Skip to content

Commit 2336477

Browse files
Allow for pfcount to take multiple keys
When first creating the pfCount function, I simply allowed for one string value for the key. Either Redis changed since then, or I just missed it initially, but the PFCOUNT command can take one or more keys. This change doesn't break the API (in case anyone is using it under develop now) as it can still take a single string argument, or can take an array.
1 parent 590c753 commit 2336477

File tree

2 files changed

+92
-11
lines changed

2 files changed

+92
-11
lines changed

redis.c

+86-11
Original file line numberDiff line numberDiff line change
@@ -7367,15 +7367,19 @@ PHP_METHOD(Redis, pfadd) {
73677367
REDIS_PROCESS_RESPONSE(redis_1_response);
73687368
}
73697369

7370-
/* {{{ proto Redis::pfCount(string key) }}}*/
7370+
/* {{{ proto Redis::pfCount(string key) }}}
7371+
* proto Redis::pfCount(array keys) }}} */
73717372
PHP_METHOD(Redis, pfcount) {
7372-
zval *object;
7373+
zval *object, *z_keys, **z_key, *z_tmp = NULL;
7374+
HashTable *ht_keys;
7375+
HashPosition ptr;
73737376
RedisSock *redis_sock;
7374-
char *key, *cmd;
7375-
int key_len, cmd_len, key_free;
7377+
smart_str cmd = {0};
7378+
int num_keys, key_len, key_free;
7379+
char *key;
73767380

7377-
if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os",
7378-
&object, redis_ce, &key, &key_len)==FAILURE)
7381+
if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz",
7382+
&object, redis_ce, &z_keys)==FAILURE)
73797383
{
73807384
RETURN_FALSE;
73817385
}
@@ -7384,17 +7388,88 @@ PHP_METHOD(Redis, pfcount) {
73847388
RETURN_FALSE;
73857389
}
73867390

7387-
// Prefix key if neccisary and construct our command
7388-
key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
7389-
cmd_len = redis_cmd_format_static(&cmd, "PFCOUNT", "s", key, key_len);
7390-
if(key_free) efree(key);
7391+
/* If we were passed an array of keys, iterate through them prefixing if
7392+
* required and capturing lengths and if we need to free them. Otherwise
7393+
* attempt to treat the argument as a string and just pass one */
7394+
if (Z_TYPE_P(z_keys) == IS_ARRAY) {
7395+
/* Grab key hash table and the number of keys */
7396+
ht_keys = Z_ARRVAL_P(z_keys);
7397+
num_keys = zend_hash_num_elements(ht_keys);
73917398

7392-
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
7399+
/* There is no reason to send zero keys */
7400+
if (num_keys == 0) {
7401+
RETURN_FALSE;
7402+
}
7403+
7404+
/* Initialize the command with our number of arguments */
7405+
redis_cmd_init_sstr(&cmd, num_keys, "PFCOUNT", sizeof("PFCOUNT")-1);
7406+
7407+
/* Append our key(s) */
7408+
for (zend_hash_internal_pointer_reset_ex(ht_keys, &ptr);
7409+
zend_hash_get_current_data_ex(ht_keys, (void**)&z_key, &ptr)==SUCCESS;
7410+
zend_hash_move_forward_ex(ht_keys, &ptr))
7411+
{
7412+
/* Turn our value into a string if it isn't one */
7413+
if (Z_TYPE_PP(z_key) != IS_STRING) {
7414+
MAKE_STD_ZVAL(z_tmp);
7415+
*z_tmp = **z_key;
7416+
zval_copy_ctor(z_tmp);
7417+
convert_to_string(z_tmp);
7418+
7419+
key = Z_STRVAL_P(z_tmp);
7420+
key_len = Z_STRLEN_P(z_tmp);
7421+
} else {
7422+
key = Z_STRVAL_PP(z_key);
7423+
key_len = Z_STRLEN_PP(z_key);
7424+
}
7425+
7426+
/* Append this key to our command */
7427+
key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
7428+
redis_cmd_append_sstr(&cmd, key, key_len);
7429+
7430+
/* Cleanup */
7431+
if (key_free) efree(key);
7432+
if (z_tmp) {
7433+
zval_dtor(z_tmp);
7434+
efree(z_tmp);
7435+
z_tmp = NULL;
7436+
}
7437+
}
7438+
} else {
7439+
/* Turn our key into a string if it's a different type */
7440+
if (Z_TYPE_P(z_keys) != IS_STRING) {
7441+
MAKE_STD_ZVAL(z_tmp);
7442+
*z_tmp = *z_keys;
7443+
zval_copy_ctor(z_tmp);
7444+
convert_to_string(z_tmp);
7445+
7446+
key = Z_STRVAL_P(z_tmp);
7447+
key_len = Z_STRLEN_P(z_tmp);
7448+
} else {
7449+
key = Z_STRVAL_P(z_keys);
7450+
key_len = Z_STRLEN_P(z_keys);
7451+
}
7452+
7453+
/* Construct our whole command */
7454+
redis_cmd_init_sstr(&cmd, 1, "PFCOUNT", sizeof("PFCOUNT")-1);
7455+
key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
7456+
redis_cmd_append_sstr(&cmd, key, key_len);
7457+
7458+
/* Cleanup */
7459+
if (key_free) efree(key);
7460+
if (z_tmp) {
7461+
zval_dtor(z_tmp);
7462+
efree(z_tmp);
7463+
}
7464+
}
7465+
7466+
REDIS_PROCESS_REQUEST(redis_sock, cmd.c, cmd.len);
73937467
IF_ATOMIC() {
73947468
redis_long_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL);
73957469
}
73967470
REDIS_PROCESS_RESPONSE(redis_long_response);
73977471
}
7472+
/* }}} */
73987473

73997474
/* {{{ proto Redis::pfMerge(array keys) }}}*/
74007475
PHP_METHOD(Redis, pfmerge) {

tests/TestRedis.php

+6
Original file line numberDiff line numberDiff line change
@@ -4910,13 +4910,19 @@ public function testPFCommands() {
49104910
$i_card = $this->redis->pfcount($str_key);
49114911
$this->assertTrue(is_int($i_card));
49124912

4913+
49134914
// Count should be close
49144915
$this->assertLess(abs($i_card-count($arr_mems)), count($arr_mems) * .1);
49154916

49164917
// The PFCOUNT on this key should be the same as the above returned response
49174918
$this->assertEquals($this->redis->pfcount($str_key), $i_card);
4919+
49184920
}
49194921

4922+
// Make sure we can pass an array of keys into pfCount
4923+
$i_card = $this->redis->pfcount($arr_keys);
4924+
$this->assertTrue(is_int($i_card));
4925+
49204926
// Clean up merge key
49214927
$this->redis->del('pf-merge-key');
49224928

0 commit comments

Comments
 (0)