8000 Merge branch 'release/2.2.3' · jrtkcoder/phpredis@f9f2dc0 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f9f2dc0

Browse files
Merge branch 'release/2.2.3'
2 parents 4c16a30 + 3e6d5b6 commit f9f2dc0

13 files changed

+350
-28
lines changed

README.markdown

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2522,7 +2522,6 @@ $redis->zAdd('key', 2, 'val2');
25222522
$redis->zAdd('key', 10, 'val10');
25232523
$redis->zRangeByScore('key', 0, 3); /* array('val0', 'val2') */
25242524
$redis->zRangeByScore('key', 0, 3, array('withscores' => TRUE); /* array('val0' => 0, 'val2' => 2) */
2525-
$redis->zRangeByScore('key', 0, 3, array('limit' => array(1, 1)); /* array('val2' => 2) */
25262525
$redis->zRangeByScore('key', 0, 3, array('limit' => array(1, 1)); /* array('val2') */
25272526
$redis->zRangeByScore('key', 0, 3, array('withscores' => TRUE, 'limit' => array(1, 1)); /* array('val2' => 2) */
25282527
~~~
@@ -2889,6 +2888,34 @@ $redis->script('exists', $script1, [$script2, $script3, ...]);
28892888
* SCRIPT KILL will return true if a script was able to be killed and false if not
28902889
* SCRIPT EXISTS will return an array with TRUE or FALSE for each passed script
28912890

2891+
### client
2892+
-----
2893+
_**Description**_: Issue the CLIENT command with various arguments.
2894+
2895+
The Redis CLIENT command can be used in four ways.
2896+
* CLIENT LIST
2897+
* CLIENT GETNAME
2898+
* CLIENT SETNAME [name]
2899+
* CLIENT KILL [ip:port]
2900+
2901+
##### *Usage*
2902+
~~~
2903+
$redis->client('list'); // Get a list of clients
2904+
$redis->client('getname'); // Get the name of the current connection
2905+
$redis->client('setname', 'somename'); // Set the name of the current connection
2906+
$redis->client('kill', <ip:port>); // Kill the process at ip:port
2907+
~~~
2908+
2909+
##### *Return value*
2910+
This will vary depending on which client command was executed.
2911+
2912+
* CLIENT LIST will return an array of arrays with client information.
2913+
* CLIENT GETNAME will return the client name or false if none has been set
2914+
* CLIENT SETNAME will return true if it can be set and false if not
2915+
* CLIENT KILL will return true if the client can be killed, and false if not
2916+
2917+
Note: phpredis will attempt to reconnect so you can actually kill your own connection
2918+
but may not notice losing it!
28922919
### getLastError
28932920
-----
28942921
_**Description**_: The last error message (if any)

common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ typedef struct {
160160
char *auth;
161161
double timeout;
162162
double read_timeout;
163+
long retry_interval;
163164
int failed;
164165
int status;
165166
int persistent;

library.c

Lines changed: 133 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC)
3838
int eof;
3939
int count = 0;
4040

41-
if (!redis_sock->stream)
41+
if (!redis_sock->stream) {
4242
return -1;
43+
}
4344

4445
eof = php_stream_eof(redis_sock->stream);
4546
for (; eof; count++) {
@@ -60,6 +61,12 @@ PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC)
6061
redis_sock->mode = ATOMIC;
6162
redis_sock->watching = 0;
6263
}
64+
// Wait for a while before trying to reconnect
65+
if (redis_sock->retry_interval) {
66+
// Random factor to avoid having several (or many) concurrent connections trying to reconnect at the same time
67+
long retry_interval = (count ? redis_sock->retry_interval : (random() % redis_sock->retry_interval));
68+
usleep(retry_interval);
69+
}
6370
redis_sock_connect(redis_sock TSRMLS_CC); /* reconnect */
6471
if(redis_sock->stream) { /* check for EOF again. */
6572
eof = php_stream_eof(redis_sock->stream);
@@ -608,6 +615,128 @@ PHPAPI void redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s
608615
}
609616
}
610617

618+
/*
619+
* Specialized handling of the CLIENT LIST output so it comes out in a simple way for PHP userland code
620+
* to handle.
621+
*/
622+
PHPAPI void redis_client_list_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab) {
623+
char *resp;
624+
int resp_len;
625+
zval *z_result, *z_sub_result;
626+
627+
// Make sure we can read a response from Redis
628+
if((resp = redis_sock_read(redis_sock, &resp_len TSRMLS_CC)) == NULL) {
629+
RETURN_FALSE;
630+
}
631+
632+
// Allocate memory for our response
633+
MAKE_STD_ZVAL(z_result);
634+
array_init(z_result);
635+
636+
// Allocate memory for one user (there should be at least one, namely us!)
637+
ALLOC_INIT_ZVAL(z_sub_result);
638+
array_init(z_sub_result);
639+
640+
// Pointers for parsing
641+
char *p = resp, *lpos = resp, *kpos = NULL, *vpos = NULL, *p2, *key, *value;
642+
643+
// Key length, done flag
644+
int klen, done = 0, is_numeric;
645+
646+
// While we've got more to parse
647+
while(!done) {
648+
// What character are we on
649+
switch(*p) {
650+
/* We're done */
651+
case '\0':
652+
done = 1;
653+
break;
654+
/* \n, ' ' mean we can pull a k/v pair */
655+
case '\n':
656+
case ' ':
657+
// Grab our value
658+
vpos = lpos;
659+
660+
// There is some communication error or Redis bug if we don't
661+
// have a key and value, but check anyway.
662+
if(kpos && vpos) {
663+
// Allocate, copy in our key
664+
key = emalloc(klen + 1);
665+
strncpy(key, kpos, klen);
666+
key[klen] = 0;
667+
668+
// Allocate, copy in our value
669+
value = emalloc(p-lpos+1);
670+
strncpy(value,lpos,p-lpos+1);
671+
value[p-lpos]=0;
672+
673+
// Treat numbers as numbers, strings as strings
674+
is_numeric = 1;
675+
for(p2 = value; *p; ++p) {
676+
if(*p < '0' || *p > '9') {
677+
is_numeric = 0;
678+
break;
679+
}
680+
}
681+
682+
// Add as a long or string, depending
683+
if(is_numeric == 1) {
684+
add_assoc_long(z_sub_result, key, atol(value));
685+
efree(value);
686+
} else {
687+
add_assoc_string(z_sub_result, key, value, 0);
688+
}
689+
690+
// If we hit a '\n', then we can add this user to our list
691+
if(*p == '\n') {
692+
// Add our user
693+
add_next_index_zval(z_result, z_sub_result);
694+
695+
// If we have another user, make another one
696+
if(*(p+1) != '\0') {
697+
ALLOC_INIT_ZVAL(z_sub_result);
698+
array_init(z_sub_result);
699+
}
700+
}
701+
702+
// Free our key
703+
efree(key);
704+
} else {
705+
// Something is wrong
706+
efree(resp);
707+
RETURN_FALSE;
708+
}
709+
710+
// Move forward
711+
lpos = p + 1;
712+
713+
break;
714+
/* We can pull the key and null terminate at our sep */
715+
case '=':
716+
// Key, key length
717+
kpos = lpos;
718+
klen = p - lpos;
719+
720+
// Move forward
721+
lpos = p + 1;
722+
723+
break;
724+
}
725+
726+
// Increment
727+
p++;
728+
}
729+
730+
// Free our respoonse
731+
efree(resp);
732+
733+
IF_MULTI_OR_PIPELINE() {
734+
add_next_index_zval(z_tab, z_result);
735+
} else {
736+
RETVAL_ZVAL(z_result, 0, 1);
737+
}
738+
}
739+
611740
PHPAPI void redis_boolean_response_impl(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx, SuccessCallback success_callback) {
612741

613742
char *response;
@@ -840,7 +969,8 @@ PHPAPI void redis_ping_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s
840969
* redis_sock_create
841970
*/
842971
PHPAPI RedisSock* redis_sock_create(char *host, int host_len, unsigned short port,
843-
double timeout, int persistent, char *persistent_id)
972+
double timeout, int persistent, char *persistent_id,
973+
long retry_interval)
844974
{
845975
RedisSock *redis_sock;
846976

@@ -850,7 +980,7 @@ PHPAPI RedisSock* redis_sock_create(char *host, int host_len, unsigned short por
850980
redis_sock->status = REDIS_SOCK_STATUS_DISCONNECTED;
851981
redis_sock->watching = 0;
852982
redis_sock->dbNumber = 0;
853-
983+
redis_sock->retry_interval = retry_interval * 1000;
854984
redis_sock->persistent = persistent;
855985

856986
if(persistent_id) {

library.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ PHPAPI void redis_string_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis
2020
PHPAPI void redis_ping_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
2121
PHPAPI void redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
2222
PHPAPI void redis_type_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
23-
PHPAPI RedisSock* redis_sock_create(char *host, int host_len, unsigned short port, double timeout, int persistent, char *persistent_id);
23+
PHPAPI RedisSock* redis_sock_create(char *host, int host_len, unsigned short port, double timeout, int persistent, char *persistent_id, long retry_interval);
2424
PHPAPI int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC);
2525
PHPAPI int redis_sock_server_open(RedisSock *redis_sock, int force_connect TSRMLS_DC);
2626
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
5959
PHPAPI int redis_read_multibulk_recursive(RedisSock *redis_sock, int elements, zval **z_ret TSRMLS_DC);
6060
PHPAPI int redis_read_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab);
6161

62+
PHPAPI void redis_client_list_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab);
6263

6364
#if ZEND_MODULE_API_NO >= 20100000
6465
#define REDIS_DOUBLE_TO_STRING(dbl_str, dbl_len, dbl) \

php_redis.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ PHP_METHOD(Redis, setOption);
181181

182182
PHP_METHOD(Redis, config);
183183

184+
PHP_METHOD(Redis, client);
185+
184186
PHP_METHOD(Redis, getHost);
185187
PHP_METHOD(Redis, getPort);
186188
PHP_METHOD(Redis, getDBNum);
@@ -254,7 +256,7 @@ extern zend_module_entry redis_module_entry;
254256

255257
#define phpext_redis_ptr redis_module_ptr
256258

257-
#define PHP_REDIS_VERSION "2.2.2"
259+
#define PHP_REDIS_VERSION "2.2.3"
258260

259261
#endif
260262

redis.c

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
| Original author: Alfonso Jimenez <yo@alfonsojimenez.com> |
1717
| Maintainer: Nicolas Favre-Felix <n.favre-felix@owlient.eu> |
1818
| Maintainer: Nasreddine Bouafif <n.bouafif@owlient.eu> |
19+
| Maintainer: Michael Grunder <michael.grunder@gmail.com |
1920
+----------------------------------------------------------------------+
2021
*/
2122

@@ -227,6 +228,7 @@ static zend_function_entry redis_functions[] = {
227228
PHP_ME(Redis, _prefix, NULL, ZEND_ACC_PUBLIC)
228229
PHP_ME(Redis, _unserialize, NULL, ZEND_ACC_PUBLIC)
229230

231+
PHP_ME(Redis, client, NULL, ZEND_ACC_PUBLIC)
230232

231233
/* options */
232234
PHP_ME(Redis, getOption, NULL, ZEND_ACC_PUBLIC)
@@ -554,7 +556,7 @@ PHP_METHOD(Redis,__destruct) {
554556
}
555557
}
556558

557-
/* {{{ proto boolean Redis::connect(string host, int port [, double timeout])
559+
/* {{{ proto boolean Redis::connect(string host, int port [, double timeout [, long retry_interval]])
558560
*/
559561
PHP_METHOD(Redis, connect)
560562
{
@@ -590,6 +592,7 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) {
590592
int host_len, id;
591593
char *host = NULL;
592594
long port = -1;
595+
long retry_interval = 0;
593596

594597
char *persistent_id = NULL;
595598
int persistent_id_len = -1;
@@ -602,9 +605,10 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) {
602605
persistent = 0;
603606
#endif
604607

605-
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|lds",
608+
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|ldsl",
606609
&object, redis_ce, &host, &host_len, &port,
607-
&timeout, &persistent_id, &persistent_id_len) == FAILURE) {
610+
&timeout, &persistent_id, &persistent_id_len,
611+
&retry_interval) == FAILURE) {
608612
return FAILURE;
609613
}
610614

