mirror of
https://github.com/php-win-ext/phpredis.git
synced 2026-03-24 00:52:16 +01:00
Add more docblocks and fix XAUTOCLAIM response handler.
- Finish adding docblocks with examples for all of the stream commands. - Fix XAUTOCLAIM response handler (the reply has a slightly different structure to XCLAIM.
This commit is contained in:
committed by
Michael Grunder
parent
c14a9e3a01
commit
0b7bd83f57
@@ -2333,7 +2333,9 @@ cluster_xclaim_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
|
||||
|
||||
array_init(&z_msg);
|
||||
|
||||
if (redis_read_xclaim_response(c->cmd_sock, c->reply_len, &z_msg) < 0) {
|
||||
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
|
||||
|
||||
if (redis_read_xclaim_reply(c->cmd_sock, c->reply_len, ctx == PHPREDIS_CTX_PTR, &z_msg) < 0) {
|
||||
zval_dtor(&z_msg);
|
||||
CLUSTER_RETURN_FALSE(c);
|
||||
}
|
||||
|
||||
87
library.c
87
library.c
@@ -1999,11 +1999,9 @@ failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This helper function does that actual XCLAIM response handling, which can be used by both
|
||||
* Redis and RedisCluster. Note that XCLAIM is somewhat unique in that its reply type depends
|
||||
* on whether or not it was called with the JUSTID option */
|
||||
PHP_REDIS_API int
|
||||
redis_read_xclaim_response(RedisSock *redis_sock, int count, zval *rv) {
|
||||
/* A helper method to read X[AUTO]CLAIM messages into an array. */
|
||||
static int
|
||||
redis_read_xclaim_ids(RedisSock *redis_sock, int count, zval *rv) {
|
||||
zval z_msg;
|
||||
REDIS_REPLY_TYPE type;
|
||||
char *id = NULL;
|
||||
@@ -2011,6 +2009,8 @@ redis_read_xclaim_response(RedisSock *redis_sock, int count, zval *rv) {
|
||||
long li;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
id = NULL;
|
||||
|
||||
/* Consume inner reply type */
|
||||
if (redis_read_reply_type(redis_sock, &type, &li) < 0 ||
|
||||
(type != TYPE_BULK && type != TYPE_MULTIBULK) ||
|
||||
@@ -2043,29 +2043,88 @@ redis_read_xclaim_response(RedisSock *redis_sock, int count, zval *rv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read an X[AUTO]CLAIM reply having already consumed the reply-type byte. */
|
||||
PHP_REDIS_API int
|
||||
redis_read_xclaim_reply(RedisSock *redis_sock, int count, int is_xautoclaim, zval *rv) {
|
||||
REDIS_REPLY_TYPE type;
|
||||
zval z_msgs = {0};
|
||||
char *id = NULL;
|
||||
long id_len = 0;
|
||||
int messages;
|
||||
|
||||
ZEND_ASSERT(!is_xautoclaim || count == 3);
|
||||
|
||||
ZVAL_UNDEF(rv);
|
||||
|
||||
/* If this is XAUTOCLAIM consume the BULK ID and then the actual number of IDs.
|
||||
* Otherwise, our 'count' argument is the number of IDs. */
|
||||
if (is_xautoclaim) {
|
||||
if (redis_read_reply_type(redis_sock, &type, &id_len) < 0 || type != TYPE_BULK)
|
||||
goto failure;
|
||||
if ((id = redis_sock_read_bulk_reply(redis_sock, id_len)) == NULL)
|
||||
goto failure;
|
||||
if (read_mbulk_header(redis_sock, &messages) < 0)
|
||||
goto failure;
|
||||
} else {
|
||||
messages = count;
|
||||
}
|
||||
|
||||
array_init(&z_msgs);
|
||||
|
||||
if (redis_read_xclaim_ids(redis_sock, messages, &z_msgs) < 0)
|
||||
goto failure;
|
||||
|
||||
/* If XAUTOCLAIM we now need to consume the final array of message IDs */
|
||||
if (is_xautoclaim) {
|
||||
zval z_deleted = {0};
|
||||
|
||||
if (redis_sock_read_multibulk_reply_zval(redis_sock, &z_deleted) == NULL)
|
||||
goto failure;
|
||||
|
||||
array_init(rv);
|
||||
|
||||
// Package up ID, message, and deleted messages in our reply
|
||||
add_next_index_stringl(rv, id, id_len);
|
||||
add_next_index_zval(rv, &z_msgs);
|
||||
add_next_index_zval(rv, &z_deleted);
|
||||
|
||||
efree(id);
|
||||
} else {
|
||||
// We just want the messages
|
||||
ZVAL_COPY_VALUE(rv, &z_msgs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
zval_dtor(&z_msgs);
|
||||
zval_dtor(rv);
|
||||
if (id) efree(id);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
PHP_REDIS_API int
|
||||
redis_xclaim_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
|
||||
zval *z_tab, void *ctx)
|
||||
{
|
||||
zval z_ret;
|
||||
int messages;
|
||||
zval z_ret = {0};
|
||||
int count;
|
||||
|
||||
/* All XCLAIM responses start multibulk */
|
||||
if (read_mbulk_header(redis_sock, &messages) < 0)
|
||||
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
|
||||
|
||||
if (read_mbulk_header(redis_sock, &count) < 0)
|
||||
goto failure;
|
||||
|
||||
array_init(&z_ret);
|
||||
|
||||
if (redis_read_xclaim_response(redis_sock, messages, &z_ret) < 0) {
|
||||
zval_dtor(&z_ret);
|
||||
if (redis_read_xclaim_reply(redis_sock, count, ctx == PHPREDIS_CTX_PTR, &z_ret) < 0)
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (IS_ATOMIC(redis_sock)) {
|
||||
RETVAL_ZVAL(&z_ret, 0, 1);
|
||||
} else {
|
||||
add_next_index_zval(z_tab, &z_ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
|
||||
@@ -104,8 +104,12 @@ PHP_REDIS_API int redis_xrange_reply(INTERNAL_FUNCTION_PARAMETERS,
|
||||
RedisSock *redis_sock, zval *z_tab, void *ctx);
|
||||
PHP_REDIS_API int redis_xread_reply(INTERNAL_FUNCTION_PARAMETERS,
|
||||
RedisSock *redis_sock, zval *z_tab, void *ctx);
|
||||
|
||||
PHP_REDIS_API int redis_xclaim_reply(INTERNAL_FUNCTION_PARAMETERS,
|
||||
RedisSock *redis_sock, zval *z_tab, void *ctx);
|
||||
PHP_REDIS_API int redis_read_xclaim_reply(
|
||||
RedisSock *redis_sock, int count, int is_xautoclaim, zval *rv);
|
||||
|
||||
PHP_REDIS_API int redis_xinfo_reply(INTERNAL_FUNCTION_PARAMETERS,
|
||||
RedisSock *redis_sock, zval *z_tab, void *ctx);
|
||||
|
||||
@@ -149,8 +153,6 @@ redis_read_stream_messages(RedisSock *redis_sock, int count, zval *z_ret);
|
||||
PHP_REDIS_API int
|
||||
redis_read_stream_messages_multi(RedisSock *redis_sock, int count, zval *z_ret);
|
||||
PHP_REDIS_API int
|
||||
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
|
||||
|
||||
304
redis.stub.php
304
redis.stub.php
@@ -2919,6 +2919,25 @@ class Redis {
|
||||
* Redis::REDIS_ZSET
|
||||
* Redis::REDIS_HASH
|
||||
* Redis::REDIS_STREAM
|
||||
*
|
||||
* <code>
|
||||
* <?php
|
||||
* $redis = new Redis(['host' => 'localhost']);
|
||||
*
|
||||
* // NOTE: Never use 'KEYS' in production!
|
||||
* $keys = $redis->keys('*');
|
||||
*
|
||||
* $redis->pipeline();
|
||||
* foreach ($keys as $key) {
|
||||
* $redis->type($key);
|
||||
* }
|
||||
*
|
||||
* $ktypes = array_combine($keys, $redis->exec());
|
||||
*
|
||||
* // Print each key with its corresponding type
|
||||
* print_r($ktypes);
|
||||
* ?>
|
||||
* </code>
|
||||
*/
|
||||
public function type(string $key): Redis|int|false;
|
||||
|
||||
@@ -2949,6 +2968,22 @@ class Redis {
|
||||
* @see https://redis.io/commands/unsubscribe
|
||||
* @see Redis::subscribe()
|
||||
*
|
||||
* <code>
|
||||
* <?php
|
||||
* $redis = new Redis(['host' => 'localhost']);
|
||||
*
|
||||
* $redis->subscribe(['channel-1', 'channel-2'], function ($redis, $channel, $message) {
|
||||
* if ($message == 'quit') {
|
||||
* echo "$channel => 'quit' detected, unsubscribing!\n";
|
||||
* $redis->unsubscribe([$channel]);
|
||||
* } else {
|
||||
* echo "$channel => $message\n";
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* echo "We've unsubscribed from both channels, exiting\n";
|
||||
* ?>
|
||||
* </code>
|
||||
*/
|
||||
public function unsubscribe(array $channels): Redis|array|bool;
|
||||
|
||||
@@ -2964,9 +2999,48 @@ class Redis {
|
||||
public function unwatch(): Redis|bool;
|
||||
|
||||
/**
|
||||
* @return bool|Redis
|
||||
* Watch one or more keys for conditional execution of a transaction.
|
||||
*
|
||||
* @see https://redis.io/commands/watch
|
||||
* @see https://redis.io/commands/unwatch
|
||||
*
|
||||
* @param array|string $key_or_keys Either an array with one or more key names, or a string key name
|
||||
* @param string $other_keys If the first argument was passed as a string, any number of additional
|
||||
* string key names may be passed variadically.
|
||||
*
|
||||
* @return Redis|bool
|
||||
*
|
||||
* <code>
|
||||
* <?php
|
||||
*
|
||||
* $redis1 = new Redis(['host' => 'localhost']);
|
||||
* $redis2 = new Redis(['host' => 'localhost']);
|
||||
*
|
||||
* // Start watching 'incr-key'
|
||||
* $redis1->watch('incr-key');
|
||||
*
|
||||
* // Retrieve its value.
|
||||
* $val = $redis1->get('incr-key');
|
||||
*
|
||||
* // A second client modifies 'incr-key' after we read it.
|
||||
* $redis2->set('incr-key', 0);
|
||||
*
|
||||
* // Because another client changed the value of 'incr-key' after we read it, this
|
||||
* // is no longer a proper increment operation, but because we are `WATCH`ing the
|
||||
* // key, this transaction will fail and we can try again.
|
||||
* //
|
||||
* // If were to comment out the above `$redis2->set('incr-key', 0)` line the
|
||||
* // transaction would succeed.
|
||||
* $redis1->multi();
|
||||
* $redis1->set('incr-key', $val + 1);
|
||||
* $res = $redis1->exec();
|
||||
*
|
||||
* // bool(false)
|
||||
* var_dump($res);
|
||||
* </code>
|
||||
*
|
||||
*/
|
||||
public function watch(array|string $key, string ...$other_keys);
|
||||
public function watch(array|string $key, string ...$other_keys): Redis|bool;
|
||||
|
||||
/**
|
||||
* Block the client up to the provided timeout until a certain number of replicas have confirmed
|
||||
@@ -2982,6 +3056,46 @@ class Redis {
|
||||
*/
|
||||
public function wait(int $numreplicas, int $timeout): int|false;
|
||||
|
||||
/**
|
||||
* Acknowledge one ore more messages that are pending (have been consumed using XREADGROUP but
|
||||
* not yet acknowledged by XACK.)
|
||||
*
|
||||
* @see https://redis.io/commands/xack
|
||||
* @see https://redis.io/commands/xreadgroup
|
||||
* @see Redis::xack()
|
||||
*
|
||||
* <code>
|
||||
* <?php
|
||||
* $redis = new Redis(['host' => 'localhost']);
|
||||
*
|
||||
* $redis->del('ships');
|
||||
*
|
||||
* $redis->xAdd('ships', '*', ['name' => 'Enterprise']);
|
||||
* $redis->xAdd('ships', '*', ['name' => 'Defiant']);
|
||||
*
|
||||
* $redis->xGroup('CREATE', 'ships', 'Federation', '0-0');
|
||||
*
|
||||
* // Consume a single message with the consumer group 'Federation'
|
||||
* $ship = $redis->xReadGroup('Federation', 'Picard', ['ships' => '>'], 1);
|
||||
*
|
||||
* /* Retrieve the ID of the message we read.
|
||||
* assert(isset($ship['ships']));
|
||||
* $id = key($ship['ships']);
|
||||
*
|
||||
* // The message we just read is now pending.
|
||||
* $res = $redis->xPending('ships', 'Federation'));
|
||||
* var_dump($res);
|
||||
*
|
||||
* // We can tell Redis we were able to process the message by using XACK
|
||||
* $res = $redis->xAck('ships', 'Federation', [$id]);
|
||||
* assert($res === 1);
|
||||
*
|
||||
* // The message should no longer be pending.
|
||||
* $res = $redis->xPending('ships', 'Federation');
|
||||
* var_dump($res);
|
||||
* ?>
|
||||
* </code>
|
||||
*/
|
||||
public function xack(string $key, string $group, array $ids): int|false;
|
||||
|
||||
/**
|
||||
@@ -3007,9 +3121,193 @@ class Redis {
|
||||
*/
|
||||
public function xadd(string $key, string $id, array $values, int $maxlen = 0, bool $approx = false, bool $nomkstream = false): Redis|string|false;
|
||||
|
||||
/**
|
||||
* This command allows a consumer to claim pending messages that have been idle for a specified period of time.
|
||||
* Its purpose is to provide a mechanism for picking up messages that may have had a failed consumer.
|
||||
*
|
||||
* @see https://redis.io/commands/xautoclaim
|
||||
* @see https://redis.io/commands/xclaim
|
||||
* @see https://redis.io/docs/data-types/streams-tutorial/
|
||||
*
|
||||
* @param string $key The stream to check.
|
||||
* @param string $group The consumer group to query.
|
||||
* @param string $consumer Which consumer to check.
|
||||
* @param int $min_idle The minimum time in milliseconds for the message to have been pending.
|
||||
* @param string $start The minimum message id to check.
|
||||
* @param int $count An optional limit on how many messages are returned.
|
||||
* @param bool $justid If the client only wants message IDs and not all of their data.
|
||||
*
|
||||
* @return Redis|array|bool An array of pending IDs or false if there are none, or on failure.
|
||||
*
|
||||
* <code>
|
||||
* <?php
|
||||
* $redis = new Redis(['host' => 'localhost']);
|
||||
*
|
||||
* $redis->del('ships');
|
||||
*
|
||||
* $redis->xGroup('CREATE', 'ships', 'combatants', '0-0', true);
|
||||
*
|
||||
* $redis->xAdd('ships', '1424-74205', ['name' => 'Defiant']);
|
||||
*
|
||||
* // Consume the ['name' => 'Defiant'] message
|
||||
* $msgs = $redis->xReadGroup('combatants', "Jem'Hadar", ['ships' => '>'], 1);
|
||||
*
|
||||
* // The "Jem'Hadar" consumer has the message presently
|
||||
* $pending = $redis->xPending('ships', 'combatants');
|
||||
*
|
||||
* //array(4) {
|
||||
* // [0]=>
|
||||
* // int(1)
|
||||
* // [1]=>
|
||||
* // string(10) "1424-74205"
|
||||
* // [2]=>
|
||||
* // string(10) "1424-74205"
|
||||
* // [3]=>
|
||||
* // array(1) {
|
||||
* // [0]=>
|
||||
* // array(2) {
|
||||
* // [0]=>
|
||||
* // string(9) "Jem'Hadar"
|
||||
* // [1]=>
|
||||
* // string(1) "1"
|
||||
* // }
|
||||
* // }
|
||||
* //}
|
||||
* var_dump($pending);
|
||||
*
|
||||
* // Asssume control of the pending message with a different consumer.
|
||||
* $res = $redis->xAutoClaim('ships', 'combatants', 'Sisko', 0, '0-0');
|
||||
*
|
||||
* // Now the 'Sisko' consumer owns the message
|
||||
* $pending = $redis->xPending('ships', 'combatants');
|
||||
*
|
||||
* // array(4) {
|
||||
* // [0]=>
|
||||
* // int(1)
|
||||
* // [1]=>
|
||||
* // string(10) "1424-74205"
|
||||
* // [2]=>
|
||||
* // string(10) "1424-74205"
|
||||
* // [3]=>
|
||||
* // array(1) {
|
||||
* // [0]=>
|
||||
* // array(2) {
|
||||
* // [0]=>
|
||||
* // string(5) "Sisko"
|
||||
* // [1]=>
|
||||
* // string(1) "1"
|
||||
* // }
|
||||
* // }
|
||||
* // }
|
||||
* var_dump($pending);
|
||||
* ?>
|
||||
* </code>
|
||||
*/
|
||||
public function xautoclaim(string $key, string $group, string $consumer, int $min_idle, string $start, int $count = -1, bool $justid = false): Redis|bool|array;
|
||||
|
||||
public function xclaim(string $key, string $group, string $consumer, int $min_idle, array $ids, array $options): Redis|bool|array;
|
||||
/**
|
||||
* This method allows a consumer to take ownership of pending stream entries, by ID. Another
|
||||
* command that does much the same thing but does not require passing specific IDs is `Redis::xAutoClaim`.
|
||||
*
|
||||
* @see https://redis.io/commands/xclaim
|
||||
* @see https://redis.io/commands/xautoclaim.
|
||||
*
|
||||
* @param string $key The stream we wish to claim messages for.
|
||||
* @param string $group Our consumer group.
|
||||
* @param string $consumer Our consumer.
|
||||
* @param int $min_idle_time The minimum idle-time in milliseconds a message must have for ownership to be transferred.
|
||||
* @param array $options An options array that modifies how the command operates.
|
||||
*
|
||||
* <code>
|
||||
* // Following is an options array describing every option you can pass. Note that
|
||||
* // 'IDLE', and 'TIME' are mutually exclusive.
|
||||
* $options = [
|
||||
* 'IDLE' => 3 // Set the idle time of the message to a 3. By default the
|
||||
* // idle time is set to zero.
|
||||
* 'TIME' => 1000*time() // Same as IDLE except it takes a unix timestamp in milliseconds.
|
||||
* 'RETRYCOUNT' => 0 // Set the retry counter to zero. By default XCLAIM doesn't modify
|
||||
* // the counter.
|
||||
* 'FORCE' // Creates the pending message entry even if IDs are not already
|
||||
* // in the PEL with another client.
|
||||
* 'JUSTID' // Return only an array of IDs rather than the messages themselves.
|
||||
* ];
|
||||
* </code>
|
||||
*
|
||||
* @return Redis|array|bool An array of claimed messags or false on failure.
|
||||
*
|
||||
* <code>
|
||||
* <?php
|
||||
* $redis = new Redis(['host' => 'localhost']);
|
||||
*
|
||||
* $redis->del('ships');
|
||||
*
|
||||
* $redis->xGroup('CREATE', 'ships', 'combatants', '0-0', true);
|
||||
*
|
||||
* $redis->xAdd('ships', '1424-74205', ['name' => 'Defiant']);
|
||||
*
|
||||
* // Consume the ['name' => 'Defiant'] message
|
||||
* $msgs = $redis->xReadGroup('combatants', "Jem'Hadar", ['ships' => '>'], 1);
|
||||
*
|
||||
* // The "Jem'Hadar" consumer has the message presently
|
||||
* $pending = $redis->xPending('ships', 'combatants');
|
||||
*
|
||||
* //array(4) {
|
||||
* // [0]=>
|
||||
* // int(1)
|
||||
* // [1]=>
|
||||
* // string(10) "1424-74205"
|
||||
* // [2]=>
|
||||
* // string(10) "1424-74205"
|
||||
* // [3]=>
|
||||
* // array(1) {
|
||||
* // [0]=>
|
||||
* // array(2) {
|
||||
* // [0]=>
|
||||
* // string(9) "Jem'Hadar"
|
||||
* // [1]=>
|
||||
* // string(1) "1"
|
||||
* // }
|
||||
* // }
|
||||
* //}
|
||||
* var_dump($pending);
|
||||
*
|
||||
* assert($pending && isset($pending[1]));
|
||||
*
|
||||
* // Claim the message by ID.
|
||||
* $claimed = $redis->xClaim('ships', 'combatants', 'Sisko', 0, [$pending[1]], ['JUSTID']);
|
||||
*
|
||||
* // array(1) {
|
||||
* // [0]=>
|
||||
* // string(10) "1424-74205"
|
||||
* // }
|
||||
* var_dump($claimed);
|
||||
*
|
||||
* // Now the 'Sisko' consumer owns the message
|
||||
* $pending = $redis->xPending('ships', 'combatants');
|
||||
*
|
||||
* // array(4) {
|
||||
* // [0]=>
|
||||
* // int(1)
|
||||
* // [1]=>
|
||||
* // string(10) "1424-74205"
|
||||
* // [2]=>
|
||||
* // string(10) "1424-74205"
|
||||
* // [3]=>
|
||||
* // array(1) {
|
||||
* // [0]=>
|
||||
* // array(2) {
|
||||
* // [0]=>
|
||||
* // string(5) "Sisko"
|
||||
* // [1]=>
|
||||
* // string(1) "1"
|
||||
* // }
|
||||
* // }
|
||||
* // }
|
||||
* var_dump($pending);
|
||||
* ?>
|
||||
* </code>
|
||||
*/
|
||||
public function xclaim(string $key, string $group, string $consumer, int $min_idle, array $ids, array $options): Redis|array|bool;
|
||||
|
||||
/**
|
||||
* Remove one or more specific IDs from a stream.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 897e7ef01adac7ae817e3f6678569996786cf8ed */
|
||||
* Stub hash: 7230a9518fe0e79ae51f6b49d269053535a34199 */
|
||||
|
||||
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")
|
||||
@@ -860,7 +860,7 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_Redis_unwatch arginfo_class_Redis_bgSave
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_watch, 0, 0, 1)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_watch, 0, 1, Redis, MAY_BE_BOOL)
|
||||
ZEND_ARG_TYPE_MASK(0, key, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
|
||||
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
@@ -895,7 +895,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xautoclaim, 0, 5
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, justid, _IS_BOOL, 0, "false")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xclaim, 0, 6, Redis, MAY_BE_BOOL|MAY_BE_ARRAY)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xclaim, 0, 6, Redis, MAY_BE_ARRAY|MAY_BE_BOOL)
|
||||
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, consumer, IS_STRING, 0)
|
||||
|
||||
@@ -2904,6 +2904,10 @@ PHP_METHOD(RedisCluster, xclaim) {
|
||||
CLUSTER_PROCESS_CMD(xclaim, cluster_xclaim_resp, 0);
|
||||
}
|
||||
|
||||
PHP_METHOD(RedisCluster, xautoclaim) {
|
||||
CLUSTER_PROCESS_CMD(xautoclaim, cluster_xclaim_resp, 0);
|
||||
}
|
||||
|
||||
PHP_METHOD(RedisCluster, xdel) {
|
||||
CLUSTER_PROCESS_KW_CMD("XDEL", redis_key_str_arr_cmd, cluster_long_resp, 0);
|
||||
}
|
||||
|
||||
@@ -895,7 +895,13 @@ class RedisCluster {
|
||||
/**
|
||||
* @see Redis::xgroup
|
||||
*/
|
||||
public function xgroup(string $operation, string $key = null, string $arg1 = null, string $arg2 = null, bool $arg3 = false): mixed;
|
||||
public function xgroup(string $operation, string $key = null, string $group = null, string $id_or_consumer = null,
|
||||
bool $mkstream = false, int $entries_read = -2): mixed;
|
||||
|
||||
/**
|
||||
* @see Redis::xautoclaim
|
||||
*/
|
||||
public function xautoclaim(string $key, string $group, string $consumer, int $min_idle, string $start, int $count = -1, bool $justid = false): Redis|bool|array;
|
||||
|
||||
/**
|
||||
* @see Redis::xinfo
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 1783d14c476f95598062edb44dab7284b9b2680d */
|
||||
* Stub hash: 2f2132e45b1d60011f8ef9298cb35b7ba2b247d5 */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 1)
|
||||
@@ -773,9 +773,20 @@ ZEND_END_ARG_INFO()
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_xgroup, 0, 1, IS_MIXED, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, operation, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, key, IS_STRING, 0, "null")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg1, IS_STRING, 0, "null")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg2, IS_STRING, 0, "null")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg3, _IS_BOOL, 0, "false")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, group, IS_STRING, 0, "null")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, id_or_consumer, IS_STRING, 0, "null")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mkstream, _IS_BOOL, 0, "false")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, entries_read, IS_LONG, 0, "-2")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xautoclaim, 0, 5, Redis, MAY_BE_BOOL|MAY_BE_ARRAY)
|
||||
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, consumer, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, min_idle, IS_LONG, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, justid, _IS_BOOL, 0, "false")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_xinfo, 0, 1, IS_MIXED, 0)
|
||||
@@ -1122,6 +1133,7 @@ ZEND_METHOD(RedisCluster, xadd);
|
||||
ZEND_METHOD(RedisCluster, xclaim);
|
||||
ZEND_METHOD(RedisCluster, xdel);
|
||||
ZEND_METHOD(RedisCluster, xgroup);
|
||||
ZEND_METHOD(RedisCluster, xautoclaim);
|
||||
ZEND_METHOD(RedisCluster, xinfo);
|
||||
ZEND_METHOD(RedisCluster, xlen);
|
||||
ZEND_METHOD(RedisCluster, xpending);
|
||||
@@ -1331,6 +1343,7 @@ static const zend_function_entry class_RedisCluster_methods[] = {
|
||||
ZEND_ME(RedisCluster, xclaim, arginfo_class_RedisCluster_xclaim, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xdel, arginfo_class_RedisCluster_xdel, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xgroup, arginfo_class_RedisCluster_xgroup, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xautoclaim, arginfo_class_RedisCluster_xautoclaim, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xinfo, arginfo_class_RedisCluster_xinfo, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xlen, arginfo_class_RedisCluster_xlen, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xpending, arginfo_class_RedisCluster_xpending, ZEND_ACC_PUBLIC)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 1783d14c476f95598062edb44dab7284b9b2680d */
|
||||
* Stub hash: 2f2132e45b1d60011f8ef9298cb35b7ba2b247d5 */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, name)
|
||||
@@ -653,9 +653,20 @@ ZEND_END_ARG_INFO()
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xgroup, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, operation)
|
||||
ZEND_ARG_INFO(0, key)
|
||||
ZEND_ARG_INFO(0, arg1)
|
||||
ZEND_ARG_INFO(0, arg2)
|
||||
ZEND_ARG_INFO(0, arg3)
|
||||
ZEND_ARG_INFO(0, group)
|
||||
ZEND_ARG_INFO(0, id_or_consumer)
|
||||
ZEND_ARG_INFO(0, mkstream)
|
||||
ZEND_ARG_INFO(0, entries_read)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xautoclaim, 0, 0, 5)
|
||||
ZEND_ARG_INFO(0, key)
|
||||
ZEND_ARG_INFO(0, group)
|
||||
ZEND_ARG_INFO(0, consumer)
|
||||
ZEND_ARG_INFO(0, min_idle)
|
||||
ZEND_ARG_INFO(0, start)
|
||||
ZEND_ARG_INFO(0, count)
|
||||
ZEND_ARG_INFO(0, justid)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xinfo, 0, 0, 1)
|
||||
@@ -973,6 +984,7 @@ ZEND_METHOD(RedisCluster, xadd);
|
||||
ZEND_METHOD(RedisCluster, xclaim);
|
||||
ZEND_METHOD(RedisCluster, xdel);
|
||||
ZEND_METHOD(RedisCluster, xgroup);
|
||||
ZEND_METHOD(RedisCluster, xautoclaim);
|
||||
ZEND_METHOD(RedisCluster, xinfo);
|
||||
ZEND_METHOD(RedisCluster, xlen);
|
||||
ZEND_METHOD(RedisCluster, xpending);
|
||||
@@ -1182,6 +1194,7 @@ static const zend_function_entry class_RedisCluster_methods[] = {
|
||||
ZEND_ME(RedisCluster, xclaim, arginfo_class_RedisCluster_xclaim, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xdel, arginfo_class_RedisCluster_xdel, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xgroup, arginfo_class_RedisCluster_xgroup, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xautoclaim, arginfo_class_RedisCluster_xautoclaim, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xinfo, arginfo_class_RedisCluster_xinfo, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xlen, arginfo_class_RedisCluster_xlen, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(RedisCluster, xpending, arginfo_class_RedisCluster_xpending, ZEND_ACC_PUBLIC)
|
||||
|
||||
@@ -5776,10 +5776,8 @@ static int64_t get_xclaim_i64_arg(const char *key, zval *zv) {
|
||||
|
||||
/* Helper to extract XCLAIM options */
|
||||
static void get_xclaim_options(zval *z_arr, xclaimOptions *opt) {
|
||||
HashTable *ht;
|
||||
zend_string *zkey;
|
||||
char *kval;
|
||||
size_t klen;
|
||||
HashTable *ht;
|
||||
zval *zv;
|
||||
|
||||
/* Initialize options array to sane defaults */
|
||||
@@ -5795,29 +5793,20 @@ static void get_xclaim_options(zval *z_arr, xclaimOptions *opt) {
|
||||
ht = Z_ARRVAL_P(z_arr);
|
||||
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, zkey, zv) {
|
||||
if (zkey) {
|
||||
kval = ZSTR_VAL(zkey);
|
||||
klen = ZSTR_LEN(zkey);
|
||||
|
||||
if (klen == 4) {
|
||||
if (!strncasecmp(kval, "TIME", 4)) {
|
||||
opt->idle.type = "TIME";
|
||||
opt->idle.time = get_xclaim_i64_arg("TIME", zv);
|
||||
} else if (!strncasecmp(kval, "IDLE", 4)) {
|
||||
opt->idle.type = "IDLE";
|
||||
opt->idle.time = get_xclaim_i64_arg("IDLE", zv);
|
||||
}
|
||||
} else if (klen == 10 && !strncasecmp(kval, "RETRYCOUNT", 10)) {
|
||||
if (zend_string_equals_literal_ci(zkey, "TIME")) {
|
||||
opt->idle.type = "TIME";
|
||||
opt->idle.time = get_xclaim_i64_arg("TIME", zv);
|
||||
} else if (zend_string_equals_literal_ci(zkey, "IDLE")) {
|
||||
opt->idle.type = "IDLE";
|
||||
opt->idle.time = get_xclaim_i64_arg("IDLE", zv);
|
||||
} else if (zend_string_equals_literal_ci(zkey, "RETRYCOUNT")) {
|
||||
opt->retrycount = zval_get_long(zv);
|
||||
}
|
||||
} else {
|
||||
if (Z_TYPE_P(zv) == IS_STRING) {
|
||||
kval = Z_STRVAL_P(zv);
|
||||
klen = Z_STRLEN_P(zv);
|
||||
if (klen == 5 && !strncasecmp(kval, "FORCE", 5)) {
|
||||
opt->force = 1;
|
||||
} else if (klen == 6 && !strncasecmp(kval, "JUSTID", 6)) {
|
||||
opt->justid = 1;
|
||||
}
|
||||
} else if (Z_TYPE_P(zv) == IS_STRING) {
|
||||
if (zend_string_equals_literal_ci(Z_STR_P(zv), "FORCE")) {
|
||||
opt->force = 1;
|
||||
} else if (zend_string_equals_literal_ci(Z_STR_P(zv), "JUSTID")) {
|
||||
opt->justid = 1;
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
@@ -5898,6 +5887,10 @@ redis_xautoclaim_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
|
||||
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "JUSTID");
|
||||
}
|
||||
|
||||
// Set the context to distinguish XCLAIM from XAUTOCLAIM which
|
||||
// have slightly different reply structures.
|
||||
*ctx = PHPREDIS_CTX_PTR;
|
||||
|
||||
*cmd = cmdstr.c;
|
||||
*cmd_len = cmdstr.len;
|
||||
return SUCCESS;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 897e7ef01adac7ae817e3f6678569996786cf8ed */
|
||||
* Stub hash: 7230a9518fe0e79ae51f6b49d269053535a34199 */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
|
||||
ZEND_ARG_INFO(0, options)
|
||||
|
||||
@@ -6821,6 +6821,7 @@ class Redis_Test extends TestSuite
|
||||
|
||||
for ($n = count($ids); $n >= 0; $n--) {
|
||||
$xp = $this->redis->xPending('s', 'group');
|
||||
|
||||
$this->assertEquals($xp[0], count($ids));
|
||||
|
||||
/* Verify we're seeing the IDs themselves */
|
||||
@@ -6975,6 +6976,36 @@ class Redis_Test extends TestSuite
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure our XAUTOCLAIM handler works */
|
||||
public function testXAutoClaim() {
|
||||
$this->redis->del('ships');
|
||||
$this->redis->xGroup('CREATE', 'ships', 'combatants', '0-0', true);
|
||||
|
||||
// Test an empty xautoclaim reply
|
||||
$res = $this->redis->xAutoClaim('ships', 'combatants', 'Sisko', 0, '0-0');
|
||||
$this->assertEquals(['0-0', [], []], $res);
|
||||
|
||||
$this->redis->xAdd('ships', '1424-74205', ['name' => 'Defiant']);
|
||||
|
||||
// Consume the ['name' => 'Defiant'] message
|
||||
$this->redis->xReadGroup('combatants', "Jem'Hadar", ['ships' => '>'], 1);
|
||||
|
||||
// The "Jem'Hadar" consumer has the message presently
|
||||
$pending = $this->redis->xPending('ships', 'combatants');
|
||||
$this->assertTrue($pending && isset($pending[3][0][0]) && $pending[3][0][0] == "Jem'Hadar");
|
||||
|
||||
// Asssume control of the pending message with a different consumer.
|
||||
$res = $this->redis->xAutoClaim('ships', 'combatants', 'Sisko', 0, '0-0');
|
||||
|
||||
$this->assertTrue($res && count($res) == 3 && $res[0] == '0-0' &&
|
||||
isset($res[1]['1424-74205']['name']) &&
|
||||
$res[1]['1424-74205']['name'] == 'Defiant');
|
||||
|
||||
// Now the 'Sisko' consumer should own the message
|
||||
$pending = $this->redis->xPending('ships', 'combatants');
|
||||
$this->assertTrue(isset($pending[3][0][0]) && $pending[3][0][0] == 'Sisko');
|
||||
}
|
||||
|
||||
public function testXInfo()
|
||||
{
|
||||
if (!$this->minVersionCheck("5.0"))
|
||||
|
||||
Reference in New Issue
Block a user