From bfc6e9f72cde6c592a0044123546642a8d261485 Mon Sep 17 00:00:00 2001 From: michael-grunder Date: Fri, 14 Oct 2022 09:14:17 -0700 Subject: [PATCH] INFO with multiple sections See #2068 --- library.c | 1 + redis.c | 34 +++++++++++---------------- redis.stub.php | 16 ++++++++++++- redis_arginfo.h | 4 ++-- redis_cluster.c | 43 +++++++++++++++++----------------- redis_cluster.stub.php | 18 +++++++++++++- redis_cluster_arginfo.h | 4 ++-- redis_cluster_legacy_arginfo.h | 4 ++-- redis_legacy_arginfo.h | 4 ++-- tests/RedisTest.php | 6 +++++ 10 files changed, 82 insertions(+), 52 deletions(-) diff --git a/library.c b/library.c index 91f8fca9cb..bbdca77d25 100644 --- a/library.c +++ b/library.c @@ -3414,6 +3414,7 @@ redis_unpack(RedisSock *redis_sock, const char *src, int srclen, zval *zdst) { } PHP_REDIS_API int + redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len) { php_serialize_data_t ht; diff --git a/redis.c b/redis.c index 36b0cf186e..9ce8018b21 100644 --- a/redis.c +++ b/redis.c @@ -1752,38 +1752,32 @@ PHP_METHOD(Redis, pttl) { /* {{{ proto array Redis::info() */ PHP_METHOD(Redis, info) { - - zval *object; + smart_string cmdstr = {0}; RedisSock *redis_sock; - char *cmd, *opt = NULL; - size_t opt_len; - int cmd_len; + zend_string *section; + zval *args = NULL; + int i, argc = 0; - if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), - "O|s", &object, redis_ce, &opt, &opt_len) - == FAILURE) - { - RETURN_FALSE; - } + ZEND_PARSE_PARAMETERS_START(0, -1) + Z_PARAM_VARIADIC('+', args, argc) + ZEND_PARSE_PARAMETERS_END(); - if ((redis_sock = redis_sock_get(object, 0)) == NULL) { + if ((redis_sock = redis_sock_get(getThis(), 0)) == NULL) RETURN_FALSE; - } - /* Build a standalone INFO command or one with an option */ - if (opt != NULL) { - cmd_len = REDIS_SPPRINTF(&cmd, "INFO", "s", opt, opt_len); - } else { - cmd_len = REDIS_SPPRINTF(&cmd, "INFO", ""); + REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "INFO"); + for (i = 0; i < argc; i++) { + section = zval_get_string(&args[i]); + redis_cmd_append_sstr_zstr(&cmdstr, section); + zend_string_release(section); } - REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); + REDIS_PROCESS_REQUEST(redis_sock, cmdstr.c, cmdstr.len); if (IS_ATOMIC(redis_sock)) { redis_info_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL); } REDIS_PROCESS_RESPONSE(redis_info_response); - } /* }}} */ diff --git a/redis.stub.php b/redis.stub.php index eb3f53132a..b41ff83101 100644 --- a/redis.stub.php +++ b/redis.stub.php @@ -269,7 +269,21 @@ public function incrBy(string $key, int $value); /** @return Redis|int|false */ public function incrByFloat(string $key, float $value); - public function info(string $opt = null): Redis|array|false; + /** + Retreive information about the connected redis-server. If no arguments are passed to + this function, redis will return every info field. Alternatively you may pass a specific + section you want returned (e.g. 'server', or 'memory') to receive only information pertaining + to that section. + + If connected to Redis server >= 7.0.0 you may pass multiple optional sections. + + @see https://redis.io/commands/info/ + + @param string ...$sections Optional section(s) you wish Redis server to return. + + @return Redis|array|false + */ + public function info(string ...$sections): Redis|array|false; public function isConnected(): bool; diff --git a/redis_arginfo.h b/redis_arginfo.h index ea38af2eed..41eb4738ae 100644 --- a/redis_arginfo.h +++ b/redis_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a8ddcde8e8af5201d72bfe8b463afc0c9dafb73d */ + * Stub hash: bd81918bd558ec53399e7f64647c39f288f3413e */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "null") @@ -444,7 +444,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_incrByFloat, 0, 0, 2) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_info, 0, 0, Redis, MAY_BE_ARRAY|MAY_BE_FALSE) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, opt, IS_STRING, 0, "null") + ZEND_ARG_VARIADIC_TYPE_INFO(0, sections, IS_STRING, 0) ZEND_END_ARG_INFO() #define arginfo_class_Redis_isConnected arginfo_class_Redis_close diff --git a/redis_cluster.c b/redis_cluster.c index 0a701ed8bb..5a3cb4db30 100644 --- a/redis_cluster.c +++ b/redis_cluster.c @@ -2578,39 +2578,38 @@ PHP_METHOD(RedisCluster, lastsave) { * proto array RedisCluster::info(array host_port, [string $arg]) */ PHP_METHOD(RedisCluster, info) { redisCluster *c = GET_CONTEXT(); + zval *node = NULL, *args = NULL; + smart_string cmdstr = {0}; REDIS_REPLY_TYPE rtype; - char *cmd, *opt = NULL; - int cmd_len; - size_t opt_len = 0; + zend_string *section; void *ctx = NULL; - - zval *z_arg; + int i, argc; short slot; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s", &z_arg, &opt, - &opt_len) == FAILURE) - { + ZEND_PARSE_PARAMETERS_START(1, -1) + Z_PARAM_ZVAL(node) + Z_PARAM_OPTIONAL + Z_PARAM_VARIADIC('*', args, argc) + ZEND_PARSE_PARAMETERS_END(); + + if ((slot = cluster_cmd_get_slot(c, node)) < 0) RETURN_FALSE; - } - /* Treat INFO as non read-only, as we probably want the master */ - c->readonly = 0; + REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "INFO"); - slot = cluster_cmd_get_slot(c, z_arg); - if (slot < 0) { - RETURN_FALSE; - } + /* Direct this command at the master */ + c->readonly = 0; - if (opt != NULL) { - cmd_len = redis_spprintf(NULL, NULL, &cmd, "INFO", "s", opt, opt_len); - } else { - cmd_len = redis_spprintf(NULL, NULL, &cmd, "INFO", ""); + for (i = 0; i < argc; i++) { + section = zval_get_string(&args[i]); + redis_cmd_append_sstr_zstr(&cmdstr, section); + zend_string_release(section); } rtype = CLUSTER_IS_ATOMIC(c) ? TYPE_BULK : TYPE_LINE; - if (cluster_send_slot(c, slot, cmd, cmd_len, rtype) < 0) { + if (cluster_send_slot(c, slot, cmdstr.c, cmdstr.len, rtype) < 0) { CLUSTER_THROW_EXCEPTION("Unable to send INFO command to specific node", 0); - efree(cmd); + efree(cmdstr.c); RETURN_FALSE; } @@ -2620,7 +2619,7 @@ PHP_METHOD(RedisCluster, info) { CLUSTER_ENQUEUE_RESPONSE(c, slot, cluster_info_resp, ctx); } - efree(cmd); + efree(cmdstr.c); } /* }}} */ diff --git a/redis_cluster.stub.php b/redis_cluster.stub.php index 05a44ccdee..713f1c468b 100644 --- a/redis_cluster.stub.php +++ b/redis_cluster.stub.php @@ -187,7 +187,23 @@ public function incrby(string $key, int $value): RedisCluster|int|false; public function incrbyfloat(string $key, float $value): RedisCluster|float|false; - public function info(string|array $key_or_address, ?string $section = null): RedisCluster|array|false; + /** + Retreive information about the connected redis-server. If no arguments are passed to + this function, redis will return every info field. Alternatively you may pass a specific + section you want returned (e.g. 'server', or 'memory') to receive only information pertaining + to that section. + + If connected to Redis server >= 7.0.0 you may pass multiple optional sections. + + @see https://redis.io/commands/info/ + + @param string|array $key_or_address Either a key name or array with host and port indicating + which cluster node we want to send the command to. + @param string ...$sections Optional section(s) you wish Redis server to return. + + @return Redis|array|false + */ + public function info(string|array $key_or_address, string ...$sections): RedisCluster|array|false; public function keys(string $pattern): RedisCluster|array|false; diff --git a/redis_cluster_arginfo.h b/redis_cluster_arginfo.h index 7578b03206..3dd1f55d46 100644 --- a/redis_cluster_arginfo.h +++ b/redis_cluster_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: ccb418a312ff22f03e2354de508ff8bd9e4d266e */ + * Stub hash: d3d58cb90bf0884a4153cd01f3d0850b42fcd910 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 1) @@ -385,7 +385,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_info, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE) ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, section, IS_STRING, 1, "null") + ZEND_ARG_VARIADIC_TYPE_INFO(0, sections, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_keys, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE) diff --git a/redis_cluster_legacy_arginfo.h b/redis_cluster_legacy_arginfo.h index 6e392c7243..6dbd023107 100644 --- a/redis_cluster_legacy_arginfo.h +++ b/redis_cluster_legacy_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: ccb418a312ff22f03e2354de508ff8bd9e4d266e */ + * Stub hash: d3d58cb90bf0884a4153cd01f3d0850b42fcd910 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1) ZEND_ARG_INFO(0, name) @@ -327,7 +327,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_info, 0, 0, 1) ZEND_ARG_INFO(0, key_or_address) - ZEND_ARG_INFO(0, section) + ZEND_ARG_VARIADIC_INFO(0, sections) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_keys, 0, 0, 1) diff --git a/redis_legacy_arginfo.h b/redis_legacy_arginfo.h index 5c8642d9cc..18db4f2584 100644 --- a/redis_legacy_arginfo.h +++ b/redis_legacy_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a8ddcde8e8af5201d72bfe8b463afc0c9dafb73d */ + * Stub hash: bd81918bd558ec53399e7f64647c39f288f3413e */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_INFO(0, options) @@ -375,7 +375,7 @@ ZEND_END_ARG_INFO() #define arginfo_class_Redis_incrByFloat arginfo_class_Redis_append ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_info, 0, 0, 0) - ZEND_ARG_INFO(0, opt) + ZEND_ARG_VARIADIC_INFO(0, sections) ZEND_END_ARG_INFO() #define arginfo_class_Redis_isConnected arginfo_class_Redis___destruct diff --git a/tests/RedisTest.php b/tests/RedisTest.php index bcef3e6277..c240bc9f72 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -2363,6 +2363,12 @@ public function testInfo() { $this->assertTrue(in_array($k, array_keys($info))); } } + + if (!$this->minVersionCheck("7.0.0")) + return; + + $res = $this->redis->info('server', 'memory'); + $this->assertTrue(is_array($res) && isset($res['redis_version']) && isset($res['used_memory'])); } public function testInfoCommandStats() {