diff --git a/README.markdown b/README.markdown index 9ccfbbd55b..7d5d37dc20 100644 --- a/README.markdown +++ b/README.markdown @@ -24,7 +24,8 @@ You can send comments, patches, questions [here on github](https://github.com/ni * [Sorted sets](#sorted-sets) * [Pub/sub](#pubsub) * [Transactions](#transactions) - * [Scripting](#scripting) + * [Scripting](#Scripting) + * [Sentinel](#Sentinel) ----- @@ -2939,3 +2940,112 @@ serializing values, and you return something from redis in a LUA script that is $redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); $redis->_unserialize('a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}'); // Will return Array(1,2,3) ~~~ + + + +## Sentinel + +* [masters](#) - Show a list of monitored masters and their state +* [slaves](#) - Show a list of slaves for specified master and their state +* [getMasterAddrByName](#) - Return the ip and port number of the master with specified name +* [reset](#) - This command will reset all the masters with matching name + +### masters +----- +_**Description**_: Show a list of monitored masters and their state + +##### *Return value* +Array. Each element of this array is associative array with info about master and it state. + +##### *Examples* +~~~ +$redis->masters(); +/* Returns: +array( + 0 => array( + 'name' => 'mymaster', + 'ip' => '192.168.0.106', + 'port' => '6379', + 'runid' => '142d3942da9827b3bba9d16dd9c36a451b96288f', + 'flags' => 'master', + 'pending-commands' => '0', + 'last-ok-ping-reply' => '584', + 'last-ping-reply' => '584', + 'info-refresh' => '4758', + 'num-slaves' => '1', + 'num-other-sentinels' => '1', + 'quorum' => '2' + ) +) +*/ +~~~ + +### slaves +----- +_**Description**_: Show a list of slaves for specified master and their state. + +##### *Parameters* +*master_name* string. Master name. + +##### *Return value* +Array. Each element of this array is associative array with info about slave and it state. + +##### *Examples* +~~~ +$redis->slaves('mymaster'); +/* Returns: +array( + 0 => array( + 'name' => '192.168.0.129:6379', + 'ip' => '192.168.0.129', + 'port' => '6379', + 'runid' => '1cad55cd8e2df3093184f5f98932996117709dab', + 'flags' => 'slave', + 'pending-commands' => '0', + 'last-ok-ping-reply' => '623', + 'last-ping-reply' => '623', + 'info-refresh' => '622', + 'master-link-down-time' => '449000', + 'master-link-status' => 'err', + 'master-host' => '192.168.0.106', + 'master-port' => '6379', + 'slave-priority' => '100' + ) +) +*/ +~~~ + +### getMasterAddrByName +----- +_**Description**_: Return the ip and port number of the master with specified name. +If a failover is in progress or terminated successfully for this master it returns +the address and port of the promoted slave. + +##### *Parameters* +*master_name* string. Master name. + +##### *Return value* +Array. First item in array is a master ip. Second item is a master port. + +##### *Examples* +~~~ +$redis->getMasterAddrByName('mymaster'); // Returns: array(0 => '192.168.0.106', 1 => '6379') +~~~ + +### reset +----- +_**Description**_: This command will reset all the masters with matching name. +The reset process clears any previous state in a master (including a failover in +progress), and removes every slave and sentinel already discovered and associated +with the master. + +##### *Parameters* +*pattern* string. The pattern argument is a glob-style pattern. + +##### *Return value* +Integer. Number of reseted masters. + +##### *Examples* +~~~ +$redis->reset('mymaster'); // Returns: 1 +~~~ diff --git a/library.c b/library.c old mode 100644 new mode 100755 index 6a93f49096..1799288495 --- a/library.c +++ b/library.c @@ -1213,6 +1213,95 @@ PHPAPI int redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, R return 0; } +/** + * redis_sock_read_multi_multibulk_reply_assoc + */ +PHPAPI int redis_sock_read_multi_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { + char inbuf[1024], *response, *key; + int response_len; + int i, j, numElems, numSubElems; + zval *z_multi_result; + zval *z_signle_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_sock->stream = NULL; + redis_sock->status = REDIS_SOCK_STATUS_FAILED; + redis_sock->mode = ATOMIC; + redis_sock->watching = 0; + zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC); + return -1; + } + if(inbuf[0] != '*') { + return -1; + } + + numSubElems = atoi(inbuf+1); + MAKE_STD_ZVAL(z_signle_result); + array_init(z_signle_result); /* pre-allocate array for multi's results. */ + + for(j = 0; j < numSubElems; ++j) { + 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_sock->stream = NULL; + redis_sock->status = REDIS_SOCK_STATUS_FAILED; + redis_sock->mode = ATOMIC; + redis_sock->watching = 0; + zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC); + return -1; + } + if(inbuf[0] != '*') { + return -1; + } + + numElems = atoi(inbuf+1) / 2; + MAKE_STD_ZVAL(z_multi_result); + array_init(z_multi_result); /* pre-allocate array for multi's results. */ + + for(i = 0; i < numElems; ++i) { + // read key + key = redis_sock_read(redis_sock, &response_len TSRMLS_CC); + if(key == NULL) { + continue; + } + + // read value and append it to array + response = redis_sock_read(redis_sock, &response_len TSRMLS_CC); + if(response != NULL) { + zval *kValue = NULL; + if(redis_unserialize(redis_sock, response, response_len, &kValue TSRMLS_CC) == 1) { + efree(response); + add_assoc_zval(z_multi_result, key, kValue); + } else { + add_assoc_stringl_ex(z_multi_result, key, strlen(key)+1, response, response_len, 0); + } + } else { + continue; + } + } + + add_next_index_zval(z_signle_result, z_multi_result); + } + + IF_MULTI_OR_PIPELINE() { + add_next_index_zval(z_tab, z_signle_result); + } else { + *return_value = *z_signle_result; + + zval_copy_ctor(return_value); + INIT_PZVAL(return_value); + } + + return 0; +} + /** * redis_sock_write */ diff --git a/library.h b/library.h old mode 100644 new mode 100755 index ea135bfbc5..06873cb53d --- a/library.h +++ b/library.h @@ -31,6 +31,7 @@ PHPAPI int redis_sock_read_multibulk_reply_loop(INTERNAL_FUNCTION_PARAMETERS, Re PHPAPI int redis_sock_read_multibulk_reply_zipped(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHPAPI int redis_sock_read_multibulk_reply_zipped_strings(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHPAPI int redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); +PHPAPI int redis_sock_read_multi_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHPAPI int redis_sock_write(RedisSock *redis_sock, char *cmd, size_t sz TSRMLS_DC); PHPAPI void redis_stream_close(RedisSock *redis_sock TSRMLS_DC); PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC); diff --git a/php_redis.h b/php_redis.h old mode 100644 new mode 100755 index 24f002150e..bb34771742 --- a/php_redis.h +++ b/php_redis.h @@ -181,6 +181,12 @@ PHP_METHOD(Redis, setOption); PHP_METHOD(Redis, config); +/* Sentinel functions*/ +PHP_METHOD(Redis, masters); +PHP_METHOD(Redis, getMasterAddrByName); +PHP_METHOD(Redis, slaves); +PHP_METHOD(Redis, reset); + #ifdef PHP_WIN32 #define PHP_REDIS_API __declspec(dllexport) #else diff --git a/redis.c b/redis.c old mode 100644 new mode 100755 index fd103d30f9..9940a926d9 --- a/redis.c +++ b/redis.c @@ -235,6 +235,12 @@ static zend_function_entry redis_functions[] = { /* config */ PHP_ME(Redis, config, NULL, ZEND_ACC_PUBLIC) + /* Sentinel */ + PHP_ME(Redis, masters, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Redis, getMasterAddrByName, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Redis, slaves, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Redis, reset, NULL, ZEND_ACC_PUBLIC) + /* aliases */ PHP_MALIAS(Redis, open, connect, NULL, ZEND_ACC_PUBLIC) PHP_MALIAS(Redis, popen, pconnect, NULL, ZEND_ACC_PUBLIC) @@ -6242,5 +6248,128 @@ PHP_METHOD(Redis, time) { REDIS_PROCESS_RESPONSE(redis_sock_read_multibulk_reply_raw); } +/* {{{ proto array Redis::masters() + */ +PHP_METHOD(Redis, masters) { + + zval *object; + RedisSock *redis_sock; + char *cmd, *opt = NULL; + int cmd_len, opt_len; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|s", + &object, redis_ce, &opt, &opt_len) == FAILURE) { + RETURN_FALSE; + } + + if (redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) { + RETURN_FALSE; + } + + cmd_len = redis_cmd_format(&cmd, "SENTINEL masters" _NL, ""); + + REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); + IF_ATOMIC() { + redis_sock_read_multi_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL); + } + REDIS_PROCESS_RESPONSE(redis_sock_read_multi_multibulk_reply_assoc); +} +/* }}} */ + +/* {{{ proto array Redis::getMasterAddrByName() + */ +PHP_METHOD(Redis, getMasterAddrByName) { + + zval *object; + RedisSock *redis_sock; + char *cmd, *opt = NULL; + int cmd_len, opt_len; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|s", + &object, redis_ce, &opt, &opt_len) == FAILURE) { + RETURN_FALSE; + } + + if (redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) { + RETURN_FALSE; + } + + if(opt == NULL) { + RETURN_FALSE; + } + + cmd_len = redis_cmd_format(&cmd, "SENTINEL get-master-addr-by-name %s" _NL, opt, opt_len); + + REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); + IF_ATOMIC() { + redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL); + } + REDIS_PROCESS_RESPONSE(redis_sock_read_multibulk_reply); +} +/* }}} */ + +/* {{{ proto array Redis::slaves() + */ +PHP_METHOD(Redis, slaves) { + + zval *object; + RedisSock *redis_sock; + char *cmd, *opt = NULL; + int cmd_len, opt_len; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|s", + &object, redis_ce, &opt, &opt_len) == FAILURE) { + RETURN_FALSE; + } + + if (redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) { + RETURN_FALSE; + } + + if(opt == NULL) { + RETURN_FALSE; + } + + cmd_len = redis_cmd_format(&cmd, "SENTINEL slaves %s" _NL, opt, opt_len); + + REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); + IF_ATOMIC() { + redis_sock_read_multi_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL); + } + REDIS_PROCESS_RESPONSE(redis_sock_read_multi_multibulk_reply_assoc); +} + +/* {{{ proto array Redis::reset() + */ +PHP_METHOD(Redis, reset) { + + zval *object; + RedisSock *redis_sock; + char *cmd, *opt = NULL; + int cmd_len, opt_len; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|s", + &object, redis_ce, &opt, &opt_len) == FAILURE) { + RETURN_FALSE; + } + + if (redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) { + RETURN_FALSE; + } + + if(opt == NULL) { + RETURN_FALSE; + } + + cmd_len = redis_cmd_format(&cmd, "SENTINEL reset %s" _NL, opt, opt_len); + + REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); + IF_ATOMIC() { + redis_long_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL); + } + REDIS_PROCESS_RESPONSE(redis_long_response); +} +/* }}} */ + /* vim: set tabstop=4 softtabstop=4 noexpandtab shiftwidth=4: */