diff options
-rw-r--r-- | README.markdown | 29 | ||||
-rw-r--r-- | common.h | 1 | ||||
-rw-r--r-- | library.c | 136 | ||||
-rw-r--r-- | library.h | 3 | ||||
-rw-r--r-- | php_redis.h | 4 | ||||
-rw-r--r-- | redis.c | 70 | ||||
-rw-r--r-- | redis_array.c | 58 | ||||
-rw-r--r-- | redis_array.h | 1 | ||||
-rw-r--r-- | redis_array_impl.c | 34 | ||||
-rw-r--r-- | redis_array_impl.h | 4 | ||||
-rw-r--r-- | redis_session.c | 10 | ||||
-rw-r--r-- | rpm/php-redis.spec | 2 | ||||
-rw-r--r-- | tests/TestRedis.php | 26 |
13 files changed, 350 insertions, 28 deletions
diff --git a/README.markdown b/README.markdown index bb403d2f..0f4d9cb4 100644 --- a/README.markdown +++ b/README.markdown @@ -2522,7 +2522,6 @@ $redis->zAdd('key', 2, 'val2'); $redis->zAdd('key', 10, 'val10'); $redis->zRangeByScore('key', 0, 3); /* array('val0', 'val2') */ $redis->zRangeByScore('key', 0, 3, array('withscores' => TRUE); /* array('val0' => 0, 'val2' => 2) */ -$redis->zRangeByScore('key', 0, 3, array('limit' => array(1, 1)); /* array('val2' => 2) */ $redis->zRangeByScore('key', 0, 3, array('limit' => array(1, 1)); /* array('val2') */ $redis->zRangeByScore('key', 0, 3, array('withscores' => TRUE, 'limit' => array(1, 1)); /* array('val2' => 2) */ ~~~ @@ -2889,6 +2888,34 @@ $redis->script('exists', $script1, [$script2, $script3, ...]); * SCRIPT KILL will return true if a script was able to be killed and false if not * SCRIPT EXISTS will return an array with TRUE or FALSE for each passed script +### client +----- +_**Description**_: Issue the CLIENT command with various arguments. + +The Redis CLIENT command can be used in four ways. +* CLIENT LIST +* CLIENT GETNAME +* CLIENT SETNAME [name] +* CLIENT KILL [ip:port] + +##### *Usage* +~~~ +$redis->client('list'); // Get a list of clients +$redis->client('getname'); // Get the name of the current connection +$redis->client('setname', 'somename'); // Set the name of the current connection +$redis->client('kill', <ip:port>); // Kill the process at ip:port +~~~ + +##### *Return value* +This will vary depending on which client command was executed. + +* CLIENT LIST will return an array of arrays with client information. +* CLIENT GETNAME will return the client name or false if none has been set +* CLIENT SETNAME will return true if it can be set and false if not +* CLIENT KILL will return true if the client can be killed, and false if not + +Note: phpredis will attempt to reconnect so you can actually kill your own connection +but may not notice losing it! ### getLastError ----- _**Description**_: The last error message (if any) @@ -160,6 +160,7 @@ typedef struct { char *auth; double timeout; double read_timeout; + long retry_interval; int failed; int status; int persistent; @@ -38,8 +38,9 @@ PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC) int eof; int count = 0; - if (!redis_sock->stream) + if (!redis_sock->stream) { return -1; + } eof = php_stream_eof(redis_sock->stream); for (; eof; count++) { @@ -60,6 +61,12 @@ PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC) redis_sock->mode = ATOMIC; redis_sock->watching = 0; } + // Wait for a while before trying to reconnect + if (redis_sock->retry_interval) { + // Random factor to avoid having several (or many) concurrent connections trying to reconnect at the same time + long retry_interval = (count ? redis_sock->retry_interval : (random() % redis_sock->retry_interval)); + usleep(retry_interval); + } redis_sock_connect(redis_sock TSRMLS_CC); /* reconnect */ if(redis_sock->stream) { /* check for EOF again. */ eof = php_stream_eof(redis_sock->stream); @@ -608,6 +615,128 @@ PHPAPI void redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s } } +/* + * Specialized handling of the CLIENT LIST output so it comes out in a simple way for PHP userland code + * to handle. + */ +PHPAPI void redis_client_list_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab) { + char *resp; + int resp_len; + zval *z_result, *z_sub_result; + + // Make sure we can read a response from Redis + if((resp = redis_sock_read(redis_sock, &resp_len TSRMLS_CC)) == NULL) { + RETURN_FALSE; + } + + // Allocate memory for our response + MAKE_STD_ZVAL(z_result); + array_init(z_result); + + // Allocate memory for one user (there should be at least one, namely us!) + ALLOC_INIT_ZVAL(z_sub_result); + array_init(z_sub_result); + + // Pointers for parsing + char *p = resp, *lpos = resp, *kpos = NULL, *vpos = NULL, *p2, *key, *value; + + // Key length, done flag + int klen, done = 0, is_numeric; + + // While we've got more to parse + while(!done) { + // What character are we on + switch(*p) { + /* We're done */ + case '\0': + done = 1; + break; + /* \n, ' ' mean we can pull a k/v pair */ + case '\n': + case ' ': + // Grab our value + vpos = lpos; + + // There is some communication error or Redis bug if we don't + // have a key and value, but check anyway. + if(kpos && vpos) { + // Allocate, copy in our key + key = emalloc(klen + 1); + strncpy(key, kpos, klen); + key[klen] = 0; + + // Allocate, copy in our value + value = emalloc(p-lpos+1); + strncpy(value,lpos,p-lpos+1); + value[p-lpos]=0; + + // Treat numbers as numbers, strings as strings + is_numeric = 1; + for(p2 = value; *p; ++p) { + if(*p < '0' || *p > '9') { + is_numeric = 0; + break; + } + } + + // Add as a long or string, depending + if(is_numeric == 1) { + add_assoc_long(z_sub_result, key, atol(value)); + efree(value); + } else { + add_assoc_string(z_sub_result, key, value, 0); + } + + // If we hit a '\n', then we can add this user to our list + if(*p == '\n') { + // Add our user + add_next_index_zval(z_result, z_sub_result); + + // If we have another user, make another one + if(*(p+1) != '\0') { + ALLOC_INIT_ZVAL(z_sub_result); + array_init(z_sub_result); + } + } + + // Free our key + efree(key); + } else { + // Something is wrong + efree(resp); + RETURN_FALSE; + } + + // Move forward + lpos = p + 1; + + break; + /* We can pull the key and null terminate at our sep */ + case '=': + // Key, key length + kpos = lpos; + klen = p - lpos; + + // Move forward + lpos = p + 1; + + break; + } + + // Increment + p++; + } + + // Free our respoonse + efree(resp); + + IF_MULTI_OR_PIPELINE() { + add_next_index_zval(z_tab, z_result); + } else { + RETVAL_ZVAL(z_result, 0, 1); + } +} + PHPAPI void redis_boolean_response_impl(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx, SuccessCallback success_callback) { char *response; @@ -840,7 +969,8 @@ PHPAPI void redis_ping_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s * redis_sock_create */ PHPAPI RedisSock* redis_sock_create(char *host, int host_len, unsigned short port, - double timeout, int persistent, char *persistent_id) + double timeout, int persistent, char *persistent_id, + long retry_interval) { RedisSock *redis_sock; @@ -850,7 +980,7 @@ PHPAPI RedisSock* redis_sock_create(char *host, int host_len, unsigned short por redis_sock->status = REDIS_SOCK_STATUS_DISCONNECTED; redis_sock->watching = 0; redis_sock->dbNumber = 0; - + redis_sock->retry_interval = retry_interval * 1000; redis_sock->persistent = persistent; if(persistent_id) { @@ -20,7 +20,7 @@ PHPAPI void redis_string_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis PHPAPI void redis_ping_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHPAPI void redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHPAPI void redis_type_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); -PHPAPI RedisSock* redis_sock_create(char *host, int host_len, unsigned short port, double timeout, int persistent, char *persistent_id); +PHPAPI RedisSock* redis_sock_create(char *host, int host_len, unsigned short port, double timeout, int persistent, char *persistent_id, long retry_interval); PHPAPI int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC); PHPAPI int redis_sock_server_open(RedisSock *redis_sock, int force_connect TSRMLS_DC); PHPAPI int redis_sock_disconnect(RedisSock *redis_sock TSRMLS_DC); @@ -59,6 +59,7 @@ PHPAPI int redis_read_variant_bulk(RedisSock *redis_sock, int size, zval **z_ret PHPAPI int redis_read_multibulk_recursive(RedisSock *redis_sock, int elements, zval **z_ret TSRMLS_DC); PHPAPI int redis_read_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab); +PHPAPI void redis_client_list_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab); #if ZEND_MODULE_API_NO >= 20100000 #define REDIS_DOUBLE_TO_STRING(dbl_str, dbl_len, dbl) \ diff --git a/php_redis.h b/php_redis.h index 6ed4babe..a8f99be0 100644 --- a/php_redis.h +++ b/php_redis.h @@ -181,6 +181,8 @@ PHP_METHOD(Redis, setOption); PHP_METHOD(Redis, config); +PHP_METHOD(Redis, client); + PHP_METHOD(Redis, getHost); PHP_METHOD(Redis, getPort); PHP_METHOD(Redis, getDBNum); @@ -254,7 +256,7 @@ extern zend_module_entry redis_module_entry; #define phpext_redis_ptr redis_module_ptr -#define PHP_REDIS_VERSION "2.2.2" +#define PHP_REDIS_VERSION "2.2.3" #endif @@ -16,6 +16,7 @@ | Original author: Alfonso Jimenez <yo@alfonsojimenez.com> | | Maintainer: Nicolas Favre-Felix <n.favre-felix@owlient.eu> | | Maintainer: Nasreddine Bouafif <n.bouafif@owlient.eu> | + | Maintainer: Michael Grunder <michael.grunder@gmail.com | +----------------------------------------------------------------------+ */ @@ -227,6 +228,7 @@ static zend_function_entry redis_functions[] = { PHP_ME(Redis, _prefix, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, _unserialize, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Redis, client, NULL, ZEND_ACC_PUBLIC) /* options */ PHP_ME(Redis, getOption, NULL, ZEND_ACC_PUBLIC) @@ -554,7 +556,7 @@ PHP_METHOD(Redis,__destruct) { } } -/* {{{ proto boolean Redis::connect(string host, int port [, double timeout]) +/* {{{ proto boolean Redis::connect(string host, int port [, double timeout [, long retry_interval]]) */ PHP_METHOD(Redis, connect) { @@ -590,6 +592,7 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) { int host_len, id; char *host = NULL; long port = -1; + long retry_interval = 0; char *persistent_id = NULL; int persistent_id_len = -1; @@ -602,9 +605,10 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) { persistent = 0; #endif - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|lds", + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|ldsl", &object, redis_ce, &host, &host_len, &port, - &timeout, &persistent_id, &persistent_id_len) == FAILURE) { + &timeout, &persistent_id, &persistent_id_len, + &retry_interval) == FAILURE) { return FAILURE; } @@ -613,6 +617,11 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) { return FAILURE; } + if (retry_interval < 0L || retry_interval > INT_MAX) { + zend_throw_exception(redis_exception_ce, "Invalid retry interval", 0 TSRMLS_CC); + return FAILURE; + } + if(port == -1 && host_len && host[0] != '/') { /* not unix socket, set to default value */ port = 6379; } @@ -629,7 +638,7 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) { zend_clear_exception(TSRMLS_C); /* clear exception triggered by non-existent socket during connect(). */ } - redis_sock = redis_sock_create(host, host_len, port, timeout, persistent, persistent_id); + redis_sock = redis_sock_create(host, host_len, port, timeout, persistent, persistent_id, retry_interval); if (redis_sock_server_open(redis_sock, 1 TSRMLS_CC) < 0) { redis_free_socket(redis_sock); @@ -6456,5 +6465,56 @@ PHP_METHOD(Redis, getAuth) { } } -/* vim: set tabstop=4 softtabstop=4 noexpandtab shiftwidth=4: */ +/* + * $redis->client('list'); + * $redis->client('kill', <ip:port>); + * $redis->client('setname', <name>); + * $redis->client('getname'); + */ +PHP_METHOD(Redis, client) { + zval *object; + RedisSock *redis_sock; + char *cmd, *opt=NULL, *arg=NULL; + int cmd_len, opt_len, arg_len; + + // Parse our method parameters + if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|s", + &object, redis_ce, &opt, &opt_len, &arg, &arg_len) == FAILURE) + { + RETURN_FALSE; + } + + // Grab our socket + if(redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) { + RETURN_FALSE; + } + + // Build our CLIENT command + if(ZEND_NUM_ARGS() == 2) { + cmd_len = redis_cmd_format_static(&cmd, "CLIENT", "ss", opt, opt_len, + arg, arg_len); + } else { + cmd_len = redis_cmd_format_static(&cmd, "CLIENT", "s", opt, opt_len); + } + + // Handle CLIENT LIST specifically + int is_list = !strncasecmp(opt, "list", 4); + + // Execute our queue command + REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); + + // We handle CLIENT LIST with a custom response function + if(!strncasecmp(opt, "list", 4)) { + IF_ATOMIC() { + redis_client_list_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,redis_sock,NULL); + } + REDIS_PROCESS_RESPONSE(redis_client_list_reply); + } else { + IF_ATOMIC() { + redis_read_variant_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,redis_sock,NULL); + } + REDIS_PROCESS_RESPONSE(redis_read_variant_reply); + } +} +/* vim: set tabstop=4 softtabstops=4 noexpandtab shiftwidth=4: */ diff --git a/redis_array.c b/redis_array.c index d0460f10..9c414292 100644 --- a/redis_array.c +++ b/redis_array.c @@ -13,6 +13,7 @@ | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Nicolas Favre-Felix <n.favre-felix@owlient.eu> | + | Maintainer: Michael Grunder <michael.grunder@gmail.com> | +----------------------------------------------------------------------+ */ @@ -51,6 +52,7 @@ zend_function_entry redis_array_functions[] = { PHP_ME(RedisArray, _rehash, NULL, ZEND_ACC_PUBLIC) /* special implementation for a few functions */ + PHP_ME(RedisArray, select, NULL, ZEND_ACC_PUBLIC) PHP_ME(RedisArray, info, NULL, ZEND_ACC_PUBLIC) PHP_ME(RedisArray, ping, NULL, ZEND_ACC_PUBLIC) PHP_ME(RedisArray, mget, NULL, ZEND_ACC_PUBLIC) @@ -192,6 +194,7 @@ PHP_METHOD(RedisArray, __construct) RedisArray *ra = NULL; zend_bool b_index = 0, b_autorehash = 0; HashTable *hPrev = NULL, *hOpts = NULL; + long l_retry_interval = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|a", &z0, &z_opts) == FAILURE) { RETURN_FALSE; @@ -232,6 +235,19 @@ PHP_METHOD(RedisArray, __construct) if(FAILURE != zend_hash_find(hOpts, "autorehash", sizeof("autorehash"), (void**)&zpData) && Z_TYPE_PP(zpData) == IS_BOOL) { b_autorehash = Z_BVAL_PP(zpData); } + + /* extract retry_interval option. */ + zval **z_retry_interval_pp; + if (FAILURE != zend_hash_find(hOpts, "retry_interval", sizeof("retry_interval"), (void**)&z_retry_interval_pp)) { + if (Z_TYPE_PP(z_retry_interval_pp) == IS_LONG || Z_TYPE_PP(z_retry_interval_pp) == IS_STRING) { + if (Z_TYPE_PP(z_retry_interval_pp) == IS_LONG) { + l_retry_interval = Z_LVAL_PP(z_retry_interval_pp); + } + else { + l_retry_interval = atol(Z_STRVAL_PP(z_retry_interval_pp)); + } + } + } } /* extract either name of list of hosts from z0 */ @@ -241,7 +257,7 @@ PHP_METHOD(RedisArray, __construct) break; case IS_ARRAY: - ra = ra_make_array(Z_ARRVAL_P(z0), z_fun, z_dist, hPrev, b_index TSRMLS_CC); + ra = ra_make_array(Z_ARRVAL_P(z0), z_fun, z_dist, hPrev, b_index, l_retry_interval TSRMLS_CC); break; default: @@ -688,6 +704,46 @@ PHP_METHOD(RedisArray, setOption) efree(z_args[0]); efree(z_args[1]); } + +PHP_METHOD(RedisArray, select) +{ + zval *object, z_fun, *z_tmp, *z_args[2]; + int i; + RedisArray *ra; + long opt; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", + &object, redis_array_ce, &opt) == FAILURE) { + RETURN_FALSE; + } + + if (redis_array_get(object, &ra TSRMLS_CC) < 0) { + RETURN_FALSE; + } + + /* prepare call */ + ZVAL_STRING(&z_fun, "select", 0); + + /* copy args */ + MAKE_STD_ZVAL(z_args[0]); + ZVAL_LONG(z_args[0], opt); + + array_init(return_value); + for(i = 0; i < ra->count; ++i) { + + MAKE_STD_ZVAL(z_tmp); + + /* Call each node in turn */ + call_user_function(&redis_ce->function_table, &ra->redis[i], + &z_fun, z_tmp, 1, z_args TSRMLS_CC); + + add_assoc_zval(return_value, ra->hosts[i], z_tmp); + } + + /* cleanup */ + efree(z_args[0]); +} + #define HANDLE_MULTI_EXEC(cmd) do {\ if (redis_array_get(getThis(), &ra TSRMLS_CC) >= 0 && ra->z_multi_exec) {\ int i, num_varargs;\ diff --git a/redis_array.h b/redis_array.h index bc7fdd88..b2c7d86a 100644 --- a/redis_array.h +++ b/redis_array.h @@ -15,6 +15,7 @@ PHP_METHOD(RedisArray, _function); PHP_METHOD(RedisArray, _distributor); PHP_METHOD(RedisArray, _rehash); +PHP_METHOD(RedisArray, select); PHP_METHOD(RedisArray, info); PHP_METHOD(RedisArray, ping); PHP_METHOD(RedisArray, mget); diff --git a/redis_array_impl.c b/redis_array_impl.c index 0c361d74..bafcbd49 100644 --- a/redis_array_impl.c +++ b/redis_array_impl.c @@ -13,6 +13,7 @@ | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Nicolas Favre-Felix <n.favre-felix@owlient.eu> | + | Maintainer: Michael Grunder <michael.grunder@gmail.com> | +----------------------------------------------------------------------+ */ #include "redis_array_impl.h" @@ -29,7 +30,7 @@ extern int le_redis_sock; extern zend_class_entry *redis_ce; RedisArray* -ra_load_hosts(RedisArray *ra, HashTable *hosts TSRMLS_DC) +ra_load_hosts(RedisArray *ra, HashTable *hosts, long retry_interval TSRMLS_DC) { int i, host_len, id; int count = zend_hash_num_elements(hosts); @@ -67,7 +68,7 @@ ra_load_hosts(RedisArray *ra, HashTable *hosts TSRMLS_DC) call_user_function(&redis_ce->function_table, &ra->redis[i], &z_cons, &z_ret, 0, NULL TSRMLS_CC); /* create socket */ - redis_sock = redis_sock_create(host, host_len, port, 0, 0, NULL); /* TODO: persistence? */ + redis_sock = redis_sock_create(host, host_len, port, 0, 0, NULL, retry_interval); /* TODO: persistence? */ /* connect */ redis_sock_server_open(redis_sock, 1 TSRMLS_CC); @@ -158,9 +159,11 @@ RedisArray *ra_load_array(const char *name TSRMLS_DC) { zval *z_params_funs, **z_data_pp, *z_fun = NULL, *z_dist = NULL; zval *z_params_index; zval *z_params_autorehash; + zval *z_params_retry_interval; RedisArray *ra = NULL; zend_bool b_index = 0, b_autorehash = 0; + long l_retry_interval = 0; HashTable *hHosts = NULL, *hPrev = NULL; /* find entry */ @@ -223,8 +226,23 @@ RedisArray *ra_load_array(const char *name TSRMLS_DC) { } } + /* find retry interval option */ + MAKE_STD_ZVAL(z_params_retry_interval); + array_init(z_params_retry_interval); + sapi_module.treat_data(PARSE_STRING, estrdup(INI_STR("redis.arrays.retryinterval")), z_params_retry_interval TSRMLS_CC); + if (zend_hash_find(Z_ARRVAL_P(z_params_retry_interval), name, strlen(name) + 1, (void **) &z_data_pp) != FAILURE) { + if (Z_TYPE_PP(z_data_pp) == IS_LONG || Z_TYPE_PP(z_data_pp) == IS_STRING) { + if (Z_TYPE_PP(z_data_pp) == IS_LONG) { + l_retry_interval = Z_LVAL_PP(z_data_pp); + } + else { + l_retry_interval = atol(Z_STRVAL_PP(z_data_pp)); + } + } + } + /* create RedisArray object */ - ra = ra_make_array(hHosts, z_fun, z_dist, hPrev, b_index TSRMLS_CC); + ra = ra_make_array(hHosts, z_fun, z_dist, hPrev, b_index, l_retry_interval TSRMLS_CC); ra->auto_rehash = b_autorehash; /* cleanup */ @@ -238,12 +256,14 @@ RedisArray *ra_load_array(const char *name TSRMLS_DC) { efree(z_params_index); zval_dtor(z_params_autorehash); efree(z_params_autorehash); + zval_dtor(z_params_retry_interval); + efree(z_params_retry_interval); return ra; } RedisArray * -ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, HashTable *hosts_prev, zend_bool b_index TSRMLS_DC) { +ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, HashTable *hosts_prev, zend_bool b_index, long retry_interval TSRMLS_DC) { int count = zend_hash_num_elements(hosts); @@ -261,10 +281,10 @@ ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, HashTable *hosts_prev /* init array data structures */ ra_init_function_table(ra); - if(NULL == ra_load_hosts(ra, hosts TSRMLS_CC)) { + if(NULL == ra_load_hosts(ra, hosts, retry_interval TSRMLS_CC)) { return NULL; } - ra->prev = hosts_prev ? ra_make_array(hosts_prev, z_fun, z_dist, NULL, b_index TSRMLS_CC) : NULL; + ra->prev = hosts_prev ? ra_make_array(hosts_prev, z_fun, z_dist, NULL, b_index, retry_interval TSRMLS_CC) : NULL; /* copy function if provided */ if(z_fun) { @@ -1111,7 +1131,7 @@ static void zval_rehash_callback(zend_fcall_info *z_cb, zend_fcall_info_cache *z zval *z_host, *z_count; z_cb->retval_ptr_ptr = &z_ret; - z_cb->params = &z_args; + z_cb->params = (struct _zval_struct ***)&z_args; z_cb->param_count = 2; z_cb->no_separation = 0; diff --git a/redis_array_impl.h b/redis_array_impl.h index 0e00258c..8dd5201b 100644 --- a/redis_array_impl.h +++ b/redis_array_impl.h @@ -5,9 +5,9 @@ #include "common.h" #include "redis_array.h" -RedisArray* ra_load_hosts(RedisArray *ra, HashTable *hosts TSRMLS_DC); +RedisArray *ra_load_hosts(RedisArray *ra, HashTable *hosts, long retry_interval TSRMLS_DC); RedisArray *ra_load_array(const char *name TSRMLS_DC); -RedisArray *ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, HashTable *hosts_prev, zend_bool b_index TSRMLS_DC); +RedisArray *ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, HashTable *hosts_prev, zend_bool b_index, long retry_interval TSRMLS_DC); zval *ra_find_node_by_name(RedisArray *ra, const char *host, int host_len TSRMLS_DC); zval *ra_find_node(RedisArray *ra, const char *key, int key_len, int *out_pos TSRMLS_DC); void ra_init_function_table(RedisArray *ra); diff --git a/redis_session.c b/redis_session.c index 95d90533..4e633fc9 100644 --- a/redis_session.c +++ b/redis_session.c @@ -16,6 +16,7 @@ | Original author: Alfonso Jimenez <yo@alfonsojimenez.com> | | Maintainer: Nicolas Favre-Felix <n.favre-felix@owlient.eu> | | Maintainer: Nasreddine Bouafif <n.bouafif@owlient.eu> | + | Maintainer: Michael Grunder <michael.grunder@gmail.com> | +----------------------------------------------------------------------+ */ @@ -206,6 +207,7 @@ PS_OPEN_FUNC(redis) int persistent = 0; int database = -1; char *prefix = NULL, *auth = NULL, *persistent_id = NULL; + long retry_interval = 0; /* translate unix: into file: */ if (!strncmp(save_path+i, "unix:", sizeof("unix:")-1)) { @@ -240,7 +242,6 @@ PS_OPEN_FUNC(redis) convert_to_long_ex(param); weight = Z_LVAL_PP(param); } - if (zend_hash_find(Z_ARRVAL_P(params), "timeout", sizeof("timeout"), (void **) ¶m) != FAILURE) { timeout = atof(Z_STRVAL_PP(param)); } @@ -260,13 +261,10 @@ PS_OPEN_FUNC(redis) convert_to_long_ex(param); database = Z_LVAL_PP(param); } - - /* // not supported yet if (zend_hash_find(Z_ARRVAL_P(params), "retry_interval", sizeof("retry_interval"), (void **) ¶m) != FAILURE) { convert_to_long_ex(param); retry_interval = Z_LVAL_PP(param); } - */ zval_ptr_dtor(¶ms); } @@ -280,9 +278,9 @@ PS_OPEN_FUNC(redis) RedisSock *redis_sock; if(url->host) { - redis_sock = redis_sock_create(url->host, strlen(url->host), url->port, timeout, persistent, persistent_id); + redis_sock = redis_sock_create(url->host, strlen(url->host), url->port, timeout, persistent, persistent_id, retry_interval); } else { /* unix */ - redis_sock = redis_sock_create(url->path, strlen(url->path), 0, timeout, persistent, persistent_id); + redis_sock = redis_sock_create(url->path, strlen(url->path), 0, timeout, persistent, persistent_id, retry_interval); } redis_pool_add(pool, redis_sock, weight, database, prefix, auth TSRMLS_CC); diff --git a/rpm/php-redis.spec b/rpm/php-redis.spec index 633e3ed2..714854bc 100644 --- a/rpm/php-redis.spec +++ b/rpm/php-redis.spec @@ -3,7 +3,7 @@ %global php_version %(php-config --version 2>/dev/null || echo 0) Name: php-redis -Version: 2.2.2 +Version: 2.2.3 Release: 1%{?dist} Summary: The phpredis extension provides an API for communicating with the Redis key-value store. diff --git a/tests/TestRedis.php b/tests/TestRedis.php index db9099ba..20fdb358 100644 --- a/tests/TestRedis.php +++ b/tests/TestRedis.php @@ -1650,6 +1650,32 @@ class Redis_Test extends TestSuite $this->assertTrue(FALSE === $this->redis->persist('x')); // false if the key doesn’t exist. } + public function testClient() { + /* CLIENT SETNAME */ + $this->assertTrue($this->redis->client('setname', 'phpredis_unit_tests')); + + /* CLIENT LIST */ + $arr_clients = $this->redis->client('list'); + $this->assertTrue(is_array($arr_clients)); + + // Figure out which ip:port is us! + $str_addr = NULL; + foreach($arr_clients as $arr_client) { + if($arr_client['name'] == 'phpredis_unit_tests') { + $str_addr = $arr_client['addr']; + } + } + + // We should have found our connection + $this->assertFalse(empty($str_addr)); + + /* CLIENT GETNAME */ + $this->assertTrue($this->redis->client('getname'), 'phpredis_unit_tests'); + + /* CLIENT KILL -- phpredis will reconnect, so we can do this */ + $this->assertTrue($this->redis->client('kill', $str_addr)); + } + public function testinfo() { $info = $this->redis->info(); |