Skip to content

Commit e6c8e31

Browse files
committed
Redis fixes
1 parent 784ffb5 commit e6c8e31

9 files changed

Lines changed: 183 additions & 193 deletions

File tree

src/Admin.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use RobiNN\Pca\Dashboards\DashboardInterface;
1212

1313
class Admin {
14-
public const VERSION = '2.4.0';
14+
public const VERSION = '2.4.1';
1515

1616
private readonly Template $template;
1717

src/Dashboards/Redis/Compatibility/Cluster/PredisCluster.php

Lines changed: 22 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,13 @@
1414
use Predis\Collection\Iterator\Keyspace;
1515
use RobiNN\Pca\Dashboards\DashboardException;
1616
use RobiNN\Pca\Dashboards\Redis\Compatibility\RedisCompatibilityInterface;
17-
use RobiNN\Pca\Dashboards\Redis\Compatibility\RedisJson;
18-
use RobiNN\Pca\Dashboards\Redis\Compatibility\RedisModules;
17+
use RobiNN\Pca\Dashboards\Redis\Compatibility\RedisExtra;
1918

2019
/**
2120
* @method bool restore(string $key, int $ttl, string $value)
2221
*/
2322
class PredisCluster extends PredisClient implements RedisCompatibilityInterface {
24-
use RedisJson;
25-
use RedisModules;
23+
use RedisExtra;
2624

2725
/**
2826
* @var array<int, PredisClient>
@@ -96,22 +94,29 @@ public function getInfo(?string $option = null, ?array $combine = null): array {
9694
$aggregated = [];
9795

9896
foreach ($this->nodes as $node) {
99-
try {
100-
$node_section_info = $node->info();
101-
} catch (Exception) {
102-
continue;
103-
}
97+
foreach ($this->getInfoSections() as $section_name) {
98+
try {
99+
$response = $node->info($section_name);
100+
101+
$node_section_info = (is_array($response) && !empty($response)) ? reset($response) : null;
102+
103+
if (!$node_section_info || !is_array($node_section_info)) {
104+
continue;
105+
}
106+
107+
$section_name_lower = strtolower($section_name);
104108

105-
foreach ($node_section_info as $section_name => $section_data) {
106-
$section_name_lower = strtolower((string) $section_name);
107-
foreach ($section_data as $key => $value) {
108-
if (is_array($value)) {
109-
foreach ($value as $sub_key => $sub_val) {
110-
$aggregated[$section_name_lower][$key][$sub_key][] = $sub_val;
109+
foreach ($node_section_info as $key => $value) {
110+
if (is_array($value)) {
111+
foreach ($value as $sub_key => $sub_val) {
112+
$aggregated[$section_name_lower][$key][$sub_key][] = $sub_val;
113+
}
114+
} else {
115+
$aggregated[$section_name_lower][$key][] = $value;
111116
}
112-
} else {
113-
$aggregated[$section_name_lower][$key][] = $value;
114117
}
118+
} catch (Exception) {
119+
continue;
115120
}
116121
}
117122
}
@@ -135,34 +140,6 @@ public function getInfo(?string $option = null, ?array $combine = null): array {
135140
return $option !== null ? ($info[strtolower($option)] ?? []) : $info;
136141
}
137142

138-
/**
139-
* @param list<mixed> $values
140-
* @param list<string>|null $combine
141-
*/
142-
private function combineValues(string $key, array $values, ?array $combine): mixed {
143-
$unique = array_unique($values);
144-
145-
if (count($unique) === 1) {
146-
return $unique[0];
147-
}
148-
149-
$numeric = array_filter($values, is_numeric(...));
150-
151-
if ($combine && in_array($key, $combine, true) && count($numeric) === count($values)) {
152-
return array_sum($values);
153-
}
154-
155-
if ($key === 'mem_fragmentation_ratio' && count($numeric) === count($values)) {
156-
return round(array_sum($values) / count($values), 2);
157-
}
158-
159-
if ($key === 'used_memory_peak' && count($numeric) === count($values)) {
160-
return max($values);
161-
}
162-
163-
return $values;
164-
}
165-
166143
/**
167144
* @return array<int, string>
168145
*/

src/Dashboards/Redis/Compatibility/Cluster/RedisCluster.php

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,10 @@
1313
use RedisClusterException;
1414
use RobiNN\Pca\Dashboards\DashboardException;
1515
use RobiNN\Pca\Dashboards\Redis\Compatibility\RedisCompatibilityInterface;
16-
use RobiNN\Pca\Dashboards\Redis\Compatibility\RedisJson;
17-
use RobiNN\Pca\Dashboards\Redis\Compatibility\RedisModules;
16+
use RobiNN\Pca\Dashboards\Redis\Compatibility\RedisExtra;
1817

1918
class RedisCluster extends \RedisCluster implements RedisCompatibilityInterface {
20-
use RedisJson;
21-
use RedisModules;
19+
use RedisExtra;
2220

2321
/**
2422
* @var array<int, mixed>
@@ -90,11 +88,10 @@ public function getInfo(?string $option = null, ?array $combine = null): array {
9088
return $option !== null ? ($info[strtolower($option)] ?? []) : $info;
9189
}
9290

93-
$sections = ['SERVER', 'CLIENTS', 'MEMORY', 'PERSISTENCE', 'STATS', 'REPLICATION', 'CPU', 'CLUSTER', 'KEYSPACE'];
9491
$aggregated_data = [];
9592

9693
foreach ($this->nodes as $node) {
97-
foreach ($sections as $section_name) {
94+
foreach ($this->getInfoSections() as $section_name) {
9895
try {
9996
$node_section_info = $this->info($node, $section_name);
10097

@@ -140,34 +137,6 @@ public function getInfo(?string $option = null, ?array $combine = null): array {
140137
return $option !== null ? ($info[strtolower($option)] ?? []) : $info;
141138
}
142139

143-
/**
144-
* @param list<mixed> $values
145-
* @param list<string>|null $combine
146-
*/
147-
private function combineValues(string $key, array $values, ?array $combine): mixed {
148-
$unique = array_unique($values);
149-
150-
if (count($unique) === 1) {
151-
return $unique[0];
152-
}
153-
154-
$numeric = array_filter($values, is_numeric(...));
155-
156-
if ($combine && in_array($key, $combine, true) && count($numeric) === count($values)) {
157-
return array_sum($values);
158-
}
159-
160-
if ($key === 'mem_fragmentation_ratio' && count($numeric) === count($values)) {
161-
return round(array_sum($values) / count($values), 2);
162-
}
163-
164-
if ($key === 'used_memory_peak' && count($numeric) === count($values)) {
165-
return max($values);
166-
}
167-
168-
return $values;
169-
}
170-
171140
/**
172141
* @return array<int, string>
173142
*

src/Dashboards/Redis/Compatibility/Predis.php

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
* @method bool restore(string $key, int $ttl, string $value)
1616
*/
1717
class Predis extends Client implements RedisCompatibilityInterface {
18-
use RedisJson;
19-
use RedisModules;
18+
use RedisExtra;
2019

2120
/**
2221
* @var array<string, string>
@@ -74,42 +73,44 @@ public function getKeyType(string $key): string {
7473
public function getInfo(?string $option = null): array {
7574
static $info = null;
7675

77-
if ($info !== null) {
78-
return $option !== null ? ($info[strtolower($option)] ?? []) : $info;
79-
}
76+
if ($info === null) {
77+
$section_info = [];
8078

81-
$all_sections = $this->info();
82-
$section_info = [];
79+
foreach ($this->getInfoSections() as $section) {
80+
$response = $this->info($section);
8381

84-
foreach ($all_sections as $section_name => $section_data) {
85-
$section_name_lower = strtolower((string) $section_name);
82+
$section_data = (is_array($response) && !empty($response)) ? reset($response) : null;
8683

87-
if ($section_name_lower === 'keyspace') {
88-
$reformatted_keyspace = [];
84+
if ($section_data && is_array($section_data)) {
85+
if ($section === 'keyspace') {
86+
$reformatted_keyspace = [];
8987

90-
if (is_array($section_data)) {
91-
foreach ($section_data as $db => $keys_data_array) {
92-
$key_value_pairs = [];
88+
foreach ($section_data as $db => $keys_data_array) {
89+
$key_value_pairs = [];
9390

94-
if (is_array($keys_data_array)) {
95-
foreach ($keys_data_array as $key => $value) {
96-
$key_value_pairs[] = $key.'='.$value;
91+
if (is_array($keys_data_array)) {
92+
foreach ($keys_data_array as $key => $value) {
93+
$key_value_pairs[] = $key.'='.$value;
94+
}
9795
}
98-
}
9996

100-
$reformatted_keyspace[$db] = implode(',', $key_value_pairs);
97+
$reformatted_keyspace[$db] = implode(',', $key_value_pairs);
98+
}
99+
$section_data = $reformatted_keyspace;
101100
}
102-
}
103101

104-
$section_data = $reformatted_keyspace;
102+
$section_info[strtolower($section)] = $section_data;
103+
}
105104
}
106105

107-
$section_info[$section_name_lower] = $section_data;
106+
$info = $section_info;
108107
}
109108

110-
$info = $section_info;
109+
if ($option !== null) {
110+
return $info[strtolower($option)] ?? [];
111+
}
111112

112-
return $option !== null ? ($info[strtolower($option)] ?? []) : $info;
113+
return $info;
113114
}
114115

115116
/**

src/Dashboards/Redis/Compatibility/Redis.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
use RobiNN\Pca\Dashboards\DashboardException;
1313

1414
class Redis extends \Redis implements RedisCompatibilityInterface {
15-
use RedisJson;
16-
use RedisModules;
15+
use RedisExtra;
1716

1817
/**
1918
* @var array<int|string, string>
@@ -91,9 +90,8 @@ public function getInfo(?string $option = null): array {
9190

9291
if ($info === null) {
9392
$section_info = [];
94-
$sections = ['SERVER', 'CLIENTS', 'MEMORY', 'PERSISTENCE', 'STATS', 'REPLICATION', 'CPU', 'CLUSTER', 'KEYSPACE'];
9593

96-
foreach ($sections as $section) {
94+
foreach ($this->getInfoSections() as $section) {
9795
try {
9896
$section_data = $this->info($section);
9997

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
/**
3+
* This file is part of the phpCacheAdmin.
4+
* Copyright (c) Róbert Kelčák (https://kelcak.com/)
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace RobiNN\Pca\Dashboards\Redis\Compatibility;
10+
11+
use Exception;
12+
13+
trait RedisExtra {
14+
/**
15+
* @return array<int, string>
16+
*/
17+
public function getInfoSections(): array {
18+
return [
19+
'server', 'clients', 'memory', 'persistence', 'threads', 'stats', 'replication', 'cpu',
20+
'commandstats', 'latencystats', 'cluster', 'keyspace', 'errorstats',
21+
];
22+
}
23+
24+
/**
25+
* @return array<int, array<string, mixed>>
26+
*/
27+
public function parseSectionData(string $section): array {
28+
$data = $this->getInfo($section);
29+
30+
return array_map(static function ($value) {
31+
if (is_array($value)) {
32+
return $value;
33+
}
34+
35+
parse_str(str_replace(',', '&', $value), $parsed);
36+
37+
return $parsed;
38+
}, $data);
39+
}
40+
41+
/**
42+
* @throws Exception
43+
*/
44+
public function jsonGet(string $key): string {
45+
return $this->rawCommand('JSON.GET', $key);
46+
}
47+
48+
/**
49+
* @throws Exception
50+
*/
51+
public function jsonSet(string $key, mixed $value): bool {
52+
$raw = $this->rawCommand('JSON.SET', $key, '$', $value);
53+
54+
return $raw === true || $raw === 'OK';
55+
}
56+
57+
/**
58+
* @return array<int, array<string, int|string>>
59+
*
60+
* @throws Exception
61+
*/
62+
public function getModules(): array {
63+
static $modules = [];
64+
65+
try {
66+
$list = $this->rawCommand('MODULE', 'LIST'); // require Redis >= 4.0
67+
} catch (Exception) {
68+
return [];
69+
}
70+
71+
if (!is_array($list) || $list === []) {
72+
return [];
73+
}
74+
75+
foreach ($list as $module) {
76+
$modules[] = [
77+
$module[0] => $module[1], // name
78+
$module[2] => $module[3], // version
79+
];
80+
}
81+
82+
return $modules;
83+
}
84+
85+
/**
86+
* @throws Exception
87+
*/
88+
public function checkModule(string $module): bool {
89+
return in_array($module, array_column($this->getModules(), 'name'), true);
90+
}
91+
92+
/**
93+
* Combine info values into a single value in a cluster.
94+
*
95+
* @param list<mixed> $values
96+
* @param list<string>|null $combine
97+
*/
98+
private function combineValues(string $key, array $values, ?array $combine): mixed {
99+
$unique = array_unique($values);
100+
101+
if (count($unique) === 1) {
102+
return $unique[0];
103+
}
104+
105+
$numeric = array_filter($values, is_numeric(...));
106+
107+
if ($combine && in_array($key, $combine, true) && count($numeric) === count($values)) {
108+
return array_sum($values);
109+
}
110+
111+
if ($key === 'mem_fragmentation_ratio' && count($numeric) === count($values)) {
112+
return round(array_sum($values) / count($values), 2);
113+
}
114+
115+
if ($key === 'used_memory_peak' && count($numeric) === count($values)) {
116+
return max($values);
117+
}
118+
119+
return $values;
120+
}
121+
}

0 commit comments

Comments
 (0)