Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions cluster_library.c
Original file line number Diff line number Diff line change
Expand Up @@ -2362,6 +2362,23 @@ cluster_xinfo_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
add_next_index_zval(&c->multi_resp, &z_ret);
}

/* LMPOP, ZMPOP, BLMPOP, BZMPOP */
PHP_REDIS_API void
cluster_mpop_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
{
zval z_ret;

c->cmd_sock->null_mbulk_as_null = c->flags->null_mbulk_as_null;
if (redis_read_mpop_response(c->cmd_sock, &z_ret, c->reply_len, ctx) == FAILURE) {
CLUSTER_RETURN_FALSE(c);
}

if (CLUSTER_IS_ATOMIC(c)) {
RETURN_ZVAL(&z_ret, 0, 0);
}
add_next_index_zval(&c->multi_resp, &z_ret);
}

static void
cluster_acl_custom_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx,
int (*cb)(RedisSock*, zval*, long))
Expand Down
3 changes: 3 additions & 0 deletions cluster_library.h
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,9 @@ PHP_REDIS_API void cluster_xclaim_resp(INTERNAL_FUNCTION_PARAMETERS,
PHP_REDIS_API void cluster_xinfo_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);

PHP_REDIS_API void cluster_mpop_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);

/* Custom ACL handlers */
PHP_REDIS_API void cluster_acl_getuser_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_acl_log_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx);
Expand Down
106 changes: 96 additions & 10 deletions library.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@
#define SCORE_DECODE_INT 1
#define SCORE_DECODE_DOUBLE 2

/* PhpRedis often returns either FALSE or NULL depending on whether we have
* an option set, so this macro just wraps that often repeated logic */
#define REDIS_ZVAL_NULL(sock_, zv_) \
do { \
if ((sock_)->null_mbulk_as_null) { \
ZVAL_NULL((zv_)); \
} else { \
ZVAL_FALSE((zv_)); \
} \
} while (0)

