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

Skip to content

Commit 3efa59c

Browse files
Refactor gen_varkey_cmd
Use the new argument parsing API which lets us avoid an allocation and switch to redis_cmd_append_sstr_key_zval to abstract away key prefixing logic.
1 parent acb5db7 commit 3efa59c

1 file changed

Lines changed: 43 additions & 102 deletions

File tree

redis_commands.c

Lines changed: 43 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,141 +1846,82 @@ int redis_vararg_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
18461846
* timeout value. This can handle various SUNION/SUNIONSTORE/BRPOP type
18471847
* commands. */
18481848
static int gen_varkey_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
1849-
char *kw, int kw_len, int min_argc, int has_timeout,
1849+
char *kw, int kw_len, int min_argc, zend_bool has_timeout,
18501850
char **cmd, int *cmd_len, short *slot)
18511851
{
1852-
zval *z_args, *z_ele, ztimeout = {0};
1853-
HashTable *ht_arr;
1854-
char *key;
1855-
int key_free, i, tail;
1856-
size_t key_len;
1857-
int single_array = 0, argc = ZEND_NUM_ARGS();
1852+
zval *argv = NULL, ztimeout = {0}, *zv;
18581853
smart_string cmdstr = {0};
18591854
short kslot = -1;
1860-
zend_string *zstr;
1855+
int single_array;
1856+
int argc = 0;
18611857

1862-
if (argc < min_argc) {
1863-
zend_wrong_param_count();
1864-
return FAILURE;
1865-
}
1858+
ZEND_PARSE_PARAMETERS_START(min_argc, -1)
1859+
Z_PARAM_VARIADIC('*', argv, argc)
1860+
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
18661861

1867-
// Allocate args
1868-
z_args = emalloc(argc * sizeof(zval));
1869-
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
1870-
efree(z_args);
1871-
return FAILURE;
1872-
}
1862+
single_array = argc == 1 + !!has_timeout && Z_TYPE(argv[0]) == IS_ARRAY;
18731863

