Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6ea978e

Browse files
[B]LMPOP and [B]ZMPOP commands
Implement the new Redis 7.0.0 commands to pop multiple elements from one or more lists/zsets. Additionally, remove INTERNAL_FUNCTION_PARAMETERS from the redis_sock_read_multibulk_reply_zval helper function as it wasn't actually being used.
1 parent bebd398 commit 6ea978e

15 files changed

Lines changed: 481 additions & 19 deletions

cluster_library.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,6 +2362,23 @@ cluster_xinfo_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
23622362
add_next_index_zval(&c->multi_resp, &z_ret);
23632363
}
23642364

2365+
/* LMPOP, ZMPOP, BLMPOP, BZMPOP */
2366+
PHP_REDIS_API void
2367+
cluster_mpop_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
2368+
{
2369+
zval z_ret;
2370+
2371+
c->cmd_sock->null_mbulk_as_null = c->flags->null_mbulk_as_null;
2372+
if (redis_read_mpop_response(c->cmd_sock, &z_ret, c->reply_len, ctx) == FAILURE) {
2373+
CLUSTER_RETURN_FALSE(c);
2374+
}
2375+
2376+
if (CLUSTER_IS_ATOMIC(c)) {
2377+
RETURN_ZVAL(&z_ret, 0, 0);
2378+
}
2379+
add_next_index_zval(&c->multi_resp, &z_ret);
2380+
}
2381+
23652382
static void
23662383
cluster_acl_custom_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx,
23672384
int (*cb)(RedisSock*, zval*, long))

cluster_library.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,9 @@ PHP_REDIS_API void cluster_xclaim_resp(INTERNAL_FUNCTION_PARAMETERS,
496496
PHP_REDIS_API void cluster_xinfo_resp(INTERNAL_FUNCTION_PARAMETERS,
497497
redisCluster *c, void *ctx);
498498

499+
PHP_REDIS_API void cluster_mpop_resp(INTERNAL_FUNCTION_PARAMETERS,
500+
redisCluster *c, void *ctx);
501+
499502
/* Custom ACL handlers */
500503
PHP_REDIS_API void cluster_acl_getuser_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx);
501504
PHP_REDIS_API void cluster_acl_log_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx);

library.c

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,17 @@
6868
#define SCORE_DECODE_INT 1
6969
#define SCORE_DECODE_DOUBLE 2
7070

