Created
September 27, 2022 17:26
-
-
Save michael-grunder/1b1a5441b08f3990783e21bcc2051710 to your computer and use it in GitHub Desktop.
With a pointer timeout
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, *ztimeout = NULL; | |
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}; | |
short kslot = -1; | |
zend_string *zstr; | |
if (argc < min_argc) { | |
zend_wrong_param_count(); | |
return FAILURE; | |
} | |
// Allocate args | |
z_args = emalloc(argc * sizeof(zval)); | |
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) { | |
efree(z_args); | |
return FAILURE; | |
} | |
// Handle our "single array" case | |
if (has_timeout == 0) { | |
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 || Z_TYPE(z_args[1]) == IS_DOUBLE); | |
if (single_array) | |
ztimeout = &z_args[1]; | |
} | |
// If we're running a single array, rework args | |
if (single_array) { | |
ht_arr = Z_ARRVAL(z_args[0]); | |
argc = zend_hash_num_elements(ht_arr); | |
if (has_timeout) argc++; | |
efree(z_args); | |
z_args = NULL; | |
/* If the array is empty, we can simply abort */ | |
if (argc == 0) return FAILURE; | |
} | |
// Begin construction of our command | |
redis_cmd_init_sstr(&cmdstr, argc, kw, kw_len); | |
if (single_array) { | |
ZEND_HASH_FOREACH_VAL(ht_arr, z_ele) { | |
zstr = zval_get_string(z_ele); | |
key = ZSTR_VAL(zstr); | |
key_len = ZSTR_LEN(zstr); | |
key_free = redis_key_prefix(redis_sock, &key, &key_len); | |
// Protect against CROSSLOT errors | |
if (slot) { | |
if (kslot == -1) { | |
kslot = cluster_hash_key(key, key_len); | |
} else if (cluster_hash_key(key,key_len)!=kslot) { | |
zend_string_release(zstr); | |
if (key_free) efree(key); | |
php_error_docref(NULL, E_WARNING, | |
"Not all keys hash to the same slot!"); | |
return FAILURE; | |
} | |
} | |
// Append this key, free it if we prefixed | |
redis_cmd_append_sstr(&cmdstr, key, key_len); | |
zend_string_release(zstr); | |
if (key_free) efree(key); | |
} ZEND_HASH_FOREACH_END(); | |
if (ztimeout) { | |
ZEND_ASSERT(Z_TYPE_P(ztimeout) == IS_LONG || Z_TYPE_P(ztimeout) == IS_DOUBLE); | |
if (Z_TYPE_P(ztimeout) == IS_LONG) { | |
redis_cmd_append_sstr_long(&cmdstr, Z_LVAL_P(ztimeout)); | |
} else { | |
redis_cmd_append_sstr_dbl(&cmdstr, Z_DVAL_P(ztimeout)); | |
} | |
} | |
} else { | |
if (has_timeout) { | |
zend_uchar type = Z_TYPE(z_args[argc - 1]); | |
if (type == IS_LONG || type == IS_DOUBLE) { | |
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]); | |
key = ZSTR_VAL(zstr); | |
key_len = ZSTR_LEN(zstr); | |
key_free = redis_key_prefix(redis_sock, &key, &key_len); | |
/* Protect against CROSSSLOT errors if we've got a slot */ | |
if (slot) { | |
if ( kslot == -1) { | |
kslot = cluster_hash_key(key, key_len); | |
} else if (cluster_hash_key(key,key_len)!=kslot) { | |
php_error_docref(NULL, E_WARNING, | |
"Not all keys hash to the same slot"); | |
zend_string_release(zstr); | |
if (key_free) efree(key); | |
efree(z_args); | |
return FAILURE; | |
} | |
} | |
// Append this key | |
redis_cmd_append_sstr(&cmdstr, key, key_len); | |
zend_string_release(zstr); | |
if (key_free) efree(key); | |
} | |
if (ztimeout) { | |
ZEND_ASSERT(Z_TYPE_P(ztimeout) == IS_LONG || Z_TYPE_P(ztimeout) == IS_DOUBLE); | |
if (Z_TYPE_P(ztimeout) == IS_DOUBLE) { | |
redis_cmd_append_sstr_dbl(&cmdstr, Z_DVAL_P(ztimeout)); | |
} else { | |
redis_cmd_append_sstr_long(&cmdstr, Z_LVAL_P(ztimeout)); | |
} | |
} | |
// Cleanup args | |
efree(z_args); | |
} | |
// Push out parameters | |
if (slot) *slot = kslot; | |
*cmd = cmdstr.c; | |
*cmd_len = cmdstr.len; | |
return SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment