diff options
author | michael-grunder <michael.grunder@gmail.com> | 2022-09-23 20:41:55 +0300 |
---|---|---|
committer | Michael Grunder <michael.grunder@gmail.com> | 2022-09-27 21:35:40 +0300 |
commit | a98605f216449479cf27599244c25cbf415ed226 (patch) | |
tree | de325fcf6bc5972c3ca4dbab2749a80999806907 | |
parent | b7bf22d4c95ebb275702b9c93ae46c45f21faae2 (diff) |
BLPOP with a float timeout
See #2157
-rw-r--r-- | redis.stub.php | 4 | ||||
-rw-r--r-- | redis_arginfo.h | 12 | ||||
-rw-r--r-- | redis_commands.c | 34 | ||||
-rw-r--r-- | redis_legacy_arginfo.h | 2 | ||||
-rw-r--r-- | tests/RedisTest.php | 22 |
5 files changed, 46 insertions, 28 deletions
diff --git a/redis.stub.php b/redis.stub.php index 57e48d01..3a754901 100644 --- a/redis.stub.php +++ b/redis.stub.php @@ -52,9 +52,9 @@ class Redis { /** @return int|Redis */ public function bitpos(string $key, int $bit, int $start = 0, int $end = -1); - public function blPop(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array; + public function blPop(string|array $key, string|double|int $timeout_or_key, mixed ...$extra_args): array; - public function brPop(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array; + public function brPop(string|array $key, string|double|int $timeout_or_key, mixed ...$extra_args): array; public function brpoplpush(string $src, string $dst, int $timeout): string; diff --git a/redis_arginfo.h b/redis_arginfo.h index ea5ee288..e05c4b9f 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: 2b1fc18e5c464c551df8572363972769b2ec1096 */ + * Stub hash: 28b297e0067c033cea6e2c42fb1f42d4585234ac */ 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") @@ -72,7 +72,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_blPop, 0, 2, IS_ARRAY, 0) ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_ARRAY, NULL) - ZEND_ARG_TYPE_MASK(0, timeout_or_key, MAY_BE_STRING|MAY_BE_LONG, NULL) + ZEND_ARG_OBJ_TYPE_MASK(0, timeout_or_key, double, MAY_BE_STRING|MAY_BE_LONG, NULL) ZEND_ARG_VARIADIC_TYPE_INFO(0, extra_args, IS_MIXED, 0) ZEND_END_ARG_INFO() @@ -84,9 +84,13 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_brpoplpush, 0, 3, IS ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0) ZEND_END_ARG_INFO() -#define arginfo_class_Redis_bzPopMax arginfo_class_Redis_blPop +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_bzPopMax, 0, 2, IS_ARRAY, 0) + ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_ARRAY, NULL) + ZEND_ARG_TYPE_MASK(0, timeout_or_key, MAY_BE_STRING|MAY_BE_LONG, NULL) + ZEND_ARG_VARIADIC_TYPE_INFO(0, extra_args, IS_MIXED, 0) +ZEND_END_ARG_INFO() -#define arginfo_class_Redis_bzPopMin arginfo_class_Redis_blPop +#define arginfo_class_Redis_bzPopMin arginfo_class_Redis_bzPopMax #define arginfo_class_Redis_clearLastError arginfo_class_Redis_bgSave diff --git a/redis_commands.c b/redis_commands.c index 39c7941d..35152b7c 100644 --- a/redis_commands.c +++ b/redis_commands.c @@ -1461,14 +1461,13 @@ static int gen_varkey_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw, int kw_len, int min_argc, int has_timeout, char **cmd, int *cmd_len, short *slot) { - zval *z_args, *z_ele; + zval *z_args, *z_ele, ztimeout = {0}; HashTable *ht_arr; char *key; int key_free, i, tail; size_t key_len; int single_array = 0, argc = ZEND_NUM_ARGS(); smart_string cmdstr = {0}; - long timeout = 0; short kslot = -1; zend_string *zstr; @@ -1489,8 +1488,9 @@ static int gen_varkey_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, single_array = argc==1 && Z_TYPE(z_args[0]) == IS_ARRAY; } else { single_array = argc==2 && Z_TYPE(z_args[0]) == IS_ARRAY && - Z_TYPE(z_args[1]) == IS_LONG; - timeout = Z_LVAL(z_args[1]); + (Z_TYPE(z_args[1]) == IS_LONG || Z_TYPE(z_args[1]) == IS_DOUBLE); + if (single_array) + ZVAL_COPY_VALUE(&ztimeout, &z_args[1]); } // If we're running a single array, rework args @@ -1533,17 +1533,22 @@ static int gen_varkey_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zend_string_release(zstr); if (key_free) efree(key); } ZEND_HASH_FOREACH_END(); - if (has_timeout) { - redis_cmd_append_sstr_long(&cmdstr, timeout); + if (Z_TYPE(ztimeout) == IS_LONG) { + redis_cmd_append_sstr_long(&cmdstr, Z_LVAL(ztimeout)); + } else if (Z_TYPE(ztimeout) == IS_DOUBLE) { + redis_cmd_append_sstr_dbl(&cmdstr, Z_DVAL(ztimeout)); } } else { - if (has_timeout && Z_TYPE(z_args[argc-1])!=IS_LONG) { - php_error_docref(NULL, E_ERROR, - "Timeout value must be a LONG"); - efree(z_args); - return FAILURE; + if (has_timeout) { + zend_uchar type = Z_TYPE(z_args[argc - 1]); + if (type == IS_LONG || type == IS_DOUBLE) { + ZVAL_COPY_VALUE(&ztimeout, &z_args[argc - 1]); + } else { + php_error_docref(NULL, E_ERROR, "Timeout value must be a long or double"); + efree(z_args); + return FAILURE; + } } - tail = has_timeout ? argc-1 : argc; for(i = 0; i < tail; i++) { zstr = zval_get_string(&z_args[i]); @@ -1571,7 +1576,10 @@ static int gen_varkey_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zend_string_release(zstr); if (key_free) efree(key); } - if (has_timeout) { + + if (Z_TYPE(ztimeout) == IS_DOUBLE) { + redis_cmd_append_sstr_dbl(&cmdstr, Z_DVAL(z_args[tail])); + } else if (Z_TYPE(ztimeout) == IS_LONG) { redis_cmd_append_sstr_long(&cmdstr, Z_LVAL(z_args[tail])); } diff --git a/redis_legacy_arginfo.h b/redis_legacy_arginfo.h index cacf75f3..b26cd9e6 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: 2b1fc18e5c464c551df8572363972769b2ec1096 */ + * Stub hash: 28b297e0067c033cea6e2c42fb1f42d4585234ac */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_INFO(0, options) diff --git a/tests/RedisTest.php b/tests/RedisTest.php index 49383d47..6ef56490 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -963,18 +963,24 @@ class Redis_Test extends TestSuite } public function testblockingPop() { + /* Test with a double timeout in Redis >= 6.0.0 */ + if (version_compare($this->version, "6.0.0") >= 0) { + $this->redis->del('list'); + $this->redis->lpush('list', 'val1', 'val2'); + $this->assertEquals(['list', 'val2'], $this->redis->blpop(['list'], .1)); + $this->assertEquals(['list', 'val1'], $this->redis->blpop(['list'], .1)); + } + // non blocking blPop, brPop $this->redis->del('list'); - $this->redis->lPush('list', 'val1'); - $this->redis->lPush('list', 'val2'); - $this->assertTrue($this->redis->blPop(['list'], 2) === ['list', 'val2']); - $this->assertTrue($this->redis->blPop(['list'], 2) === ['list', 'val1']); + $this->redis->lPush('list', 'val1', 'val2'); + $this->assertEquals(['list', 'val2'], $this->redis->blPop(['list'], 2)); + $this->assertEquals(['list', 'val1'], $this->redis->blPop(['list'], 2)); $this->redis->del('list'); - $this->redis->lPush('list', 'val1'); - $this->redis->lPush('list', 'val2'); - $this->assertTrue($this->redis->brPop(['list'], 1) === ['list', 'val1']); - $this->assertTrue($this->redis->brPop(['list'], 1) === ['list', 'val2']); + $this->redis->lPush('list', 'val1', 'val2'); + $this->assertEquals(['list', 'val1'], $this->redis->brPop(['list'], 1)); + $this->assertEquals(['list', 'val2'], $this->redis->brPop(['list'], 1)); // blocking blpop, brpop $this->redis->del('list'); |