71+
/* PhpRedis often returns either FALSE or NULL depending on whether we have
72+
* an option set, so this macro just wraps that often repeated logic */
73+
#define REDIS_ZVAL_NULL(sock_, zv_) \
74+
do { \
75+
if ((sock_)->null_mbulk_as_null) { \
76+
ZVAL_NULL((zv_)); \
77+
} else { \
78+
ZVAL_FALSE((zv_)); \
79+
} \
80+
} while (0)
81+
7182
#ifndef PHP_WIN32
7283
#include <netinet/tcp.h> /* TCP_NODELAY */
7384
#include <sys/socket.h> /* SO_KEEPALIVE */
@@ -464,9 +475,7 @@ PHP_REDIS_API int redis_subscribe_response(INTERNAL_FUNCTION_PARAMETERS,
464475
// Consume response(s) from subscribe, which will vary on argc
465476
while(sctx->argc--) {
466477
ZVAL_NULL(&z_resp);
467-
if (!redis_sock_read_multibulk_reply_zval(
468-
INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, &z_resp)
469-
) {
478+
if (!redis_sock_read_multibulk_reply_zval(redis_sock, &z_resp)) {
470479
goto error;
471480
}
472481

@@ -513,9 +522,7 @@ PHP_REDIS_API int redis_subscribe_response(INTERNAL_FUNCTION_PARAMETERS,
513522
int tab_idx = 1, is_pmsg = 0;
514523

515524
ZVAL_NULL(&z_resp);
516-
if (!redis_sock_read_multibulk_reply_zval(
517-
INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, &z_resp)
518-
) {
525+
if (!redis_sock_read_multibulk_reply_zval(redis_sock, &z_resp)) {
519526
goto failure;
520527
}
521528

@@ -606,8 +613,7 @@ PHP_REDIS_API int redis_unsubscribe_response(INTERNAL_FUNCTION_PARAMETERS,
606613

607614
while (sctx->argc--) {
608615
ZVAL_NULL(&z_resp);
609-
if (!redis_sock_read_multibulk_reply_zval(
610-
INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, &z_resp) ||
616+
if (!redis_sock_read_multibulk_reply_zval(redis_sock, &z_resp) ||
611617
(z_chan = zend_hash_index_find(Z_ARRVAL(z_resp), 1)) == NULL
612618
) {
613619
efree(sctx);
@@ -642,8 +648,7 @@ PHP_REDIS_API int redis_unsubscribe_response(INTERNAL_FUNCTION_PARAMETERS,
642648
}
643649

644650
PHP_REDIS_API zval *
645-
redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAMETERS,
646-
RedisSock *redis_sock, zval *z_tab)
651+
redis_sock_read_multibulk_reply_zval(RedisSock *redis_sock, zval *z_tab)
647652
{
648653
int numElems;
649654

@@ -1617,6 +1622,87 @@ geosearch_cast(zval *zv)
16171622
return SUCCESS;
16181623
}
16191624

1625+
PHP_REDIS_API int
1626+
redis_read_mpop_response(RedisSock *redis_sock, zval *zdst, int elements,
1627+
void *ctx)
1628+
{
1629+
int subele, keylen;
1630+
zval zele = {0};
1631+
char *key;
1632+
1633+
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
1634+
1635+
if (elements < 0) {
1636+
REDIS_ZVAL_NULL(redis_sock, zdst);
1637+
return SUCCESS;
1638+
}
1639+
1640+
/* Invariant: We should have two elements */
1641+
ZEND_ASSERT(elements == 2);
1642+
1643+
array_init(zdst);
1644+
1645+
/* Key name and number of entries */
1646+
if ((key = redis_sock_read(redis_sock, &keylen)) == NULL ||
1647+
read_mbulk_header(redis_sock, &elements) < 0 || elements < 0)
1648+
{
1649+
if (key) efree(key);
1650+
goto fail;
1651+
}
1652+
1653+
add_next_index_stringl(zdst, key, keylen);
1654+
efree(key);
1655+
1656+
array_init_size(&zele, elements);
1657+
1658+
if (ctx == PHPREDIS_CTX_PTR) {
1659+
for (int i = 0; i < elements; i++) {
1660+
if (read_mbulk_header(redis_sock, &subele) < 0 || subele != 2) {
1661+
zval_dtor(&zele);
1662+
goto fail;
1663+
}
1664+
redis_mbulk_reply_loop(redis_sock, &zele, subele, UNSERIALIZE_KEYS);
1665+
}
1666+
1667+
array_zip_values_and_scores(redis_sock, &zele, SCORE_DECODE_DOUBLE);
1668+
} else {
1669+
redis_mbulk_reply_loop(redis_sock, &zele, elements, UNSERIALIZE_ALL);
1670+
}
1671+
1672+
add_next_index_zval(zdst, &zele);
1673+
1674+
return SUCCESS;
1675+
1676+
fail:
1677+
zval_dtor(zdst);
1678+
ZVAL_FALSE(zdst);
1679+
1680+
return FAILURE;
1681+
}
1682+
1683+
PHP_REDIS_API int
1684+
redis_mpop_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
1685+
zval *z_tab, void *ctx)
1686+
{
1687+
int elements, res = SUCCESS;
1688+
zval zret = {0};
1689+
1690+
if (read_mbulk_header(redis_sock, &elements) == FAILURE ||
1691+
redis_read_mpop_response(redis_sock, &zret, elements, ctx) == FAILURE)
1692+
{
1693+
res = FAILURE;
1694+
ZVAL_FALSE(&zret);
1695+
}
1696+
1697+
if (IS_ATOMIC(redis_sock)) {
1698+
RETVAL_ZVAL(&zret, 0, 0);
1699+
} else {
1700+
add_next_index_zval(z_tab, &zret);
1701+
}
1702+
1703+
return res;
1704+
}
1705+
16201706
PHP_REDIS_API int
16211707
redis_geosearch_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
16221708
zval *z_tab, void *ctx)

library.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ PHP_REDIS_API void redis_sock_set_auth(RedisSock *redis_sock, zend_string *user,
7878
PHP_REDIS_API void redis_sock_set_auth_zval(RedisSock *redis_sock, zval *zv);
7979
PHP_REDIS_API void redis_sock_free_auth(RedisSock *redis_sock);
8080
PHP_REDIS_API int redis_sock_disconnect(RedisSock *redis_sock, int force);
81-
PHP_REDIS_API zval *redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab);
81+
PHP_REDIS_API zval *redis_sock_read_multibulk_reply_zval(RedisSock *redis_sock, zval *z_tab);
8282
PHP_REDIS_API int redis_sock_read_single_line(RedisSock *redis_sock, char *buffer,
8383
size_t buflen, size_t *linelen, int set_err);
8484
PHP_REDIS_API char *redis_sock_read_bulk_reply(RedisSock *redis_sock, int bytes);
@@ -148,6 +148,13 @@ redis_read_xclaim_response(RedisSock *redis_sock, int count, zval *rv);
148148
PHP_REDIS_API int
149149
redis_read_xinfo_response(RedisSock *redis_sock, zval *z_ret, int elements);
150150

151+
PHP_REDIS_API int
152+
redis_mpop_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
153+
zval *z_tab, void *ctx);
154+
155+
PHP_REDIS_API int
156+
redis_read_mpop_response(RedisSock *redis_sock, zval *zdst, int elements, void *ctx);
157+
151158
/* Specialized ACL reply handlers */
152159
PHP_REDIS_API int redis_read_acl_getuser_reply(RedisSock *redis_sock, zval *zret, long len);
153160
PHP_REDIS_API int redis_acl_getuser_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);

redis.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,8 @@ static void add_class_constants(zend_class_entry *ce, int is_cluster) {
368368
/* Cluster doesn't support pipelining at this time */
369369
zend_declare_class_constant_long(ce, ZEND_STRL("PIPELINE"), PIPELINE);
370370

371-
zend_declare_class_constant_stringl(ce, "LEFT", 4, "left", 4);
372-
zend_declare_class_constant_stringl(ce, "RIGHT", 5, "right", 5);
371+
zend_declare_class_constant_stringl(ce, ZEND_STRL("LEFT"), ZEND_STRL("left"));
372+
zend_declare_class_constant_stringl(ce, ZEND_STRL("RIGHT"), ZEND_STRL("right"));
373373
}
374374

375375
/* retry/backoff options*/
@@ -2157,6 +2157,29 @@ PHP_METHOD(Redis, bzPopMin) {
21572157
}
21582158
/* }}} */
21592159

2160+
/* {{{ proto Redis|array|false Redis::lmpop(array $keys, string $from, int $count = 1) */
2161+
PHP_METHOD(Redis, lmpop) {
2162+
REDIS_PROCESS_KW_CMD("LMPOP", redis_mpop_cmd, redis_mpop_response);
2163+
}
2164+
/* }}} */
2165+
2166+
/* {{{ proto Redis|array|false Redis::blmpop(double $timeout, array $keys, string $from, int $count = 1) */
2167+
PHP_METHOD(Redis, blmpop) {
2168+
REDIS_PROCESS_KW_CMD("BLMPOP", redis_mpop_cmd, redis_mpop_response);
2169+
}
2170+
/* }}} */
2171+
2172+
/* {{{ proto Redis|array|false Redis::zmpop(array $keys, string $from, int $count = 1) */
2173+
PHP_METHOD(Redis, zmpop) {
2174+
REDIS_PROCESS_KW_CMD("ZMPOP", redis_mpop_cmd, redis_mpop_response);
2175+
}
2176+
2177+
/* {{{ proto Redis|array|false Redis::bzmpop(double $timeout, array $keys, string $from, int $count = 1) */
2178+
PHP_METHOD(Redis, bzmpop) {
2179+
REDIS_PROCESS_KW_CMD("BZMPOP", redis_mpop_cmd, redis_mpop_response);
2180+
}
2181+
2182+
/* }}} */
21602183
/* hashes */
21612184

21622185
/* {{{ proto long Redis::hset(string key, string mem, string val) */

redis.stub.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ public function bzPopMax(string|array $key, string|int $timeout_or_key, mixed ..
6262

6363
public function bzPopMin(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array;
6464

65+
public function bzmpop(float $timeout, array $keys, string $from, int $count = 1): Redis|array|null|false;
66+
67+
public function zmpop(array $keys, string $from, int $count = 1): Redis|array|null|false;
68+
69+
public function blmpop(float $timeout, array $keys, string $from, int $count = 1): Redis|array|null|false;
70+
71+
public function lmpop(array $keys, string $from, int $count = 1): Redis|array|null|false;
72+
6573
public function clearLastError(): bool;
6674

6775
public function client(string $opt, mixed ...$args): mixed;

redis_arginfo.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: d7e7c4d63f53a7eeeb17a5d54ce3ee1173eb18e6 */
2+
* Stub hash: f547b5f24c4d373043c89dab57d450d27f959b08 */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
55
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "null")
@@ -92,6 +92,23 @@ ZEND_END_ARG_INFO()
9292

9393
#define arginfo_class_Redis_bzPopMin arginfo_class_Redis_bzPopMax
9494

95+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_bzmpop, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE)
96+
ZEND_ARG_TYPE_INFO(0, timeout, IS_DOUBLE, 0)
97+
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
98+
ZEND_ARG_TYPE_INFO(0, from, IS_STRING, 0)
99+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "1")
100+
ZEND_END_ARG_INFO()
101+
102+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zmpop, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE)
103+
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
104+
ZEND_ARG_TYPE_INFO(0, from, IS_STRING, 0)
105+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "1")
106+
ZEND_END_ARG_INFO()
107+
108+
#define arginfo_class_Redis_blmpop arginfo_class_Redis_bzmpop
109+
110+
#define arginfo_class_Redis_lmpop arginfo_class_Redis_zmpop
111+
95112
#define arginfo_class_Redis_clearLastError arginfo_class_Redis_bgSave
96113

97114
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_client, 0, 1, IS_MIXED, 0)
@@ -1073,6 +1090,10 @@ ZEND_METHOD(Redis, brPop);
10731090
ZEND_METHOD(Redis, brpoplpush);
10741091
ZEND_METHOD(Redis, bzPopMax);
10751092
ZEND_METHOD(Redis, bzPopMin);
1093+
ZEND_METHOD(Redis, bzmpop);
1094+
ZEND_METHOD(Redis, zmpop);
1095+
ZEND_METHOD(Redis, blmpop);
1096+
ZEND_METHOD(Redis, lmpop);
10761097
ZEND_METHOD(Redis, clearLastError);
10771098
ZEND_METHOD(Redis, client);
10781099
ZEND_METHOD(Redis, close);
@@ -1309,6 +1330,10 @@ static const zend_function_entry class_Redis_methods[] = {
13091330
ZEND_ME(Redis, brpoplpush, arginfo_class_Redis_brpoplpush, ZEND_ACC_PUBLIC)
13101331
ZEND_ME(Redis, bzPopMax, arginfo_class_Redis_bzPopMax, ZEND_ACC_PUBLIC)
13111332
ZEND_ME(Redis, bzPopMin, arginfo_class_Redis_bzPopMin, ZEND_ACC_PUBLIC)
1333+
ZEND_ME(Redis, bzmpop, arginfo_class_Redis_bzmpop, ZEND_ACC_PUBLIC)
1334+
ZEND_ME(Redis, zmpop, arginfo_class_Redis_zmpop, ZEND_ACC_PUBLIC)
1335+
ZEND_ME(Redis, blmpop, arginfo_class_Redis_blmpop, ZEND_ACC_PUBLIC)
1336+
ZEND_ME(Redis, lmpop, arginfo_class_Redis_lmpop, ZEND_ACC_PUBLIC)
13121337
ZEND_ME(Redis, clearLastError, arginfo_class_Redis_clearLastError, ZEND_ACC_PUBLIC)
13131338
ZEND_ME(Redis, client, arginfo_class_Redis_client, ZEND_ACC_PUBLIC)
13141339
ZEND_ME(Redis, close, arginfo_class_Redis_close, ZEND_ACC_PUBLIC)

redis_cluster.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,7 +1336,30 @@ PHP_METHOD(RedisCluster, lcs) {
13361336
CLUSTER_PROCESS_CMD(lcs, cluster_variant_resp, 1);
13371337
}
13381338

1339+
/* {{{ proto Redis|array|false Redis::lmpop(array $keys, string $from, int $count = 1) */
1340+
PHP_METHOD(RedisCluster, lmpop) {
1341+
CLUSTER_PROCESS_KW_CMD("LMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
1342+
}
1343+
/* }}} */
1344+
1345+
/* {{{ proto Redis|array|false Redis::blmpop(double $timeout, array $keys, string $from, int $count = 1) */
1346+
PHP_METHOD(RedisCluster, blmpop) {
1347+
CLUSTER_PROCESS_KW_CMD("BLMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
1348+
}
13391349
/* }}} */
1350+
1351+
/* {{{ proto Redis|array|false Redis::zmpop(array $keys, string $from, int $count = 1) */
1352+
PHP_METHOD(RedisCluster, zmpop) {
1353+
CLUSTER_PROCESS_KW_CMD("ZMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
1354+
}
1355+
/* }}} */
1356+
1357+
/* {{{ proto Redis|array|false Redis::bzmpop(double $timeout, array $keys, sring $from, int $count = 1) */
1358+
PHP_METHOD(RedisCluster, bzmpop) {
1359+
CLUSTER_PROCESS_KW_CMD("BZMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
1360+
}
1361+
/* }}} */
1362+
13401363
/* {{{ proto string RedisCluster::ltrim(string key, long start, long end) */
13411364
PHP_METHOD(RedisCluster, ltrim) {
13421365
CLUSTER_PROCESS_KW_CMD("LTRIM", redis_key_long_long_cmd, cluster_bool_resp, 0);

redis_cluster.stub.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ public function bzpopmax(string|array $key, string|int $timeout_or_key, mixed ..
5252

5353
public function bzpopmin(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array;
5454

55+
public function bzmpop(float $timeout, array $keys, string $from, int $count = 1): Redis|array|null|false;
56+
57+
public function zmpop(array $keys, string $from, int $count = 1): Redis|array|null|false;
58+
59+
public function blmpop(float $timeout, array $keys, string $from, int $count = 1): Redis|array|null|false;
60+
61+
public function lmpop(array $keys, string $from, int $count = 1): Redis|array|null|false;
62+
5563
public function clearlasterror(): bool;
5664

5765
public function client(string|array $node, string $subcommand, string|null $arg): array|string|bool;

0 commit comments

Comments
 (0)