88
99namespace RobiNN \Pca \Dashboards \Redis \Compatibility \Cluster ;
1010
11+ use InvalidArgumentException ;
1112use Redis ;
1213use RedisClusterException ;
1314use RobiNN \Pca \Dashboards \DashboardException ;
@@ -19,6 +20,11 @@ class RedisCluster extends \RedisCluster implements RedisCompatibilityInterface
1920 use RedisJson;
2021 use RedisModules;
2122
23+ /**
24+ * @var array<int, mixed>
25+ */
26+ private array $ nodes ;
27+
2228 /**
2329 * @var array<int|string, string>
2430 */
@@ -50,6 +56,8 @@ public function __construct(array $server) {
5056 } catch (RedisClusterException $ e ) {
5157 throw new DashboardException ($ e ->getMessage ().' [ ' .implode (', ' , $ server ['nodes ' ]).'] ' );
5258 }
59+
60+ $ this ->nodes = $ this ->_masters ();
5361 }
5462
5563 public function getType (string |int $ type ): string {
@@ -71,30 +79,44 @@ public function getKeyType(string $key): string {
7179 }
7280
7381 /**
74- * @return array<int|string, mixed>
82+ * @param list<string>|null $combine
83+ *
84+ * @return array<string, array<string, mixed>>
7585 *
7686 * @throws RedisClusterException
7787 */
78- public function getInfo (?string $ option = null ): array {
88+ public function getInfo (?string $ option = null , ? array $ combine = null ): array {
7989 static $ info = [];
8090
8191 $ options = ['SERVER ' , 'CLIENTS ' , 'MEMORY ' , 'PERSISTENCE ' , 'STATS ' , 'REPLICATION ' , 'CPU ' , 'CLUSTER ' , 'KEYSPACE ' ];
82- $ nodes = $ this ->_masters ();
8392
8493 foreach ($ options as $ option_name ) {
94+ /** @var array<string, array<int, mixed>|array<string, array<int, mixed>>> $combined */
8595 $ combined = [];
8696
87- foreach ($ nodes as $ node ) {
97+ foreach ($ this ->nodes as $ node ) {
98+ /** @var array<string, mixed> $node_info */
8899 $ node_info = $ this ->info ($ node , $ option_name );
89100
90101 foreach ($ node_info as $ key => $ value ) {
91- $ combined [$ key ][] = $ value ;
102+ if (is_array ($ value )) {
103+ foreach ($ value as $ sub_key => $ sub_val ) {
104+ $ combined [$ key ][$ sub_key ][] = $ sub_val ;
105+ }
106+ } else {
107+ $ combined [$ key ][] = $ value ;
108+ }
92109 }
93110 }
94111
95112 foreach ($ combined as $ key => $ values ) {
96- $ unique = array_unique ($ values );
97- $ combined [$ key ] = count ($ unique ) === 1 ? $ unique [0 ] : $ unique ;
113+ if (is_array (reset ($ values ))) {
114+ foreach ($ values as $ sub_key => $ sub_values ) {
115+ $ combined [$ key ][$ sub_key ] = $ this ->combineValues ($ sub_key , $ sub_values , $ combine );
116+ }
117+ } else {
118+ $ combined [$ key ] = $ this ->combineValues ($ key , $ values , $ combine );
119+ }
98120 }
99121
100122 $ info [strtolower ($ option_name )] = $ combined ;
@@ -103,15 +125,42 @@ public function getInfo(?string $option = null): array {
103125 return $ option !== null ? ($ info [$ option ] ?? []) : $ info ;
104126 }
105127
128+ /**
129+ * @param list<mixed> $values
130+ * @param list<string>|null $combine
131+ */
132+ private function combineValues (string $ key , array $ values , ?array $ combine ): mixed {
133+ $ unique = array_unique ($ values );
134+
135+ if (count ($ unique ) === 1 ) {
136+ return $ unique [0 ];
137+ }
138+
139+ $ numeric = array_filter ($ values , 'is_numeric ' );
140+
141+ if ($ combine && in_array ($ key , $ combine , true ) && count ($ numeric ) === count ($ values )) {
142+ return array_sum ($ values );
143+ }
144+
145+ if ($ key === 'mem_fragmentation_ratio ' && count ($ numeric ) === count ($ values )) {
146+ return round (array_sum ($ values ) / count ($ values ), 2 );
147+ }
148+
149+ if ($ key === 'used_memory_peak ' && count ($ numeric ) === count ($ values )) {
150+ return max ($ values );
151+ }
152+
153+ return $ values ;
154+ }
155+
106156 /**
107157 * @return array<int, string>
108158 * @throws RedisClusterException
109159 */
110160 public function scanKeys (string $ pattern , int $ count ): array {
111161 $ keys = [];
112- $ nodes = $ this ->_masters ();
113162
114- foreach ($ nodes as $ node ) {
163+ foreach ($ this -> nodes as $ node ) {
115164 $ iterator = null ;
116165
117166 while (false !== ($ scan = $ this ->scan ($ iterator , $ node , $ pattern , $ count ))) {
@@ -196,9 +245,7 @@ public function size(string $key): int {
196245 * @throws RedisClusterException
197246 */
198247 public function flushDatabase (): bool {
199- $ nodes = $ this ->_masters ();
200-
201- foreach ($ nodes as $ node ) {
248+ foreach ($ this ->nodes as $ node ) {
202249 $ this ->flushDB ($ node );
203250 }
204251
@@ -218,4 +265,70 @@ public function databaseSize(): int {
218265
219266 return $ total ;
220267 }
268+
269+ /**
270+ * @throws RedisClusterException|InvalidArgumentException
271+ */
272+ public function execConfig (string $ operation , mixed ...$ args ): mixed {
273+ switch (strtoupper ($ operation )) {
274+ case 'GET ' :
275+ if (empty ($ args )) {
276+ throw new InvalidArgumentException ('CONFIG GET requires a parameter name. ' );
277+ }
278+
279+ $ result = $ this ->rawcommand ($ this ->nodes [0 ], 'CONFIG ' , 'GET ' , $ args [0 ]);
280+
281+ return isset ($ result [0 ], $ result [1 ]) ? [$ result [0 ] => $ result [1 ]] : [];
282+ case 'SET ' :
283+ if (count ($ args ) < 2 ) {
284+ throw new InvalidArgumentException ('CONFIG SET requires a parameter name and a value. ' );
285+ }
286+
287+ foreach ($ this ->nodes as $ node ) {
288+ $ this ->rawcommand ($ node , 'CONFIG ' , 'SET ' , $ args [0 ], $ args [1 ]);
289+ }
290+
291+ return true ;
292+ case 'REWRITE ' :
293+ case 'RESETSTAT ' :
294+ foreach ($ this ->nodes as $ node ) {
295+ $ this ->rawcommand ($ node , 'CONFIG ' , strtoupper ($ operation ));
296+ }
297+
298+ return true ;
299+ default :
300+ throw new InvalidArgumentException ('Unsupported CONFIG operation: ' .$ operation );
301+ }
302+ }
303+
304+ /**
305+ * @return null|array<int, mixed>
306+ *
307+ * @throws RedisClusterException
308+ */
309+ public function getSlowlog (int $ count ): ?array {
310+ $ all_logs = [];
311+
312+ foreach ($ this ->nodes as $ node ) {
313+ $ logs = $ this ->rawcommand ($ node , 'SLOWLOG ' , 'GET ' , $ count );
314+
315+ if (is_array ($ logs ) && !empty ($ logs )) {
316+ array_push ($ all_logs , ...$ logs );
317+ }
318+ }
319+
320+ usort ($ all_logs , static function ($ a , $ b ) {
321+ return $ b [1 ] <=> $ a [1 ];
322+ });
323+
324+ return $ all_logs ;
325+ }
326+
327+ public function resetSlowlog (): bool {
328+ foreach ($ this ->nodes as $ node ) {
329+ $ this ->rawcommand ($ node , 'SLOWLOG ' , 'RESET ' );
330+ }
331+
332+ return true ;
333+ }
221334}
0 commit comments