diff options
author | michael-grunder <michael.grunder@gmail.com> | 2022-10-08 21:06:23 +0300 |
---|---|---|
committer | Michael Grunder <michael.grunder@gmail.com> | 2022-10-08 21:35:10 +0300 |
commit | 6b34d17fc480c99f7c7c9c8fae1a55c13b7e94f3 (patch) | |
tree | 1798f19b9b3eec99fa59330bda00d8896603dacb | |
parent | d2044c9fa49eefecebad48aa169ab7bead1af121 (diff) |
Add new Redis 6.2.0 XTRIM options
Fixes #1961
-rw-r--r-- | library.c | 4 | ||||
-rw-r--r-- | library.h | 1 | ||||
-rw-r--r-- | redis.stub.php | 2 | ||||
-rw-r--r-- | redis_arginfo.h | 6 | ||||
-rw-r--r-- | redis_cluster.stub.php | 2 | ||||
-rw-r--r-- | redis_cluster_arginfo.h | 6 | ||||
-rw-r--r-- | redis_cluster_legacy_arginfo.h | 4 | ||||
-rw-r--r-- | redis_commands.c | 52 | ||||
-rw-r--r-- | redis_legacy_arginfo.h | 4 | ||||
-rw-r--r-- | tests/RedisTest.php | 21 |
10 files changed, 81 insertions, 21 deletions
@@ -1062,6 +1062,10 @@ int redis_cmd_append_sstr_key(smart_string *str, char *key, size_t len, RedisSoc return retval; } +int redis_cmd_append_sstr_key_zstr(smart_string *dst, zend_string *key, RedisSock *redis_sock, short *slot) { + return redis_cmd_append_sstr_key(dst, ZSTR_VAL(key), ZSTR_LEN(key), redis_sock, slot); +} + /* Append an array key to a redis smart string command. This function * handles the boilerplate conditionals around string or integer keys */ int redis_cmd_append_sstr_arrkey(smart_string *cmd, zend_string *kstr, zend_ulong idx) @@ -50,6 +50,7 @@ int redis_cmd_append_sstr_dbl(smart_string *str, double value); int redis_cmd_append_sstr_zstr(smart_string *str, zend_string *zstr); int redis_cmd_append_sstr_zval(smart_string *str, zval *z, RedisSock *redis_sock); int redis_cmd_append_sstr_key(smart_string *str, char *key, size_t len, RedisSock *redis_sock, short *slot); +int redis_cmd_append_sstr_key_zstr(smart_string *str, zend_string *key, RedisSock *redis_sock, short *slot); int redis_cmd_append_sstr_arrkey(smart_string *cmd, zend_string *kstr, zend_ulong idx); PHP_REDIS_API int redis_spprintf(RedisSock *redis_sock, short *slot, char **ret, char *kw, char *fmt, ...); diff --git a/redis.stub.php b/redis.stub.php index e415a5b8..89e6f0c9 100644 --- a/redis.stub.php +++ b/redis.stub.php @@ -515,7 +515,7 @@ public function persist(string $key): bool; public function xrevrange(string $key, string $start, string $end, int $count = -1): bool|array; - public function xtrim(string $key, int $maxlen, bool $approx = false): int; + public function xtrim(string $key, int $maxlen, bool $approx = false, bool $minid = false, int $limit = -1): Redis|int|false; public function zAdd(string $key, array|float $score_or_options, mixed ...$more_scores_and_mems): Redis|int|false; diff --git a/redis_arginfo.h b/redis_arginfo.h index 8b54c21b..acd15086 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: 2c4ee6dc4a5aa66b1700df8859233c349aa00519 */ + * Stub hash: 0ace014dc4f3f94eedd835f1d6895703aea3e607 */ 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") @@ -920,10 +920,12 @@ ZEND_END_ARG_INFO() #define arginfo_class_Redis_xrevrange arginfo_class_Redis_xrange -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_xtrim, 0, 2, IS_LONG, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xtrim, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, maxlen, IS_LONG, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, approx, _IS_BOOL, 0, "false") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, minid, _IS_BOOL, 0, "false") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, limit, IS_LONG, 0, "-1") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zAdd, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE) diff --git a/redis_cluster.stub.php b/redis_cluster.stub.php index f3475f01..d4d9518a 100644 --- a/redis_cluster.stub.php +++ b/redis_cluster.stub.php @@ -358,7 +358,7 @@ class RedisCluster { public function xrevrange(string $key, string $start, string $end, int $count = -1): bool|array; - public function xtrim(string $key, int $maxlen, bool $approx = false): int; + public function xtrim(string $key, int $maxlen, bool $approx = false, bool $minid = false, int $limit = -1): RedisCluster|int|false; public function zadd(string $key, float $score, string $member, mixed ...$extra_args): int; diff --git a/redis_cluster_arginfo.h b/redis_cluster_arginfo.h index f5f6cc86..f3357408 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: 956f295e74025def86150d0acdf7a11594c72d47 */ + * Stub hash: 39c0741e5bf358e116f5ed2caa35c1ca226fd593 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 1) @@ -780,10 +780,12 @@ ZEND_END_ARG_INFO() #define arginfo_class_RedisCluster_xrevrange arginfo_class_RedisCluster_xrange -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_xtrim, 0, 2, IS_LONG, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xtrim, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, maxlen, IS_LONG, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, approx, _IS_BOOL, 0, "false") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, minid, _IS_BOOL, 0, "false") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, limit, IS_LONG, 0, "-1") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_zadd, 0, 3, IS_LONG, 0) diff --git a/redis_cluster_legacy_arginfo.h b/redis_cluster_legacy_arginfo.h index a491d494..fb31eefe 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: 956f295e74025def86150d0acdf7a11594c72d47 */ + * Stub hash: 39c0741e5bf358e116f5ed2caa35c1ca226fd593 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1) ZEND_ARG_INFO(0, name) @@ -684,6 +684,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xtrim, 0, 0, 2) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, maxlen) ZEND_ARG_INFO(0, approx) + ZEND_ARG_INFO(0, minid) + ZEND_ARG_INFO(0, limit) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zadd, 0, 0, 3) diff --git a/redis_commands.c b/redis_commands.c index 3d1b674d..867ad15e 100644 --- a/redis_commands.c +++ b/redis_commands.c @@ -5650,29 +5650,55 @@ int redis_xinfo_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, return SUCCESS; } -/* XTRIM MAXLEN [~] count */ +// XTRIM key <MAXLEN | MINID> [= | ~] threshold [LIMIT count] int redis_xtrim_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char **cmd, int *cmd_len, short *slot, void **ctx) { - char *key; - size_t keylen; - zend_long maxlen; - zend_bool approx = 0; + zend_long threshold = 0, limit = -1; + zend_bool approx = 0, minid = 0; + smart_string cmdstr = {0}; + zend_string *key = NULL; + int argc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|b", &key, &keylen, - &maxlen, &approx) == FAILURE) - { - return FAILURE; + ZEND_PARSE_PARAMETERS_START(2, 5) + Z_PARAM_STR(key) + Z_PARAM_LONG(threshold) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(approx) + Z_PARAM_BOOL(minid) + Z_PARAM_LONG(limit) + ZEND_PARSE_PARAMETERS_END_EX(return FAILURE); + + argc = 4 + (approx && limit > -1 ? 2 : 0); + REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "XTRIM"); + + redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot); + + if (minid) { + REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "MINID"); + } else { + REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "MAXLEN"); } if (approx) { - *cmd_len = REDIS_CMD_SPPRINTF(cmd, "XTRIM", "kssl", key, keylen, - "MAXLEN", 6, "~", 1, maxlen); + REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "~"); } else { - *cmd_len = REDIS_CMD_SPPRINTF(cmd, "XTRIM", "ksl", key, keylen, - "MAXLEN", 6, maxlen); + REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "="); } + redis_cmd_append_sstr_long(&cmdstr, threshold); + + if (limit > -1 && approx) { + REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "LIMIT"); + redis_cmd_append_sstr_long(&cmdstr, limit); + } else if (limit > -1) { + php_error_docref(NULL, E_WARNING, "Cannot use LIMIT without an approximate match, ignoring"); + } else if (ZEND_NUM_ARGS() == 5) { + php_error_docref(NULL, E_WARNING, "Limit must be >= 0"); + } + + *cmd = cmdstr.c; + *cmd_len = cmdstr.len; return SUCCESS; } diff --git a/redis_legacy_arginfo.h b/redis_legacy_arginfo.h index a4972491..b68b5367 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: 2c4ee6dc4a5aa66b1700df8859233c349aa00519 */ + * Stub hash: 0ace014dc4f3f94eedd835f1d6895703aea3e607 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_INFO(0, options) @@ -807,6 +807,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xtrim, 0, 0, 2) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, maxlen) ZEND_ARG_INFO(0, approx) + ZEND_ARG_INFO(0, minid) + ZEND_ARG_INFO(0, limit) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zAdd, 0, 0, 2) diff --git a/tests/RedisTest.php b/tests/RedisTest.php index 57faf1af..d44b0364 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -6625,6 +6625,27 @@ class Redis_Test extends TestSuite can call it with the flag */ $this->addStreamEntries('stream', 100); $this->assertFalse($this->redis->xTrim('stream', 1, true) === false); + + /* We need Redis >= 6.2.0 for MINID and LIMIT options */ + if (!$this->minVersionCheck("6.2.0")) + return; + + $this->assertEquals(1, $this->redis->del('stream')); + + /* Test minid by generating a stream with more than one */ + for ($i = 1; $i < 3; $i++) { + for ($j = 0; $j < 3; $j++) { + $this->redis->xadd('stream', "$i-$j", ['foo' => 'bar']); + } + } + + /* MINID of 2-0 */ + $this->assertEquals(3, $this->redis->xtrim('stream', 2, false, true)); + $this->assertEquals(['2-0', '2-1', '2-2'], array_keys($this->redis->xrange('stream', '0', '+'))); + + /* TODO: Figure oiut how to test LIMIT deterministically. For now just + send a LIMIT and verify we don't get a failure from Redis. */ + $this->assertTrue(is_int($this->redis->xtrim('stream', 2, true, false, 3))); } /* XCLAIM is one of the most complicated commands, with a great deal of different options |