diff options
author | Emmanuel Merali <emmanuel@mobli.com> | 2013-01-21 20:10:16 +0400 |
---|---|---|
committer | Emmanuel Merali <emmanuel@mobli.com> | 2013-01-21 20:10:16 +0400 |
commit | 3fb643211e524112bd9a19792f833b12b68de600 (patch) | |
tree | 2d597d3871ff3ed51ea41dff069100fdf12d5fbc | |
parent | 07369ed1fb25f5a2e9c9040ef1b41b4dcbce0108 (diff) |
Retry delay - selectDB on array
Added the possibility to delay each reconnection attempt, including a
random factor to prevent several or many concurrent connections from
trying to reconnect at the same time.
Added the select command to RedisArray to select a DB on every
connections in one instruction.
-rw-r--r-- | common.h | 1 | ||||
-rw-r--r-- | library.c | 1496 | ||||
-rw-r--r-- | library.h | 2 | ||||
-rw-r--r-- | redis.c | 15 | ||||
-rw-r--r-- | redis_array.c | 57 | ||||
-rw-r--r-- | redis_array.h | 1 | ||||
-rw-r--r-- | redis_array_impl.c | 33 | ||||
-rw-r--r-- | redis_array_impl.h | 4 | ||||
-rw-r--r-- | redis_session.c | 9 |
9 files changed, 853 insertions, 765 deletions
@@ -156,6 +156,7 @@ typedef struct { char *host; short port; double timeout; + long retry_interval; int failed; int status; int persistent; @@ -26,76 +26,83 @@ extern zend_class_entry *redis_exception_ce; extern zend_class_entry *spl_ce_RuntimeException; PHPAPI void redis_stream_close(RedisSock *redis_sock TSRMLS_DC) { - if (!redis_sock->persistent) { - php_stream_close(redis_sock->stream); - } else { - php_stream_pclose(redis_sock->stream); - } + if (!redis_sock->persistent) { + php_stream_close(redis_sock->stream); + } else { + php_stream_pclose(redis_sock->stream); + } } PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC) { - int eof; - int count = 0; - - if (!redis_sock->stream) - return -1; - - eof = php_stream_eof(redis_sock->stream); - for (; eof; count++) { - if((MULTI == redis_sock->mode) || redis_sock->watching || count == 10) { /* too many failures */ - if(redis_sock->stream) { /* close stream if still here */ - redis_stream_close(redis_sock TSRMLS_CC); - redis_sock->stream = NULL; - redis_sock->mode = ATOMIC; - redis_sock->status = REDIS_SOCK_STATUS_FAILED; - redis_sock->watching = 0; - } - zend_throw_exception(redis_exception_ce, "Connection lost", 0 TSRMLS_CC); - return -1; - } - if(redis_sock->stream) { /* close existing stream before reconnecting */ - redis_stream_close(redis_sock TSRMLS_CC); - redis_sock->stream = NULL; - redis_sock->mode = ATOMIC; - redis_sock->watching = 0; - } - redis_sock_connect(redis_sock TSRMLS_CC); /* reconnect */ - if(redis_sock->stream) { /* check for EOF again. */ - eof = php_stream_eof(redis_sock->stream); - } + int eof; + int count = 0; + + if (!redis_sock->stream) { + return -1; + } + + eof = php_stream_eof(redis_sock->stream); + for (; eof; count++) { + if((MULTI == redis_sock->mode) || redis_sock->watching || count == 10) { /* too many failures */ + if(redis_sock->stream) { /* close stream if still here */ + redis_stream_close(redis_sock TSRMLS_CC); + redis_sock->stream = NULL; + redis_sock->mode = ATOMIC; + redis_sock->status = REDIS_SOCK_STATUS_FAILED; + redis_sock->watching = 0; + } + zend_throw_exception(redis_exception_ce, "Connection lost", 0 TSRMLS_CC); + return -1; + } + if(redis_sock->stream) { /* close existing stream before reconnecting */ + redis_stream_close(redis_sock TSRMLS_CC); + redis_sock->stream = NULL; + 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); } + } // Reselect the DB. - if (count && redis_sock->dbNumber) { - char *cmd, *response; - int cmd_len, response_len; + if (count && redis_sock->dbNumber) { + char *cmd, *response; + int cmd_len, response_len; - cmd_len = redis_cmd_format_static(&cmd, "SELECT", "d", redis_sock->dbNumber); + cmd_len = redis_cmd_format_static(&cmd, "SELECT", "d", redis_sock->dbNumber); - if (redis_sock_write(redis_sock, cmd, cmd_len TSRMLS_CC) < 0) { - efree(cmd); - return -1; - } - efree(cmd); + if (redis_sock_write(redis_sock, cmd, cmd_len TSRMLS_CC) < 0) { + efree(cmd); + return -1; + } + efree(cmd); - if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { - return -1; - } + if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { + return -1; + } - if (strncmp(response, "+OK", 3)) { - efree(response); - return -1; - } - efree(response); + if (strncmp(response, "+OK", 3)) { + efree(response); + return -1; } + efree(response); + } - return 0; + return 0; } PHPAPI zval *redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) { char inbuf[1024]; - int numElems; + int numElems; zval *z_tab; if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) { @@ -103,7 +110,7 @@ PHPAPI zval *redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAMETERS, } if(php_stream_gets(redis_sock->stream, inbuf, 1024) == NULL) { - redis_stream_close(redis_sock TSRMLS_CC); + redis_stream_close(redis_sock TSRMLS_CC); redis_sock->stream = NULL; redis_sock->status = REDIS_SOCK_STATUS_FAILED; redis_sock->mode = ATOMIC; @@ -122,7 +129,7 @@ PHPAPI zval *redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAMETERS, redis_sock_read_multibulk_reply_loop(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, numElems, 1, UNSERIALIZE_ALL); - return z_tab; + return z_tab; } /** @@ -145,13 +152,13 @@ PHPAPI char *redis_sock_read_bulk_reply(RedisSock *redis_sock, int bytes TSRMLS_ char c; int i; - reply = emalloc(bytes+1); + reply = emalloc(bytes+1); while(offset < bytes) { got = php_stream_read(redis_sock->stream, reply + offset, bytes-offset); if (got <= 0) { /* Error or EOF */ - zend_throw_exception(redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC); + zend_throw_exception(redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC); break; } offset += got; @@ -179,7 +186,7 @@ PHPAPI char *redis_sock_read(RedisSock *redis_sock, int *buf_len TSRMLS_DC) } if(php_stream_gets(redis_sock->stream, inbuf, 1024) == NULL) { - redis_stream_close(redis_sock TSRMLS_CC); + redis_stream_close(redis_sock TSRMLS_CC); redis_sock->stream = NULL; redis_sock->status = REDIS_SOCK_STATUS_FAILED; redis_sock->mode = ATOMIC; @@ -190,12 +197,12 @@ PHPAPI char *redis_sock_read(RedisSock *redis_sock, int *buf_len TSRMLS_DC) switch(inbuf[0]) { case '-': - err_len = strlen(inbuf+1) - 2; - redis_sock_set_err(redis_sock, inbuf+1, err_len); - /* stale data */ - if(memcmp(inbuf + 1, "-ERR SYNC ", 10) == 0) { - zend_throw_exception(redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC); - } + err_len = strlen(inbuf+1) - 2; + redis_sock_set_err(redis_sock, inbuf+1, err_len); + /* stale data */ + if(memcmp(inbuf + 1, "-ERR SYNC ", 10) == 0) { + zend_throw_exception(redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC); + } return NULL; case '$': @@ -212,7 +219,7 @@ PHPAPI char *redis_sock_read(RedisSock *redis_sock, int *buf_len TSRMLS_DC) case '+': case ':': - // Single Line Reply + // Single Line Reply /* :123\r\n */ *buf_len = strlen(inbuf) - 2; if(*buf_len >= 2) { @@ -223,12 +230,12 @@ PHPAPI char *redis_sock_read(RedisSock *redis_sock, int *buf_len TSRMLS_DC) } default: - zend_throw_exception_ex( - redis_exception_ce, - 0 TSRMLS_CC, - "protocol error, got '%c' as reply type byte\n", - inbuf[0] - ); + zend_throw_exception_ex( + redis_exception_ce, + 0 TSRMLS_CC, + "protocol error, got '%c' as reply type byte\n", + inbuf[0] + ); } return NULL; @@ -245,42 +252,42 @@ void add_constant_long(zend_class_entry *ce, char *name, int value) { int integer_length(int i) { - int sz = 0; - int ci = abs(i); - while (ci > 0) { - ci /= 10; - sz++; - } - if (i == 0) { /* log 0 doesn't make sense. */ - sz = 1; - } else if (i < 0) { /* allow for neg sign as well. */ - sz++; - } - return sz; + int sz = 0; + int ci = abs(i); + while (ci > 0) { + ci /= 10; + sz++; + } + if (i == 0) { /* log 0 doesn't make sense. */ + sz = 1; + } else if (i < 0) { /* allow for neg sign as well. */ + sz++; + } + return sz; } int redis_cmd_format_header(char **ret, char *keyword, int arg_count) { - // Our return buffer - smart_str buf = {0}; - - // Keyword length - int l = strlen(keyword); - - smart_str_appendc(&buf, '*'); - smart_str_append_long(&buf, arg_count + 1); - smart_str_appendl(&buf, _NL, sizeof(_NL) -1); - smart_str_appendc(&buf, '$'); - smart_str_append_long(&buf, l); - smart_str_appendl(&buf, _NL, sizeof(_NL) -1); - smart_str_appendl(&buf, keyword, l); - smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); - - // Set our return pointer - *ret = buf.c; - - // Return the length - return buf.len; + // Our return buffer + smart_str buf = {0}; + + // Keyword length + int l = strlen(keyword); + + smart_str_appendc(&buf, '*'); + smart_str_append_long(&buf, arg_count + 1); + smart_str_appendl(&buf, _NL, sizeof(_NL) -1); + smart_str_appendc(&buf, '$'); + smart_str_append_long(&buf, l); + smart_str_appendl(&buf, _NL, sizeof(_NL) -1); + smart_str_appendl(&buf, keyword, l); + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + + // Set our return pointer + *ret = buf.c; + + // Return the length + return buf.len; } int @@ -290,74 +297,74 @@ redis_cmd_format_static(char **ret, char *keyword, char *format, ...) { va_list ap; smart_str buf = {0}; int l = strlen(keyword); - char *dbl_str; - int dbl_len; - - va_start(ap, format); - - /* add header */ - smart_str_appendc(&buf, '*'); - smart_str_append_long(&buf, strlen(format) + 1); - smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); - smart_str_appendc(&buf, '$'); - smart_str_append_long(&buf, l); - smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); - smart_str_appendl(&buf, keyword, l); - smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); - - while (*p) { - smart_str_appendc(&buf, '$'); - - switch(*p) { - case 's': { - char *val = va_arg(ap, char*); - int val_len = va_arg(ap, int); - smart_str_append_long(&buf, val_len); - smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); - smart_str_appendl(&buf, val, val_len); - } - break; - - case 'f': - case 'F': { - double d = va_arg(ap, double); - REDIS_DOUBLE_TO_STRING(dbl_str, dbl_len, d) - smart_str_append_long(&buf, dbl_len); - smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); - smart_str_appendl(&buf, dbl_str, dbl_len); - efree(dbl_str); - } - break; - - case 'i': - case 'd': { - int i = va_arg(ap, int); - char tmp[32]; - int tmp_len = snprintf(tmp, sizeof(tmp), "%d", i); - smart_str_append_long(&buf, tmp_len); - smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); - smart_str_appendl(&buf, tmp, tmp_len); - } - break; - case 'l': - case 'L': { - long l = va_arg(ap, long); - char tmp[32]; - int tmp_len = snprintf(tmp, sizeof(tmp), "%ld", l); - smart_str_append_long(&buf, tmp_len); - smart_str_appendl(&buf, _NL, sizeof(_NL) -1); - smart_str_appendl(&buf, tmp, tmp_len); - } - break; - } - p++; - smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); - } - smart_str_0(&buf); - - *ret = buf.c; - - return buf.len; + char *dbl_str; + int dbl_len; + + va_start(ap, format); + + /* add header */ + smart_str_appendc(&buf, '*'); + smart_str_append_long(&buf, strlen(format) + 1); + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + smart_str_appendc(&buf, '$'); + smart_str_append_long(&buf, l); + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + smart_str_appendl(&buf, keyword, l); + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + + while (*p) { + smart_str_appendc(&buf, '$'); + + switch(*p) { + case 's': { + char *val = va_arg(ap, char*); + int val_len = va_arg(ap, int); + smart_str_append_long(&buf, val_len); + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + smart_str_appendl(&buf, val, val_len); + } + break; + + case 'f': + case 'F': { + double d = va_arg(ap, double); + REDIS_DOUBLE_TO_STRING(dbl_str, dbl_len, d) + smart_str_append_long(&buf, dbl_len); + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + smart_str_appendl(&buf, dbl_str, dbl_len); + efree(dbl_str); + } + break; + + case 'i': + case 'd': { + int i = va_arg(ap, int); + char tmp[32]; + int tmp_len = snprintf(tmp, sizeof(tmp), "%d", i); + smart_str_append_long(&buf, tmp_len); + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + smart_str_appendl(&buf, tmp, tmp_len); + } + break; + case 'l': + case 'L': { + long l = va_arg(ap, long); + char tmp[32]; + int tmp_len = snprintf(tmp, sizeof(tmp), "%ld", l); + smart_str_append_long(&buf, tmp_len); + smart_str_appendl(&buf, _NL, sizeof(_NL) -1); + smart_str_appendl(&buf, tmp, tmp_len); + } + break; + } + p++; + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + } + smart_str_0(&buf); + + *ret = buf.c; + + return buf.len; } /** @@ -368,119 +375,119 @@ redis_cmd_format_static(char **ret, char *keyword, char *format, ...) { int redis_cmd_format(char **ret, char *format, ...) { - smart_str buf = {0}; - va_list ap; - char *p = format; - char *dbl_str; - int dbl_len; - - va_start(ap, format); - - while (*p) { - if (*p == '%') { - switch (*(++p)) { - case 's': { - char *tmp = va_arg(ap, char*); - int tmp_len = va_arg(ap, int); - smart_str_appendl(&buf, tmp, tmp_len); - } - break; - - case 'F': - case 'f': { - double d = va_arg(ap, double); - REDIS_DOUBLE_TO_STRING(dbl_str, dbl_len, d) - smart_str_append_long(&buf, dbl_len); - smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); - smart_str_appendl(&buf, dbl_str, dbl_len); - efree(dbl_str); - } - break; - - case 'd': - case 'i': { - int i = va_arg(ap, int); - char tmp[32]; - int tmp_len = snprintf(tmp, sizeof(tmp), "%d", i); - smart_str_appendl(&buf, tmp, tmp_len); - } - break; - } - } else { - smart_str_appendc(&buf, *p); - } - - p++; - } - - smart_str_0(&buf); - - *ret = buf.c; - - return buf.len; + smart_str buf = {0}; + va_list ap; + char *p = format; + char *dbl_str; + int dbl_len; + + va_start(ap, format); + + while (*p) { + if (*p == '%') { + switch (*(++p)) { + case 's': { + char *tmp = va_arg(ap, char*); + int tmp_len = va_arg(ap, int); + smart_str_appendl(&buf, tmp, tmp_len); + } + break; + + case 'F': + case 'f': { + double d = va_arg(ap, double); + REDIS_DOUBLE_TO_STRING(dbl_str, dbl_len, d) + smart_str_append_long(&buf, dbl_len); + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + smart_str_appendl(&buf, dbl_str, dbl_len); + efree(dbl_str); + } + break; + + case 'd': + case 'i': { + int i = va_arg(ap, int); + char tmp[32]; + int tmp_len = snprintf(tmp, sizeof(tmp), "%d", i); + smart_str_appendl(&buf, tmp, tmp_len); + } + break; + } + } else { + smart_str_appendc(&buf, *p); + } + + p++; + } + + smart_str_0(&buf); + + *ret = buf.c; + + return buf.len; } /* * Append a command sequence to a Redis command */ int redis_cmd_append_str(char **cmd, int cmd_len, char *append, int append_len) { - // Smart string buffer - smart_str buf = {0}; + // Smart string buffer + smart_str buf = {0}; - // Append the current command to our smart_str - smart_str_appendl(&buf, *cmd, cmd_len); + // Append the current command to our smart_str + smart_str_appendl(&buf, *cmd, cmd_len); - // Append our new command sequence - smart_str_appendc(&buf, '$'); - smart_str_append_long(&buf, append_len); - smart_str_appendl(&buf, _NL, sizeof(_NL) -1); - smart_str_appendl(&buf, append, append_len); - smart_str_appendl(&buf, _NL, sizeof(_NL) -1); + // Append our new command sequence + smart_str_appendc(&buf, '$'); + smart_str_append_long(&buf, append_len); + smart_str_appendl(&buf, _NL, sizeof(_NL) -1); + smart_str_appendl(&buf, append, append_len); + smart_str_appendl(&buf, _NL, sizeof(_NL) -1); - // Free our old command - efree(*cmd); + // Free our old command + efree(*cmd); - // Set our return pointer - *cmd = buf.c; + // Set our return pointer + *cmd = buf.c; - // Return new command length - return buf.len; + // Return new command length + return buf.len; } /* * Append an integer command to a Redis command */ int redis_cmd_append_int(char **cmd, int cmd_len, int append) { - char int_buf[32]; + char int_buf[32]; - // Conver to an int, capture length - int int_len = snprintf(int_buf, sizeof(int_buf), "%d", append); + // Conver to an int, capture length + int int_len = snprintf(int_buf, sizeof(int_buf), "%d", append); - // Return the new length - return redis_cmd_append_str(cmd, cmd_len, int_buf, int_len); + // Return the new length + return redis_cmd_append_str(cmd, cmd_len, int_buf, int_len); } PHPAPI void redis_bulk_double_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { char *response; int response_len; - double ret; + double ret; if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { - IF_MULTI_OR_PIPELINE() { - add_next_index_bool(z_tab, 0); - } else { - RETURN_FALSE; - } - return; + IF_MULTI_OR_PIPELINE() { + add_next_index_bool(z_tab, 0); + } else { + RETURN_FALSE; + } + return; } ret = atof(response); efree(response); IF_MULTI_OR_PIPELINE() { - add_next_index_double(z_tab, ret); + add_next_index_double(z_tab, ret); } else { - RETURN_DOUBLE(ret); + RETURN_DOUBLE(ret); } } @@ -490,41 +497,41 @@ PHPAPI void redis_type_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s long l; if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { - IF_MULTI_OR_PIPELINE() { - add_next_index_bool(z_tab, 0); - } else { - RETURN_FALSE; - } + IF_MULTI_OR_PIPELINE() { + add_next_index_bool(z_tab, 0); + } else { + RETURN_FALSE; + } } if (strncmp(response, "+string", 7) == 0) { - l = REDIS_STRING; + l = REDIS_STRING; } else if (strncmp(response, "+set", 4) == 0){ - l = REDIS_SET; + l = REDIS_SET; } else if (strncmp(response, "+list", 5) == 0){ - l = REDIS_LIST; + l = REDIS_LIST; } else if (strncmp(response, "+zset", 5) == 0){ - l = REDIS_ZSET; + l = REDIS_ZSET; } else if (strncmp(response, "+hash", 5) == 0){ - l = REDIS_HASH; + l = REDIS_HASH; } else { - l = REDIS_NOT_FOUND; + l = REDIS_NOT_FOUND; } efree(response); IF_MULTI_OR_PIPELINE() { - add_next_index_long(z_tab, l); + add_next_index_long(z_tab, l); } else { - RETURN_LONG(l); + RETURN_LONG(l); } } PHPAPI void redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { char *response; int response_len; - char *pos, *cur; - char *key, *value, *p; - int is_numeric; + char *pos, *cur; + char *key, *value, *p; + int is_numeric; zval *z_multi_result; if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { @@ -540,13 +547,13 @@ PHPAPI void redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s cur = response; while(1) { - /* skip comments and empty lines */ - if(*cur == '#' || *cur == '\r') { - if(!(cur = strchr(cur, '\n'))) - break; - cur++; - continue; - } + /* skip comments and empty lines */ + if(*cur == '#' || *cur == '\r') { + if(!(cur = strchr(cur, '\n'))) + break; + cur++; + continue; + } /* key */ pos = strchr(cur, ':'); @@ -601,10 +608,10 @@ PHPAPI void redis_boolean_response_impl(INTERNAL_FUNCTION_PARAMETERS, RedisSock char ret; if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { - IF_MULTI_OR_PIPELINE() { + IF_MULTI_OR_PIPELINE() { add_next_index_bool(z_tab, 0); - return; - } + return; + } RETURN_FALSE; } ret = response[0]; @@ -620,15 +627,15 @@ PHPAPI void redis_boolean_response_impl(INTERNAL_FUNCTION_PARAMETERS, RedisSock add_next_index_bool(z_tab, 0); } } else { - if (ret == '+') { + if (ret == '+') { if (success_callback != NULL) { success_callback(redis_sock); } - RETURN_TRUE; - } else { - RETURN_FALSE; - } - } + RETURN_TRUE; + } else { + RETURN_FALSE; + } + } } PHPAPI void redis_boolean_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { @@ -641,38 +648,38 @@ PHPAPI void redis_long_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s int response_len; if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { - IF_MULTI_OR_PIPELINE() { - add_next_index_bool(z_tab, 0); - return; - } else { - RETURN_FALSE; - } + IF_MULTI_OR_PIPELINE() { + add_next_index_bool(z_tab, 0); + return; + } else { + RETURN_FALSE; + } } if(response[0] == ':') { long long ret = atoll(response + 1); IF_MULTI_OR_PIPELINE() { - if(ret > LONG_MAX) { /* overflow */ - add_next_index_stringl(z_tab, response+1, response_len-1, 1); - } else { - efree(response); - add_next_index_long(z_tab, (long)ret); - } + if(ret > LONG_MAX) { /* overflow */ + add_next_index_stringl(z_tab, response+1, response_len-1, 1); + } else { + efree(response); + add_next_index_long(z_tab, (long)ret); + } } else { - if(ret > LONG_MAX) { /* overflow */ - RETURN_STRINGL(response+1, response_len-1, 1); - } else { - efree(response); - RETURN_LONG((long)ret); - } - } + if(ret > LONG_MAX) { /* overflow */ + RETURN_STRINGL(response+1, response_len-1, 1); + } else { + efree(response); + RETURN_LONG((long)ret); + } + } } else { efree(response); IF_MULTI_OR_PIPELINE() { add_next_index_null(z_tab); } else { - RETURN_FALSE; - } + RETURN_FALSE; + } } } @@ -680,20 +687,20 @@ PHPAPI void redis_long_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s PHPAPI int redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, int flag) { - /* - int ret = redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab TSRMLS_CC); - array_zip_values_and_scores(return_value, 0); - */ + /* + int ret = redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab TSRMLS_CC); + array_zip_values_and_scores(return_value, 0); + */ char inbuf[1024]; - int numElems; + int numElems; zval *z_multi_result; if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) { return -1; } if(php_stream_gets(redis_sock->stream, inbuf, 1024) == NULL) { - redis_stream_close(redis_sock TSRMLS_CC); + redis_stream_close(redis_sock TSRMLS_CC); redis_sock->stream = NULL; redis_sock->status = REDIS_SOCK_STATUS_FAILED; redis_sock->mode = ATOMIC; @@ -717,10 +724,10 @@ PHPAPI int redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNCTION_PA IF_MULTI_OR_PIPELINE() { add_next_index_zval(z_tab, z_multi_result); } else { - *return_value = *z_multi_result; - zval_copy_ctor(return_value); - zval_dtor(z_multi_result); - efree(z_multi_result); + *return_value = *z_multi_result; + zval_copy_ctor(return_value); + zval_dtor(z_multi_result); + efree(z_multi_result); } return 0; @@ -728,43 +735,43 @@ PHPAPI int redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNCTION_PA PHPAPI int redis_sock_read_multibulk_reply_zipped(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { - return redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, 1); + return redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, 1); } PHPAPI int redis_sock_read_multibulk_reply_zipped_strings(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { - return redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, 0); + return redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, 0); } PHPAPI void redis_1_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { - char *response; - int response_len; - char ret; - - if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { - IF_MULTI_OR_PIPELINE() { - add_next_index_bool(z_tab, 0); - return; - } else { - RETURN_FALSE; - } - } - ret = response[1]; - efree(response); - - IF_MULTI_OR_PIPELINE() { - if(ret == '1') { - add_next_index_bool(z_tab, 1); - } else { - add_next_index_bool(z_tab, 0); - } - } else { - if (ret == '1') { - RETURN_TRUE; - } else { - RETURN_FALSE; - } - } + char *response; + int response_len; + char ret; + + if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { + IF_MULTI_OR_PIPELINE() { + add_next_index_bool(z_tab, 0); + return; + } else { + RETURN_FALSE; + } + } + ret = response[1]; + efree(response); + + IF_MULTI_OR_PIPELINE() { + if(ret == '1') { + add_next_index_bool(z_tab, 1); + } else { + add_next_index_bool(z_tab, 0); + } + } else { + if (ret == '1') { + RETURN_TRUE; + } else { + RETURN_FALSE; + } + } } PHPAPI void redis_string_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { @@ -775,25 +782,25 @@ PHPAPI void redis_string_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { IF_MULTI_OR_PIPELINE() { add_next_index_bool(z_tab, 0); - return; + return; } RETURN_FALSE; } IF_MULTI_OR_PIPELINE() { - zval *z = NULL; - if(redis_unserialize(redis_sock, response, response_len, &z TSRMLS_CC) == 1) { - efree(response); - add_next_index_zval(z_tab, z); - } else { - add_next_index_stringl(z_tab, response, response_len, 0); - } + zval *z = NULL; + if(redis_unserialize(redis_sock, response, response_len, &z TSRMLS_CC) == 1) { + efree(response); + add_next_index_zval(z_tab, z); + } else { + add_next_index_stringl(z_tab, response, response_len, 0); + } } else { - if(redis_unserialize(redis_sock, response, response_len, &return_value TSRMLS_CC) == 0) { - RETURN_STRINGL(response, response_len, 0); - } else { - efree(response); - } - } + if(redis_unserialize(redis_sock, response, response_len, &return_value TSRMLS_CC) == 0) { + RETURN_STRINGL(response, response_len, 0); + } else { + efree(response); + } + } } /* like string response, but never unserialized. */ @@ -805,15 +812,15 @@ PHPAPI void redis_ping_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { IF_MULTI_OR_PIPELINE() { add_next_index_bool(z_tab, 0); - return; + return; } RETURN_FALSE; } IF_MULTI_OR_PIPELINE() { - add_next_index_stringl(z_tab, response, response_len, 0); + add_next_index_stringl(z_tab, response, response_len, 0); } else { - RETURN_STRINGL(response, response_len, 0); - } + RETURN_STRINGL(response, response_len, 0); + } } @@ -821,7 +828,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; @@ -831,11 +839,11 @@ 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) { - size_t persistent_id_len = strlen(persistent_id); + size_t persistent_id_len = strlen(persistent_id); redis_sock->persistent_id = ecalloc(persistent_id_len + 1, 1); memcpy(redis_sock->persistent_id, persistent_id, persistent_id_len); } else { @@ -869,8 +877,8 @@ PHPAPI int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC) struct timeval tv, *tv_ptr = NULL; char *host = NULL, *persistent_id = NULL, *errstr = NULL; int host_len, err = 0; - php_netstream_data_t *sock; - int tcp_flag = 1; + php_netstream_data_t *sock; + int tcp_flag = 1; if (redis_sock->stream != NULL) { redis_sock_disconnect(redis_sock TSRMLS_CC); @@ -879,15 +887,15 @@ PHPAPI int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC) tv.tv_sec = (time_t)redis_sock->timeout; tv.tv_usec = (int)((redis_sock->timeout - tv.tv_sec) * 1000000); if(tv.tv_sec != 0 || tv.tv_usec != 0) { - tv_ptr = &tv; + tv_ptr = &tv; } if(redis_sock->host[0] == '/' && redis_sock->port < 1) { - host_len = spprintf(&host, 0, "unix://%s", redis_sock->host); + host_len = spprintf(&host, 0, "unix://%s", redis_sock->host); } else { - if(redis_sock->port == 0) - redis_sock->port = 6379; - host_len = spprintf(&host, 0, "%s:%d", redis_sock->host, redis_sock->port); + if(redis_sock->port == 0) + redis_sock->port = 6379; + host_len = spprintf(&host, 0, "%s:%d", redis_sock->host, redis_sock->port); } if (redis_sock->persistent) { @@ -899,10 +907,10 @@ PHPAPI int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC) } redis_sock->stream = php_stream_xport_create(host, host_len, ENFORCE_SAFE_MODE, - STREAM_XPORT_CLIENT - | STREAM_XPORT_CONNECT, - persistent_id, tv_ptr, NULL, &errstr, &err - ); + STREAM_XPORT_CLIENT + | STREAM_XPORT_CONNECT, + persistent_id, tv_ptr, NULL, &errstr, &err + ); if (persistent_id) { efree(persistent_id); @@ -916,7 +924,7 @@ PHPAPI int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC) } /* set TCP_NODELAY */ - sock = (php_netstream_data_t*)redis_sock->stream->abstract; + sock = (php_netstream_data_t*)redis_sock->stream->abstract; setsockopt(sock->socket, IPPROTO_TCP, TCP_NODELAY, (char *) &tcp_flag, sizeof(int)); php_stream_auto_cleanup(redis_sock->stream); @@ -967,23 +975,23 @@ PHPAPI int redis_sock_server_open(RedisSock *redis_sock, int force_connect TSRML PHPAPI int redis_sock_disconnect(RedisSock *redis_sock TSRMLS_DC) { if (redis_sock == NULL) { - return 1; + return 1; } redis_sock->dbNumber = 0; if (redis_sock->stream != NULL) { - if (!redis_sock->persistent) { - redis_sock_write(redis_sock, "QUIT", sizeof("QUIT") - 1 TSRMLS_CC); - } + if (!redis_sock->persistent) { + redis_sock_write(redis_sock, "QUIT", sizeof("QUIT") - 1 TSRMLS_CC); + } - redis_sock->status = REDIS_SOCK_STATUS_DISCONNECTED; + redis_sock->status = REDIS_SOCK_STATUS_DISCONNECTED; redis_sock->watching = 0; - if(redis_sock->stream && !redis_sock->persistent) { /* still valid after the write? */ - php_stream_close(redis_sock->stream); - } - redis_sock->stream = NULL; + if(redis_sock->stream && !redis_sock->persistent) { /* still valid after the write? */ + php_stream_close(redis_sock->stream); + } + redis_sock->stream = NULL; - return 1; + return 1; } return 0; @@ -992,8 +1000,8 @@ PHPAPI int redis_sock_disconnect(RedisSock *redis_sock TSRMLS_DC) PHPAPI void redis_send_discard(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) { char *cmd; - int response_len, cmd_len; - char * response; + int response_len, cmd_len; + char * response; cmd_len = redis_cmd_format_static(&cmd, "DISCARD", ""); @@ -1007,41 +1015,41 @@ PHPAPI void redis_send_discard(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_so RETURN_FALSE; } - if(response_len == 3 && strncmp(response, "+OK", 3) == 0) { - RETURN_TRUE; - } - RETURN_FALSE; + if(response_len == 3 && strncmp(response, "+OK", 3) == 0) { + RETURN_TRUE; + } + RETURN_FALSE; } /** * redis_sock_set_err */ PHPAPI int redis_sock_set_err(RedisSock *redis_sock, const char *msg, int msg_len) { - // Allocate/Reallocate our last error member - if(msg != NULL && msg_len > 0) { - if(redis_sock->err == NULL) { - redis_sock->err = emalloc(msg_len + 1); - } else if(msg_len > redis_sock->err_len) { - redis_sock->err = erealloc(redis_sock->err, msg_len +1); - } - - // Copy in our new error message, set new length, and null terminate - memcpy(redis_sock->err, msg, msg_len); - redis_sock->err[msg_len] = '\0'; - redis_sock->err_len = msg_len; - } else { - // Free our last error - if(redis_sock->err != NULL) { - efree(redis_sock->err); - } - - // Set to null, with zero length - redis_sock->err = NULL; - redis_sock->err_len = 0; - } - - // Success - return 0; + // Allocate/Reallocate our last error member + if(msg != NULL && msg_len > 0) { + if(redis_sock->err == NULL) { + redis_sock->err = emalloc(msg_len + 1); + } else if(msg_len > redis_sock->err_len) { + redis_sock->err = erealloc(redis_sock->err, msg_len +1); + } + + // Copy in our new error message, set new length, and null terminate + memcpy(redis_sock->err, msg, msg_len); + redis_sock->err[msg_len] = '\0'; + redis_sock->err_len = msg_len; + } else { + // Free our last error + if(redis_sock->err != NULL) { + efree(redis_sock->err); + } + + // Set to null, with zero length + redis_sock->err = NULL; + redis_sock->err_len = 0; + } + + // Success + return 0; } /** @@ -1050,14 +1058,14 @@ PHPAPI int redis_sock_set_err(RedisSock *redis_sock, const char *msg, int msg_le PHPAPI int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { char inbuf[1024]; - int numElems; + int numElems; zval *z_multi_result; if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) { return -1; } if(php_stream_gets(redis_sock->stream, inbuf, 1024) == NULL) { - redis_stream_close(redis_sock TSRMLS_CC); + redis_stream_close(redis_sock TSRMLS_CC); redis_sock->stream = NULL; redis_sock->status = REDIS_SOCK_STATUS_FAILED; redis_sock->mode = ATOMIC; @@ -1092,14 +1100,14 @@ PHPAPI int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSo PHPAPI int redis_sock_read_multibulk_reply_raw(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { char inbuf[1024]; - int numElems; + int numElems; zval *z_multi_result; if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) { return -1; } if(php_stream_gets(redis_sock->stream, inbuf, 1024) == NULL) { - redis_stream_close(redis_sock TSRMLS_CC); + redis_stream_close(redis_sock TSRMLS_CC); redis_sock->stream = NULL; redis_sock->status = REDIS_SOCK_STATUS_FAILED; redis_sock->mode = ATOMIC; @@ -1138,17 +1146,17 @@ redis_sock_read_multibulk_reply_loop(INTERNAL_FUNCTION_PARAMETERS, RedisSock *re while(numElems > 0) { response = redis_sock_read(redis_sock, &response_len TSRMLS_CC); if(response != NULL) { - zval *z = NULL; - int can_unserialize = unwrap_key; - if(unserialize_even_only == UNSERIALIZE_ONLY_VALUES && numElems % 2 == 0) - can_unserialize = 0; - - if(can_unserialize && redis_unserialize(redis_sock, response, response_len, &z TSRMLS_CC) == 1) { - efree(response); - add_next_index_zval(z_tab, z); - } else { - add_next_index_stringl(z_tab, response, response_len, 0); - } + zval *z = NULL; + int can_unserialize = unwrap_key; + if(unserialize_even_only == UNSERIALIZE_ONLY_VALUES && numElems % 2 == 0) + can_unserialize = 0; + + if(can_unserialize && redis_unserialize(redis_sock, response, response_len, &z TSRMLS_CC) == 1) { + efree(response); + add_next_index_zval(z_tab, z); + } else { + add_next_index_stringl(z_tab, response, response_len, 0); + } } else { add_next_index_bool(z_tab, 0); } @@ -1164,8 +1172,8 @@ PHPAPI int redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, R { char inbuf[1024], *response; int response_len; - int i, numElems; - zval *z_multi_result; + int i, numElems; + zval *z_multi_result; zval **z_keys = ctx; @@ -1173,7 +1181,7 @@ PHPAPI int redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, R return -1; } if(php_stream_gets(redis_sock->stream, inbuf, 1024) == NULL) { - redis_stream_close(redis_sock TSRMLS_CC); + redis_stream_close(redis_sock TSRMLS_CC); redis_sock->stream = NULL; redis_sock->status = REDIS_SOCK_STATUS_FAILED; redis_sock->mode = ATOMIC; @@ -1192,30 +1200,30 @@ PHPAPI int redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, R for(i = 0; i < numElems; ++i) { response = redis_sock_read(redis_sock, &response_len TSRMLS_CC); if(response != NULL) { - zval *z = NULL; - if(redis_unserialize(redis_sock, response, response_len, &z TSRMLS_CC) == 1) { - efree(response); - add_assoc_zval_ex(z_multi_result, Z_STRVAL_P(z_keys[i]), 1+Z_STRLEN_P(z_keys[i]), z); - } else { - add_assoc_stringl_ex(z_multi_result, Z_STRVAL_P(z_keys[i]), 1+Z_STRLEN_P(z_keys[i]), response, response_len, 0); - } - } else { - add_assoc_bool_ex(z_multi_result, Z_STRVAL_P(z_keys[i]), 1+Z_STRLEN_P(z_keys[i]), 0); - } - zval_dtor(z_keys[i]); - efree(z_keys[i]); + zval *z = NULL; + if(redis_unserialize(redis_sock, response, response_len, &z TSRMLS_CC) == 1) { + efree(response); + add_assoc_zval_ex(z_multi_result, Z_STRVAL_P(z_keys[i]), 1+Z_STRLEN_P(z_keys[i]), z); + } else { + add_assoc_stringl_ex(z_multi_result, Z_STRVAL_P(z_keys[i]), 1+Z_STRLEN_P(z_keys[i]), response, response_len, 0); + } + } else { + add_assoc_bool_ex(z_multi_result, Z_STRVAL_P(z_keys[i]), 1+Z_STRLEN_P(z_keys[i]), 0); + } + zval_dtor(z_keys[i]); + efree(z_keys[i]); } efree(z_keys); IF_MULTI_OR_PIPELINE() { add_next_index_zval(z_tab, z_multi_result); } else { - *return_value = *z_multi_result; - zval_copy_ctor(return_value); - INIT_PZVAL(return_value); - zval_dtor(z_multi_result); - efree(z_multi_result); - } + *return_value = *z_multi_result; + zval_copy_ctor(return_value); + INIT_PZVAL(return_value); + zval_dtor(z_multi_result); + efree(z_multi_result); + } return 0; } @@ -1224,10 +1232,10 @@ PHPAPI int redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, R */ PHPAPI int redis_sock_write(RedisSock *redis_sock, char *cmd, size_t sz TSRMLS_DC) { - if(redis_sock && redis_sock->status == REDIS_SOCK_STATUS_DISCONNECTED) { - zend_throw_exception(redis_exception_ce, "Connection closed", 0 TSRMLS_CC); - return -1; - } + if(redis_sock && redis_sock->status == REDIS_SOCK_STATUS_DISCONNECTED) { + zend_throw_exception(redis_exception_ce, "Connection closed", 0 TSRMLS_CC); + return -1; + } if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) { return -1; } @@ -1240,10 +1248,10 @@ PHPAPI int redis_sock_write(RedisSock *redis_sock, char *cmd, size_t sz TSRMLS_D PHPAPI void redis_free_socket(RedisSock *redis_sock) { if(redis_sock->prefix) { - efree(redis_sock->prefix); - } + efree(redis_sock->prefix); + } if(redis_sock->err) { - efree(redis_sock->err); + efree(redis_sock->err); } efree(redis_sock->host); efree(redis_sock); @@ -1252,146 +1260,146 @@ PHPAPI void redis_free_socket(RedisSock *redis_sock) PHPAPI int redis_serialize(RedisSock *redis_sock, zval *z, char **val, int *val_len TSRMLS_DC) { #if ZEND_MODULE_API_NO >= 20100000 - php_serialize_data_t ht; + php_serialize_data_t ht; #else - HashTable ht; + HashTable ht; #endif - smart_str sstr = {0}; - zval *z_copy; - size_t sz; - uint8_t *val8; - - switch(redis_sock->serializer) { - case REDIS_SERIALIZER_NONE: - switch(Z_TYPE_P(z)) { - - case IS_STRING: - *val = Z_STRVAL_P(z); - *val_len = Z_STRLEN_P(z); - return 0; - - case IS_OBJECT: - MAKE_STD_ZVAL(z_copy); - ZVAL_STRINGL(z_copy, "Object", 6, 1); - break; - - case IS_ARRAY: - MAKE_STD_ZVAL(z_copy); - ZVAL_STRINGL(z_copy, "Array", 5, 1); - break; - - default: /* copy */ - MAKE_STD_ZVAL(z_copy); - *z_copy = *z; - zval_copy_ctor(z_copy); - break; - } - - /* return string */ - convert_to_string(z_copy); - *val = Z_STRVAL_P(z_copy); - *val_len = Z_STRLEN_P(z_copy); - efree(z_copy); - return 1; - - case REDIS_SERIALIZER_PHP: + smart_str sstr = {0}; + zval *z_copy; + size_t sz; + uint8_t *val8; + + switch(redis_sock->serializer) { + case REDIS_SERIALIZER_NONE: + switch(Z_TYPE_P(z)) { + + case IS_STRING: + *val = Z_STRVAL_P(z); + *val_len = Z_STRLEN_P(z); + return 0; + + case IS_OBJECT: + MAKE_STD_ZVAL(z_copy); + ZVAL_STRINGL(z_copy, "Object", 6, 1); + break; + + case IS_ARRAY: + MAKE_STD_ZVAL(z_copy); + ZVAL_STRINGL(z_copy, "Array", 5, 1); + break; + + default: /* copy */ + MAKE_STD_ZVAL(z_copy); + *z_copy = *z; + zval_copy_ctor(z_copy); + break; + } + + /* return string */ + convert_to_string(z_copy); + *val = Z_STRVAL_P(z_copy); + *val_len = Z_STRLEN_P(z_copy); + efree(z_copy); + return 1; + + case REDIS_SERIALIZER_PHP: #if ZEND_MODULE_API_NO >= 20100000 - PHP_VAR_SERIALIZE_INIT(ht); + PHP_VAR_SERIALIZE_INIT(ht); #else - zend_hash_init(&ht, 10, NULL, NULL, 0); + zend_hash_init(&ht, 10, NULL, NULL, 0); #endif - php_var_serialize(&sstr, &z, &ht TSRMLS_CC); - *val = sstr.c; - *val_len = (int)sstr.len; + php_var_serialize(&sstr, &z, &ht TSRMLS_CC); + *val = sstr.c; + *val_len = (int)sstr.len; #if ZEND_MODULE_API_NO >= 20100000 - PHP_VAR_SERIALIZE_DESTROY(ht); + PHP_VAR_SERIALIZE_DESTROY(ht); #else - zend_hash_destroy(&ht); + zend_hash_destroy(&ht); #endif - return 1; + return 1; - case REDIS_SERIALIZER_IGBINARY: + case REDIS_SERIALIZER_IGBINARY: #ifdef HAVE_REDIS_IGBINARY - if(igbinary_serialize(&val8, (size_t *)&sz, z TSRMLS_CC) == 0) { /* ok */ - *val = (char*)val8; - *val_len = (int)sz; - return 1; - } + if(igbinary_serialize(&val8, (size_t *)&sz, z TSRMLS_CC) == 0) { /* ok */ + *val = (char*)val8; + *val_len = (int)sz; + return 1; + } #endif - return 0; - } - return 0; + return 0; + } + return 0; } PHPAPI int redis_unserialize(RedisSock *redis_sock, const char *val, int val_len, zval **return_value TSRMLS_DC) { - php_unserialize_data_t var_hash; - int ret; + php_unserialize_data_t var_hash; + int ret; - switch(redis_sock->serializer) { - case REDIS_SERIALIZER_NONE: - return 0; + switch(redis_sock->serializer) { + case REDIS_SERIALIZER_NONE: + return 0; - case REDIS_SERIALIZER_PHP: - if(!*return_value) { - MAKE_STD_ZVAL(*return_value); - } + case REDIS_SERIALIZER_PHP: + if(!*return_value) { + MAKE_STD_ZVAL(*return_value); + } #if ZEND_MODULE_API_NO >= 20100000 - PHP_VAR_UNSERIALIZE_INIT(var_hash); + PHP_VAR_UNSERIALIZE_INIT(var_hash); #else - memset(&var_hash, 0, sizeof(var_hash)); + memset(&var_hash, 0, sizeof(var_hash)); #endif - if(!php_var_unserialize(return_value, (const unsigned char**)&val, - (const unsigned char*)val + val_len, &var_hash TSRMLS_CC)) { - efree(*return_value); - ret = 0; - } else { - ret = 1; - } + if(!php_var_unserialize(return_value, (const unsigned char**)&val, + (const unsigned char*)val + val_len, &var_hash TSRMLS_CC)) { + efree(*return_value); + ret = 0; + } else { + ret = 1; + } #if ZEND_MODULE_API_NO >= 20100000 - PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); #else - var_destroy(&var_hash); + var_destroy(&var_hash); #endif - return ret; + return ret; - case REDIS_SERIALIZER_IGBINARY: + case REDIS_SERIALIZER_IGBINARY: #ifdef HAVE_REDIS_IGBINARY - if(!*return_value) { - MAKE_STD_ZVAL(*return_value); - } - if(igbinary_unserialize((const uint8_t *)val, (size_t)val_len, return_value TSRMLS_CC) == 0) { - return 1; - } - efree(*return_value); + if(!*return_value) { + MAKE_STD_ZVAL(*return_value); + } + if(igbinary_unserialize((const uint8_t *)val, (size_t)val_len, return_value TSRMLS_CC) == 0) { + return 1; + } + efree(*return_value); #endif - return 0; - break; - } - return 0; + return 0; + break; + } + return 0; } PHPAPI int redis_key_prefix(RedisSock *redis_sock, char **key, int *key_len TSRMLS_DC) { - int ret_len; - char *ret; - - if(redis_sock->prefix == NULL || redis_sock->prefix_len == 0) { - return 0; - } - - ret_len = redis_sock->prefix_len + *key_len; - ret = ecalloc(1 + ret_len, 1); - memcpy(ret, redis_sock->prefix, redis_sock->prefix_len); - memcpy(ret + redis_sock->prefix_len, *key, *key_len); - - *key = ret; - *key_len = ret_len; - return 1; + int ret_len; + char *ret; + + if(redis_sock->prefix == NULL || redis_sock->prefix_len == 0) { + return 0; + } + + ret_len = redis_sock->prefix_len + *key_len; + ret = ecalloc(1 + ret_len, 1); + memcpy(ret, redis_sock->prefix, redis_sock->prefix_len); + memcpy(ret + redis_sock->prefix_len, *key, *key_len); + + *key = ret; + *key_len = ret_len; + return 1; } /* @@ -1401,60 +1409,60 @@ redis_key_prefix(RedisSock *redis_sock, char **key, int *key_len TSRMLS_DC) { PHPAPI int redis_sock_gets(RedisSock *redis_sock, char *buf, int buf_size, size_t *line_size TSRMLS_DC) { // Handle EOF - if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) { + if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) { return -1; } - if(php_stream_get_line(redis_sock->stream, buf, buf_size, line_size) == NULL) { - // Close, put our socket state into error - redis_stream_close(redis_sock TSRMLS_CC); - redis_sock->stream = NULL; - redis_sock->status = REDIS_SOCK_STATUS_FAILED; - redis_sock->mode = ATOMIC; - redis_sock->watching = 0; + if(php_stream_get_line(redis_sock->stream, buf, buf_size, line_size) == NULL) { + // Close, put our socket state into error + redis_stream_close(redis_sock TSRMLS_CC); + redis_sock->stream = NULL; + redis_sock->status = REDIS_SOCK_STATUS_FAILED; + redis_sock->mode = ATOMIC; + redis_sock->watching = 0; - // Throw a read error exception - zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC); - } + // Throw a read error exception + zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC); + } - // We don't need \r\n - *line_size-=2; - buf[*line_size]='\0'; + // We don't need \r\n + *line_size-=2; + buf[*line_size]='\0'; - // Success! - return 0; + // Success! + return 0; } PHPAPI int redis_read_reply_type(RedisSock *redis_sock, REDIS_REPLY_TYPE *reply_type, int *reply_info TSRMLS_DC) { - // Make sure we haven't lost the connection, even trying to reconnect - if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) { - // Failure - return -1; - } - - // Attempt to read the reply-type byte - if((*reply_type = php_stream_getc(redis_sock->stream)) == EOF) { - zend_throw_exception(redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC); - } - - // If this is a BULK, MULTI BULK, or simply an INTEGER response, we can extract the value or size info here - if(*reply_type == TYPE_INT || *reply_type == TYPE_BULK || *reply_type == TYPE_MULTIBULK) { - // Buffer to hold size information - char inbuf[255]; - - // Read up to our newline - if(php_stream_gets(redis_sock->stream, inbuf, sizeof(inbuf)) < 0) { - return -1; - } - - // Set our size response - *reply_info = atoi(inbuf); - } - - // Success! - return 0; + // Make sure we haven't lost the connection, even trying to reconnect + if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) { + // Failure + return -1; + } + + // Attempt to read the reply-type byte + if((*reply_type = php_stream_getc(redis_sock->stream)) == EOF) { + zend_throw_exception(redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC); + } + + // If this is a BULK, MULTI BULK, or simply an INTEGER response, we can extract the value or size info here + if(*reply_type == TYPE_INT || *reply_type == TYPE_BULK || *reply_type == TYPE_MULTIBULK) { + // Buffer to hold size information + char inbuf[255]; + + // Read up to our newline + if(php_stream_gets(redis_sock->stream, inbuf, sizeof(inbuf)) < 0) { + return -1; + } + + // Set our size response + *reply_info = atoi(inbuf); + } + + // Success! + return 0; } /* @@ -1462,152 +1470,152 @@ redis_read_reply_type(RedisSock *redis_sock, REDIS_REPLY_TYPE *reply_type, int * */ PHPAPI int redis_read_variant_line(RedisSock *redis_sock, REDIS_REPLY_TYPE reply_type, zval **z_ret TSRMLS_DC) { - // Buffer to read our single line reply - char inbuf[1024]; - size_t line_size; - - // Attempt to read our single line reply - if(redis_sock_gets(redis_sock, inbuf, sizeof(inbuf), &line_size TSRMLS_CC) < 0) { - return -1; - } - - // If this is an error response, check if it is a SYNC error, and throw in that case - if(reply_type == TYPE_ERR) { - if(memcmp(inbuf, "ERR SYNC", 9) == 0) { - zend_throw_exception(redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC); - } - - // Set our last error - redis_sock_set_err(redis_sock, inbuf, line_size); - - // Set our response to FALSE - ZVAL_FALSE(*z_ret); - } else { - // Set our response to TRUE - ZVAL_TRUE(*z_ret); - } - - return 0; + // Buffer to read our single line reply + char inbuf[1024]; + size_t line_size; + + // Attempt to read our single line reply + if(redis_sock_gets(redis_sock, inbuf, sizeof(inbuf), &line_size TSRMLS_CC) < 0) { + return -1; + } + + // If this is an error response, check if it is a SYNC error, and throw in that case + if(reply_type == TYPE_ERR) { + if(memcmp(inbuf, "ERR SYNC", 9) == 0) { + zend_throw_exception(redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC); + } + + // Set our last error + redis_sock_set_err(redis_sock, inbuf, line_size); + + // Set our response to FALSE + ZVAL_FALSE(*z_ret); + } else { + // Set our response to TRUE + ZVAL_TRUE(*z_ret); + } + + return 0; } PHPAPI int redis_read_variant_bulk(RedisSock *redis_sock, int size, zval **z_ret TSRMLS_DC) { - // Attempt to read the bulk reply - char *bulk_resp = redis_sock_read_bulk_reply(redis_sock, size TSRMLS_CC); - - // Set our reply to FALSE on failure, and the string on success - if(bulk_resp == NULL) { - ZVAL_FALSE(*z_ret); - return -1; - } else { - ZVAL_STRINGL(*z_ret, bulk_resp, size, 0); - return 0; - } + // Attempt to read the bulk reply + char *bulk_resp = redis_sock_read_bulk_reply(redis_sock, size TSRMLS_CC); + + // Set our reply to FALSE on failure, and the string on success + if(bulk_resp == NULL) { + ZVAL_FALSE(*z_ret); + return -1; + } else { + ZVAL_STRINGL(*z_ret, bulk_resp, size, 0); + return 0; + } } PHPAPI int redis_read_multibulk_recursive(RedisSock *redis_sock, int elements, zval **z_ret TSRMLS_DC) { - int reply_info; - REDIS_REPLY_TYPE reply_type; - zval *z_subelem; - - // Iterate while we have elements - while(elements > 0) { - // Attempt to read our reply type - if(redis_read_reply_type(redis_sock, &reply_type, &reply_info TSRMLS_CC) < 0) { - zend_throw_exception_ex(redis_exception_ce, 0 TSRMLS_CC, "protocol error, couldn't parse MULTI-BULK response\n", reply_type); - return -1; - } - - // Switch on our reply-type byte - switch(reply_type) { - case TYPE_ERR: - case TYPE_LINE: - ALLOC_INIT_ZVAL(z_subelem); - redis_read_variant_line(redis_sock, reply_type, &z_subelem TSRMLS_CC); - add_next_index_zval(*z_ret, z_subelem); - break; - case TYPE_INT: - // Add our long value - add_next_index_long(*z_ret, reply_info); - break; - case TYPE_BULK: - // Init a zval for our bulk response, read and add it - ALLOC_INIT_ZVAL(z_subelem); - redis_read_variant_bulk(redis_sock, reply_info, &z_subelem TSRMLS_CC); - add_next_index_zval(*z_ret, z_subelem); - break; - case TYPE_MULTIBULK: - // Construct an array for our sub element, and add it, and recurse - ALLOC_INIT_ZVAL(z_subelem); - array_init(z_subelem); - add_next_index_zval(*z_ret, z_subelem); - redis_read_multibulk_recursive(redis_sock, reply_info, &z_subelem TSRMLS_CC); - break; - } - - // Decrement our element counter - elements--; - } - - return 0; + int reply_info; + REDIS_REPLY_TYPE reply_type; + zval *z_subelem; + + // Iterate while we have elements + while(elements > 0) { + // Attempt to read our reply type + if(redis_read_reply_type(redis_sock, &reply_type, &reply_info TSRMLS_CC) < 0) { + zend_throw_exception_ex(redis_exception_ce, 0 TSRMLS_CC, "protocol error, couldn't parse MULTI-BULK response\n", reply_type); + return -1; + } + + // Switch on our reply-type byte + switch(reply_type) { + case TYPE_ERR: + case TYPE_LINE: + ALLOC_INIT_ZVAL(z_subelem); + redis_read_variant_line(redis_sock, reply_type, &z_subelem TSRMLS_CC); + add_next_index_zval(*z_ret, z_subelem); + break; + case TYPE_INT: + // Add our long value + add_next_index_long(*z_ret, reply_info); + break; + case TYPE_BULK: + // Init a zval for our bulk response, read and add it + ALLOC_INIT_ZVAL(z_subelem); + redis_read_variant_bulk(redis_sock, reply_info, &z_subelem TSRMLS_CC); + add_next_index_zval(*z_ret, z_subelem); + break; + case TYPE_MULTIBULK: + // Construct an array for our sub element, and add it, and recurse + ALLOC_INIT_ZVAL(z_subelem); + array_init(z_subelem); + add_next_index_zval(*z_ret, z_subelem); + redis_read_multibulk_recursive(redis_sock, reply_info, &z_subelem TSRMLS_CC); + break; + } + + // Decrement our element counter + elements--; + } + + return 0; } PHPAPI int redis_read_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab) { - // Reply type, and reply size vars - REDIS_REPLY_TYPE reply_type; - int reply_info; - //char *bulk_resp; - zval *z_ret; - - // Attempt to read our header - if(redis_read_reply_type(redis_sock, &reply_type, &reply_info TSRMLS_CC) < 0) { - return -1; - } - - // Our return ZVAL - MAKE_STD_ZVAL(z_ret); - - // Switch based on our top level reply type - switch(reply_type) { - case TYPE_ERR: - case TYPE_LINE: - redis_read_variant_line(redis_sock, reply_type, &z_ret TSRMLS_CC); - break; - case TYPE_INT: - ZVAL_LONG(z_ret, reply_info); - break; - case TYPE_BULK: - redis_read_variant_bulk(redis_sock, reply_info, &z_ret TSRMLS_CC); - break; - case TYPE_MULTIBULK: - // Initialize an array for our multi-bulk response - array_init(z_ret); - - // If we've got more than zero elements, parse our multi bulk respoinse recursively - if(reply_info > -1) { - redis_read_multibulk_recursive(redis_sock, reply_info, &z_ret TSRMLS_CC); - } - break; - default: - // Protocol error - zend_throw_exception_ex(redis_exception_ce, 0 TSRMLS_CC, "protocol error, got '%c' as reply-type byte\n", reply_type); - break; - } - - IF_MULTI_OR_PIPELINE() { - add_next_index_zval(z_tab, z_ret); - } else { - // Set our return value - *return_value = *z_ret; - zval_copy_ctor(return_value); - zval_dtor(z_ret); - efree(z_ret); - } - - // Success - return 0; + // Reply type, and reply size vars + REDIS_REPLY_TYPE reply_type; + int reply_info; + //char *bulk_resp; + zval *z_ret; + + // Attempt to read our header + if(redis_read_reply_type(redis_sock, &reply_type, &reply_info TSRMLS_CC) < 0) { + return -1; + } + + // Our return ZVAL + MAKE_STD_ZVAL(z_ret); + + // Switch based on our top level reply type + switch(reply_type) { + case TYPE_ERR: + case TYPE_LINE: + redis_read_variant_line(redis_sock, reply_type, &z_ret TSRMLS_CC); + break; + case TYPE_INT: + ZVAL_LONG(z_ret, reply_info); + break; + case TYPE_BULK: + redis_read_variant_bulk(redis_sock, reply_info, &z_ret TSRMLS_CC); + break; + case TYPE_MULTIBULK: + // Initialize an array for our multi-bulk response + array_init(z_ret); + + // If we've got more than zero elements, parse our multi bulk respoinse recursively + if(reply_info > -1) { + redis_read_multibulk_recursive(redis_sock, reply_info, &z_ret TSRMLS_CC); + } + break; + default: + // Protocol error + zend_throw_exception_ex(redis_exception_ce, 0 TSRMLS_CC, "protocol error, got '%c' as reply-type byte\n", reply_type); + break; + } + + IF_MULTI_OR_PIPELINE() { + add_next_index_zval(z_tab, z_ret); + } else { + // Set our return value + *return_value = *z_ret; + zval_copy_ctor(return_value); + zval_dtor(z_ret); + efree(z_ret); + } + + // Success + return 0; } /* vim: set tabstop=4 softtabstop=4 noexpandtab shiftwidth=4: */ @@ -19,7 +19,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); @@ -520,7 +520,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) { @@ -556,6 +556,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; @@ -568,9 +569,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; } @@ -579,6 +581,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; } @@ -595,7 +602,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); diff --git a/redis_array.c b/redis_array.c index d0460f10..be95c50d 100644 --- a/redis_array.c +++ b/redis_array.c @@ -51,6 +51,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 +193,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 +234,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 +256,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 +703,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 d5370c82..c38e2fe6 100644 --- a/redis_array_impl.c +++ b/redis_array_impl.c @@ -29,7 +29,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 +67,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 +158,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 +225,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 +255,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 +280,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) { @@ -1112,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..009bac51 100644 --- a/redis_session.c +++ b/redis_session.c @@ -206,6 +206,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 +241,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 +260,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 +277,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); |