#ifndef PHP_WIN32
#include <netinet/tcp.h> /* TCP_NODELAY */
#include <sys/socket.h> /* SO_KEEPALIVE */
Expand Down Expand Up @@ -464,9 +475,7 @@ PHP_REDIS_API int redis_subscribe_response(INTERNAL_FUNCTION_PARAMETERS,
// Consume response(s) from subscribe, which will vary on argc
while(sctx->argc--) {
ZVAL_NULL(&z_resp);
if (!redis_sock_read_multibulk_reply_zval(
INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, &z_resp)
) {
if (!redis_sock_read_multibulk_reply_zval(redis_sock, &z_resp)) {
goto error;
}

Expand Down Expand Up @@ -513,9 +522,7 @@ PHP_REDIS_API int redis_subscribe_response(INTERNAL_FUNCTION_PARAMETERS,
int tab_idx = 1, is_pmsg = 0;

ZVAL_NULL(&z_resp);
if (!redis_sock_read_multibulk_reply_zval(
INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, &z_resp)
) {
if (!redis_sock_read_multibulk_reply_zval(redis_sock, &z_resp)) {
goto failure;
}

Expand Down Expand Up @@ -606,8 +613,7 @@ PHP_REDIS_API int redis_unsubscribe_response(INTERNAL_FUNCTION_PARAMETERS,

while (sctx->argc--) {
ZVAL_NULL(&z_resp);
if (!redis_sock_read_multibulk_reply_zval(
INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, &z_resp) ||
if (!redis_sock_read_multibulk_reply_zval(redis_sock, &z_resp) ||
(z_chan = zend_hash_index_find(Z_ARRVAL(z_resp), 1)) == NULL
) {
efree(sctx);
Expand Down Expand Up @@ -642,8 +648,7 @@ PHP_REDIS_API int redis_unsubscribe_response(INTERNAL_FUNCTION_PARAMETERS,
}

PHP_REDIS_API zval *
redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab)
redis_sock_read_multibulk_reply_zval(RedisSock *redis_sock, zval *z_tab)
{
int numElems;

Expand Down Expand Up @@ -1617,6 +1622,87 @@ geosearch_cast(zval *zv)
return SUCCESS;
}

PHP_REDIS_API int
redis_read_mpop_response(RedisSock *redis_sock, zval *zdst, int elements,
void *ctx)
{
int subele, keylen;
zval zele = {0};
char *key;

ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);

if (elements < 0) {
REDIS_ZVAL_NULL(redis_sock, zdst);
return SUCCESS;
}

/* Invariant: We should have two elements */
ZEND_ASSERT(elements == 2);

array_init(zdst);

/* Key name and number of entries */
if ((key = redis_sock_read(redis_sock, &keylen)) == NULL ||
read_mbulk_header(redis_sock, &elements) < 0 || elements < 0)
{
if (key) efree(key);
goto fail;
}

add_next_index_stringl(zdst, key, keylen);
efree(key);

array_init_size(&zele, elements);

if (ctx == PHPREDIS_CTX_PTR) {
for (int i = 0; i < elements; i++) {
if (read_mbulk_header(redis_sock, &subele) < 0 || subele != 2) {
zval_dtor(&zele);
goto fail;
}
redis_mbulk_reply_loop(redis_sock, &zele, subele, UNSERIALIZE_KEYS);
}

array_zip_values_and_scores(redis_sock, &zele, SCORE_DECODE_DOUBLE);
} else {
redis_mbulk_reply_loop(redis_sock, &zele, elements, UNSERIALIZE_ALL);
}

add_next_index_zval(zdst, &zele);

return SUCCESS;

fail:
zval_dtor(zdst);
ZVAL_FALSE(zdst);

return FAILURE;
}

PHP_REDIS_API int
redis_mpop_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
int elements, res = SUCCESS;
zval zret = {0};

if (read_mbulk_header(redis_sock, &elements) == FAILURE ||
redis_read_mpop_response(redis_sock, &zret, elements, ctx) == FAILURE)
{
res = FAILURE;
ZVAL_FALSE(&zret);
}

if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&zret, 0, 0);
} else {
add_next_index_zval(z_tab, &zret);
}

return res;
}

PHP_REDIS_API int
redis_geosearch_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
Expand Down
9 changes: 8 additions & 1 deletion library.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ PHP_REDIS_API void redis_sock_set_auth(RedisSock *redis_sock, zend_string *user,
PHP_REDIS_API void redis_sock_set_auth_zval(RedisSock *redis_sock, zval *zv);
PHP_REDIS_API void redis_sock_free_auth(RedisSock *redis_sock);
PHP_REDIS_API int redis_sock_disconnect(RedisSock *redis_sock, int force);
PHP_REDIS_API zval *redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab);
PHP_REDIS_API zval *redis_sock_read_multibulk_reply_zval(RedisSock *redis_sock, zval *z_tab);
PHP_REDIS_API int redis_sock_read_single_line(RedisSock *redis_sock, char *buffer,
size_t buflen, size_t *linelen, int set_err);
PHP_REDIS_API char *redis_sock_read_bulk_reply(RedisSock *redis_sock, int bytes);
Expand Down Expand Up @@ -148,6 +148,13 @@ redis_read_xclaim_response(RedisSock *redis_sock, int count, zval *rv);
PHP_REDIS_API int
redis_read_xinfo_response(RedisSock *redis_sock, zval *z_ret, int elements);

PHP_REDIS_API int
redis_mpop_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx);

PHP_REDIS_API int
redis_read_mpop_response(RedisSock *redis_sock, zval *zdst, int elements, void *ctx);

/* Specialized ACL reply handlers */
PHP_REDIS_API int redis_read_acl_getuser_reply(RedisSock *redis_sock, zval *zret, long len);
PHP_REDIS_API int redis_acl_getuser_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
Expand Down
27 changes: 25 additions & 2 deletions redis.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,8 +368,8 @@ static void add_class_constants(zend_class_entry *ce, int is_cluster) {
/* Cluster doesn't support pipelining at this time */
zend_declare_class_constant_long(ce, ZEND_STRL("PIPELINE"), PIPELINE);

zend_declare_class_constant_stringl(ce, "LEFT", 4, "left", 4);
zend_declare_class_constant_stringl(ce, "RIGHT", 5, "right", 5);
zend_declare_class_constant_stringl(ce, ZEND_STRL("LEFT"), ZEND_STRL("left"));
zend_declare_class_constant_stringl(ce, ZEND_STRL("RIGHT"), ZEND_STRL("right"));
}

/* retry/backoff options*/
Expand Down Expand Up @@ -2157,6 +2157,29 @@ PHP_METHOD(Redis, bzPopMin) {
}
/* }}} */

/* {{{ proto Redis|array|false Redis::lmpop(array $keys, string $from, int $count = 1) */
PHP_METHOD(Redis, lmpop) {
REDIS_PROCESS_KW_CMD("LMPOP", redis_mpop_cmd, redis_mpop_response);
}
/* }}} */

/* {{{ proto Redis|array|false Redis::blmpop(double $timeout, array $keys, string $from, int $count = 1) */
PHP_METHOD(Redis, blmpop) {
REDIS_PROCESS_KW_CMD("BLMPOP", redis_mpop_cmd, redis_mpop_response);
}
/* }}} */

/* {{{ proto Redis|array|false Redis::zmpop(array $keys, string $from, int $count = 1) */
PHP_METHOD(Redis, zmpop) {
REDIS_PROCESS_KW_CMD("ZMPOP", redis_mpop_cmd, redis_mpop_response);
}

/* {{{ proto Redis|array|false Redis::bzmpop(double $timeout, array $keys, string $from, int $count = 1) */
PHP_METHOD(Redis, bzmpop) {
REDIS_PROCESS_KW_CMD("BZMPOP", redis_mpop_cmd, redis_mpop_response);
}

/* }}} */
/* hashes */

/* {{{ proto long Redis::hset(string key, string mem, string val) */
Expand Down
8 changes: 8 additions & 0 deletions redis.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ public function bzPopMax(string|array $key, string|int $timeout_or_key, mixed ..

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

public function bzmpop(float $timeout, array $keys, string $from, int $count = 1): Redis|array|null|false;

public function zmpop(array $keys, string $from, int $count = 1): Redis|array|null|false;

public function blmpop(float $timeout, array $keys, string $from, int $count = 1): Redis|array|null|false;

public function lmpop(array $keys, string $from, int $count = 1): Redis|array|null|false;

public function clearLastError(): bool;

public function client(string $opt, mixed ...$args): mixed;
Expand Down
27 changes: 26 additions & 1 deletion redis_arginfo.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: d7e7c4d63f53a7eeeb17a5d54ce3ee1173eb18e6 */
* Stub hash: f547b5f24c4d373043c89dab57d450d27f959b08 */

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")
Expand Down Expand Up @@ -92,6 +92,23 @@ ZEND_END_ARG_INFO()

#define arginfo_class_Redis_bzPopMin arginfo_class_Redis_bzPopMax

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)
ZEND_ARG_TYPE_INFO(0, timeout, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, from, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "1")
ZEND_END_ARG_INFO()

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)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, from, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "1")
ZEND_END_ARG_INFO()

#define arginfo_class_Redis_blmpop arginfo_class_Redis_bzmpop

#define arginfo_class_Redis_lmpop arginfo_class_Redis_zmpop

#define arginfo_class_Redis_clearLastError arginfo_class_Redis_bgSave

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_client, 0, 1, IS_MIXED, 0)
Expand Down Expand Up @@ -1073,6 +1090,10 @@ ZEND_METHOD(Redis, brPop);
ZEND_METHOD(Redis, brpoplpush);
ZEND_METHOD(Redis, bzPopMax);
ZEND_METHOD(Redis, bzPopMin);
ZEND_METHOD(Redis, bzmpop);
ZEND_METHOD(Redis, zmpop);
ZEND_METHOD(Redis, blmpop);
ZEND_METHOD(Redis, lmpop);
ZEND_METHOD(Redis, clearLastError);
ZEND_METHOD(Redis, client);
ZEND_METHOD(Redis, close);
Expand Down Expand Up @@ -1309,6 +1330,10 @@ static const zend_function_entry class_Redis_methods[] = {
ZEND_ME(Redis, brpoplpush, arginfo_class_Redis_brpoplpush, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bzPopMax, arginfo_class_Redis_bzPopMax, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bzPopMin, arginfo_class_Redis_bzPopMin, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bzmpop, arginfo_class_Redis_bzmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zmpop, arginfo_class_Redis_zmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, blmpop, arginfo_class_Redis_blmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lmpop, arginfo_class_Redis_lmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, clearLastError, arginfo_class_Redis_clearLastError, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, client, arginfo_class_Redis_client, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, close, arginfo_class_Redis_close, ZEND_ACC_PUBLIC)
Expand Down
23 changes: 23 additions & 0 deletions redis_cluster.c
Original file line number Diff line number Diff line change
Expand Up @@ -1336,7 +1336,30 @@ PHP_METHOD(RedisCluster, lcs) {
CLUSTER_PROCESS_CMD(lcs, cluster_variant_resp, 1);
}

/* {{{ proto Redis|array|false Redis::lmpop(array $keys, string $from, int $count = 1) */
PHP_METHOD(RedisCluster, lmpop) {
CLUSTER_PROCESS_KW_CMD("LMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
}
/* }}} */

/* {{{ proto Redis|array|false Redis::blmpop(double $timeout, array $keys, string $from, int $count = 1) */
PHP_METHOD(RedisCluster, blmpop) {
CLUSTER_PROCESS_KW_CMD("BLMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
}
/* }}} */

/* {{{ proto Redis|array|false Redis::zmpop(array $keys, string $from, int $count = 1) */
PHP_METHOD(RedisCluster, zmpop) {
CLUSTER_PROCESS_KW_CMD("ZMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
}
/* }}} */

/* {{{ proto Redis|array|false Redis::bzmpop(double $timeout, array $keys, sring $from, int $count = 1) */
PHP_METHOD(RedisCluster, bzmpop) {
CLUSTER_PROCESS_KW_CMD("BZMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
}
/* }}} */

/* {{{ proto string RedisCluster::ltrim(string key, long start, long end) */
PHP_METHOD(RedisCluster, ltrim) {
CLUSTER_PROCESS_KW_CMD("LTRIM", redis_key_long_long_cmd, cluster_bool_resp, 0);
Expand Down
8 changes: 8 additions & 0 deletions redis_cluster.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ public function bzpopmax(string|array $key, string|int $timeout_or_key, mixed ..

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

public function bzmpop(float $timeout, array $keys, string $from, int $count = 1): Redis|array|null|false;

public function zmpop(array $keys, string $from, int $count = 1): Redis|array|null|false;

public function blmpop(float $timeout, array $keys, string $from, int $count = 1): Redis|array|null|false;

public function lmpop(array $keys, string $from, int $count = 1): Redis|array|null|false;

public function clearlasterror(): bool;

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