1874-
// Handle our "single array" case
1875-
if (has_timeout == 0) {
1876-
single_array = argc==1 && Z_TYPE(z_args[0]) == IS_ARRAY;
1877-
} else {
1878-
single_array = argc==2 && Z_TYPE(z_args[0]) == IS_ARRAY &&
1879-
(Z_TYPE(z_args[1]) == IS_LONG || Z_TYPE(z_args[1]) == IS_DOUBLE);
1864+
if (has_timeout) {
18801865
if (single_array)
1881-
ZVAL_COPY_VALUE(&ztimeout, &z_args[1]);
1866+
ZVAL_COPY_VALUE(&ztimeout, &argv[1]);
1867+
else
1868+
ZVAL_COPY_VALUE(&ztimeout, &argv[argc - 1]);
1869+
1870+
if (Z_TYPE(ztimeout) != IS_LONG && Z_TYPE(ztimeout) != IS_DOUBLE) {
1871+
php_error_docref(NULL, E_WARNING, "Timeout must be a long or double");
1872+
return FAILURE;
1873+
}
18821874
}
18831875

18841876
// If we're running a single array, rework args
18851877
if (single_array) {
1886-
ht_arr = Z_ARRVAL(z_args[0]);
1887-
argc = zend_hash_num_elements(ht_arr);
1888-
if (has_timeout) argc++;
1889-
efree(z_args);
1890-
z_args = NULL;
1878+
/* Need at least one argument */
1879+
argc = zend_hash_num_elements(Z_ARRVAL(argv[0]));
1880+
if (argc == 0)
1881+
return FAILURE;
18911882

1892-
/* If the array is empty, we can simply abort */
1893-
if (argc == 0) return FAILURE;
1883+
if (has_timeout) argc++;
18941884
}
18951885

18961886
// Begin construction of our command
18971887
redis_cmd_init_sstr(&cmdstr, argc, kw, kw_len);
18981888

18991889
if (single_array) {
1900-
ZEND_HASH_FOREACH_VAL(ht_arr, z_ele) {
1901-
zstr = zval_get_string(z_ele);
1902-
key = ZSTR_VAL(zstr);
1903-
key_len = ZSTR_LEN(zstr);
1904-
key_free = redis_key_prefix(redis_sock, &key, &key_len);
1905-
1906-
// Protect against CROSSLOT errors
1890+
ZEND_HASH_FOREACH_VAL(Z_ARRVAL(argv[0]), zv) {
1891+
redis_cmd_append_sstr_key_zval(&cmdstr, zv, redis_sock, slot);
19071892
if (slot) {
1908-
if (kslot == -1) {
1909-
kslot = cluster_hash_key(key, key_len);
1910-
} else if (cluster_hash_key(key,key_len)!=kslot) {
1911-
zend_string_release(zstr);
1912-
if (key_free) efree(key);
1913-
php_error_docref(NULL, E_WARNING,
1914-
"Not all keys hash to the same slot!");
1915-
return FAILURE;
1916-
}
1893+
if (kslot != -1 && *slot != kslot)
1894+
goto cross_slot;
1895+
kslot = *slot;
19171896
}
1918-
1919-
// Append this key, free it if we prefixed
1920-
redis_cmd_append_sstr(&cmdstr, key, key_len);
1921-
zend_string_release(zstr);
1922-
if (key_free) efree(key);
19231897
} ZEND_HASH_FOREACH_END();
1924-
if (Z_TYPE(ztimeout) == IS_LONG) {
1925-
redis_cmd_append_sstr_long(&cmdstr, Z_LVAL(ztimeout));
1926-
} else if (Z_TYPE(ztimeout) == IS_DOUBLE) {
1927-
redis_cmd_append_sstr_dbl(&cmdstr, Z_DVAL(ztimeout));
1928-
}
19291898
} else {
1930-
if (has_timeout) {
1931-
zend_uchar type = Z_TYPE(z_args[argc - 1]);
1932-
if (type == IS_LONG || type == IS_DOUBLE) {
1933-
ZVAL_COPY_VALUE(&ztimeout, &z_args[argc - 1]);
1934-
} else {
1935-
php_error_docref(NULL, E_ERROR, "Timeout value must be a long or double");
1936-
efree(z_args);
1937-
return FAILURE;
1938-
}
1939-
}
1940-
tail = has_timeout ? argc-1 : argc;
1941-
for(i = 0; i < tail; i++) {
1942-
zstr = zval_get_string(&z_args[i]);
1943-
key = ZSTR_VAL(zstr);
1944-
key_len = ZSTR_LEN(zstr);
1945-
1946-
key_free = redis_key_prefix(redis_sock, &key, &key_len);
1947-
1948-
/* Protect against CROSSSLOT errors if we've got a slot */
1899+
for(uint32_t i = 0; i < argc - !!has_timeout; i++) {
1900+
redis_cmd_append_sstr_key_zval(&cmdstr, &argv[i], redis_sock, slot);
19491901
if (slot) {
1950-
if ( kslot == -1) {
1951-
kslot = cluster_hash_key(key, key_len);
1952-
} else if (cluster_hash_key(key,key_len)!=kslot) {
1953-
php_error_docref(NULL, E_WARNING,
1954-
"Not all keys hash to the same slot");
1955-
zend_string_release(zstr);
1956-
if (key_free) efree(key);
1957-
efree(z_args);
1958-
return FAILURE;
1959-
}
1902+
if (kslot != -1 && *slot != kslot)
1903+
goto cross_slot;
1904+
kslot = *slot;
19601905
}
1961-
1962-
// Append this key
1963-
redis_cmd_append_sstr(&cmdstr, key, key_len);
1964-
zend_string_release(zstr);
1965-
if (key_free) efree(key);
1966-
}
1967-
1968-
if (Z_TYPE(ztimeout) == IS_DOUBLE) {
1969-
redis_cmd_append_sstr_dbl(&cmdstr, Z_DVAL(z_args[tail]));
1970-
} else if (Z_TYPE(ztimeout) == IS_LONG) {
1971-
redis_cmd_append_sstr_long(&cmdstr, Z_LVAL(z_args[tail]));
19721906
}
1907+
}
19731908

1974-
// Cleanup args
1975-
efree(z_args);
1909+
if (Z_TYPE(ztimeout) == IS_DOUBLE) {
1910+
redis_cmd_append_sstr_dbl(&cmdstr, Z_DVAL(ztimeout));
1911+
} else if (Z_TYPE(ztimeout) == IS_LONG) {
1912+
redis_cmd_append_sstr_long(&cmdstr, Z_LVAL(ztimeout));
19761913
}
19771914

19781915
// Push out parameters
1979-
if (slot) *slot = kslot;
19801916
*cmd = cmdstr.c;
19811917
*cmd_len = cmdstr.len;
19821918

19831919
return SUCCESS;
1920+
1921+
cross_slot:
1922+
efree(cmdstr.c);
1923+
php_error_docref(NULL, E_WARNING, "Not all keys hash to the same slot!");
1924+
return FAILURE;
19841925
}
19851926

19861927
int redis_mpop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw,
@@ -2075,7 +2016,7 @@ int redis_blocking_pop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
20752016
void **ctx)
20762017
{
20772018
return gen_varkey_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, kw,
2078-
strlen(kw), 2, 2, cmd, cmd_len, slot);
2019+
strlen(kw), 2, 1, cmd, cmd_len, slot);
20792020
}
20802021

20812022
/*

0 commit comments

Comments
 (0)