@@ -613,6 +617,11 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) {
613617
return FAILURE;
614618
}
615619

620+
if (retry_interval < 0L || retry_interval > INT_MAX) {
621+
zend_throw_exception(redis_exception_ce, "Invalid retry interval", 0 TSRMLS_CC);
622+
return FAILURE;
623+
}
624+
616625
if(port == -1 && host_len && host[0] != '/') { /* not unix socket, set to default value */
617626
port = 6379;
618627
}
@@ -629,7 +638,7 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) {
629638
zend_clear_exception(TSRMLS_C); /* clear exception triggered by non-existent socket during connect(). */
630639
}
631640

632-
redis_sock = redis_sock_create(host, host_len, port, timeout, persistent, persistent_id);
641+
redis_sock = redis_sock_create(host, host_len, port, timeout, persistent, persistent_id, retry_interval);
633642

634643
if (redis_sock_server_open(redis_sock, 1 TSRMLS_CC) < 0) {
635644
redis_free_socket(redis_sock);
@@ -6456,5 +6465,56 @@ PHP_METHOD(Redis, getAuth) {
64566465
}
64576466
}
64586467

6459-
/* vim: set tabstop=4 softtabstop=4 noexpandtab shiftwidth=4: */
6468+
/*
6469+
* $redis->client('list');
6470+
* $redis->client('kill', <ip:port>);
6471+
* $redis->client('setname', <name>);
6472+
* $redis->client('getname');
6473+
*/
6474+
PHP_METHOD(Redis, client) {
6475+
zval *object;
6476+
RedisSock *redis_sock;
6477+
char *cmd, *opt=NULL, *arg=NULL;
6478+
int cmd_len, opt_len, arg_len;
6479+
6480+
// Parse our method parameters
6481+
if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|s",
6482+
&object, redis_ce, &opt, &opt_len, &arg, &arg_len) == FAILURE)
6483+
{
6484+
RETURN_FALSE;
6485+
}
6486+
6487+
// Grab our socket
6488+
if(redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) {
6489+
RETURN_FALSE;
6490+
}
6491+
6492+
// Build our CLIENT command
6493+
if(ZEND_NUM_ARGS() == 2) {
6494+
cmd_len = redis_cmd_format_static(&cmd, "CLIENT", "ss", opt, opt_len,
6495+
arg, arg_len);
6496+
} else {
6497+
cmd_len = redis_cmd_format_static(&cmd, "CLIENT", "s", opt, opt_len);
6498+
}
6499+
6500+
// Handle CLIENT LIST specifically
6501+
int is_list = !strncasecmp(opt, "list", 4);
6502+
6503+
// Execute our queue command
6504+
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
6505+
6506+
// We handle CLIENT LIST with a custom response function
6507+
if(!strncasecmp(opt, "list", 4)) {
6508+
IF_ATOMIC() {
6509+
redis_client_list_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,redis_sock,NULL);
6510+
}
6511+
REDIS_PROCESS_RESPONSE(redis_client_list_reply);
6512+
} else {
6513+
IF_ATOMIC() {
6514+
redis_read_variant_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,redis_sock,NULL);
6515+
}
6516+
REDIS_PROCESS_RESPONSE(redis_read_variant_reply);
6517+
}
6518+
}
64606519

6520+
/* vim: set tabstop=4 softtabstops=4 noexpandtab shiftwidth=4: */

0 commit comments

Comments
 (0)
0