8000 Implemented SENTINEL commands · jrtkcoder/phpredis@2470ba2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2470ba2

Browse files
Implemented SENTINEL commands
This is the initial commit for the SENTINEL command, allowing phpredis to communicate with a redis-server started in --sentinel mode. It doesn't provide functionality to direct phpredis connections but can be used to configure/execute commands against the sentinel. Addresses phpredis#449
1 parent 02a67d5 commit 2470ba2

File tree

7 files changed

+755
-1
lines changed

7 files changed

+755
-1
lines changed

common.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,25 @@ typedef enum _REDIS_SCAN_TYPE {
4545
TYPE_ZSCAN
4646
} REDIS_SCAN_TYPE;
4747

48+
/* SENTINEL subcommands */
49+
typedef enum _SENTINEL_CMD {
50+
/* Standard directives */
51+
SENTINEL_MASTERS,
52+
SENTINEL_MASTER,
53+
SENTINEL_SLAVES,
54+
SENTINEL_MASTER_BY_NAME,
55+
SENTINEL_RESET,
56+
SENTINEL_FAILOVER,
57+
58+
/* Monitoring/Configuration */
59+
SENTINEL_MONITOR,
60+
SENTINEL_REMOVE,
61+
SENTINEL_SET,
62+
63+
/* invalid/unknown */
64+
SENTINEL_UNKNOWN
65+
} SENTINEL_CMD;
66+
4867
/* PUBSUB subcommands */
4968
typedef enum _PUBSUB_TYPE {
5069
PUBSUB_CHANNELS,

library.c

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,126 @@ PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC)
100100
return 0;
101101
}
102102

103+
/* Inner MULTIBULK reply parser for SENTINEL MASTERS or SENTINEL SLAVE */
104+
static zval*
105+
read_sentinel_server_reply(RedisSock *redis_sock TSRMLS_DC)
106+
{
107+
char buf[1024], *resp;
108+
int count, resp_len;
109+
zval *z_ret;
110+
111+
if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) {
112+
return NULL;
113+
}
114+
if(php_stream_gets(redis_sock->stream, buf, sizeof(buf)) == NULL) {
115+
redis_stream_close(redis_sock TSRMLS_CC);
116+
redis_sock->stream = NULL;
117+
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
118+
redis_sock->mode = ATOMIC;
119+
redis_sock->watching = 0;
120+
zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
121+
return NULL;
122+
}
123+
124+
// Must be MULTIBULK
125+
if(buf[0] != '*') {
126+
// Set last error, if something is wrong with our command, otherwise
127+
// throw an exception.
128+
if(buf[0] == TYPE_ERR) {
129+
redis_sock_set_err(redis_sock, buf, strlen(buf));
130+
} else {
131+
snprintf(buf, sizeof(buf), "Protocol error: Expecting MULTIBULK but got %s",
132+
redis_reply_type_str(buf[0]));
133+
zend_throw_exception(redis_exception_ce, buf, 0 TSRMLS_CC);
134+
}
135+
return NULL;
136+
}
137+
138+
// Grab the number of MULTIBULK elements
139+
count = atoi(buf+1);
140+
141+
// Crate our return array
142+
MAKE_STD_ZVAL(z_ret);
143+
array_init(z_ret);
144+
145+
// Read the values raw
146+
while(count>0) {
147+
if((resp = redis_sock_read(redis_sock, &resp_len TSRMLS_CC))!=NULL) {
148+
add_next_index_stringl(z_ret, resp, resp_len, 0);
149+
}
150+
count--;
151+
}
152+
153+
// Turn k1,v1,k2,v2 into k1=>v1, k2=>v2
154+
array_zip_values_and_scores(redis_sock, z_ret, 0 TSRMLS_CC);
155+
156+
// Return our value
157+
return z_ret;
158+
}
159+
160+
/* Read one MULTIBULK server info response */
161+
PHPAPI int
162+
redis_sock_read_sentinel_server_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
163+
zval *z_tab)
164+
{
165+
zval *z_resp;
166+
167+
// Grab the response in the form key1=>val1, key2=>val2
168+
if((z_resp = read_sentinel_server_reply(redis_sock TSRMLS_CC))==NULL) {
169+
return -1;
170+
}
171+
172+
// Set this as our return value, free contianer
173+
*return_value = *z_resp;
174+
efree(z_resp);
175+
176+
// Success
177+
return 0;
178+
}
179+
180+
/* Nested MULTIBULK replies with N elements */
181+
PHPAPI int
182+
redis_sock_read_sentinel_servers_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
183+
zval *z_tab)
184+
{
185+
REDIS_REPLY_TYPE reply_type;
186+
int count;
187+
zval *z_ret, *z_sub;
188+
189+
// Read our header
190+
if(redis_read_reply_type(redis_sock, &reply_type, &count TSRMLS_CC) < 0) {
191+
return -1;
192+
}
193+
194+
// Make sure we have an outer MULTIBULK reply
195+
if(reply_type != TYPE_MULTIBULK) {
196+
return -1;
197+
}
198+
199+
// Our return variable
200+
MAKE_STD_ZVAL(z_ret);
201+
array_init(z_ret);
202+
203+
// Read for each master reply
204+
while(count > 0) {
205+
// Grab our info for this master
206+
if((z_sub = read_sentinel_server_reply(redis_sock TSRMLS_CC))==NULL) {
207+
return -1;
208+
}
209+
add_next_index_zval(z_ret, z_sub);
210+
count--;
211+
}
212+
213+
IF_MULTI_OR_PIPELINE() {
214+
add_next_index_zval(z_tab, z_ret);
215+
} else {
216+
*return_value = *z_ret;
217+
efree(z_ret);
218+
}
219+
220+
// Success!
221+
return 0;
222+
}
103223

104224
PHPAPI int
105225
redis_sock_read_scan_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
@@ -1709,6 +1829,24 @@ redis_sock_gets(RedisSock *redis_sock, char *buf, int buf_size, size_t *line_siz
17091829
return 0;
17101830
}
17111831

1832+
/* Helper method to get the string representation of a REDIS_REPLY_TYPE */
1833+
const char *redis_reply_type_str(REDIS_REPLY_TYPE reply_type) {
1834+
switch(reply_type) {
1835+
case TYPE_LINE:
1836+
return "LINE";
1837+
case TYPE_INT:
1838+
return "INTEGER";
1839+
case TYPE_ERR:
1840+
return "ERROR";
1841+
case TYPE_BULK:
1842+
return "BULK";
1843+
case TYPE_MULTIBULK:
1844+
return "MULTIBULK";
1845+
default:
1846+
return "UNKNOWN";
1847+
}
1848+
}
1849+
17121850
PHPAPI int
17131851
redis_read_reply_type(RedisSock *redis_sock, REDIS_REPLY_TYPE *reply_type, int *reply_info TSRMLS_DC) {
17141852
// Make sure we haven't lost the connection, even trying to reconnect

library.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,15 @@ redis_key_prefix(RedisSock *redis_sock, char **key, int *key_len TSRMLS_DC);
5353
PHPAPI int
5454
redis_unserialize(RedisSock *redis_sock, const char *val, int val_len, zval **return_value TSRMLS_DC);
5555

56+
/* Sentinel command handlers */
57+
PHPAPI int redis_sock_read_sentinel_servers_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab);
58+
PHPAPI int redis_sock_read_sentinel_server_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab);
5659

5760
/*
5861
* Variant Read methods, mostly to implement eval
5962
*/
6063

64+
const char *redis_reply_type_str(REDIS_REPLY_TYPE reply_type);
6165
PHPAPI int redis_read_reply_type(RedisSock *redis_sock, REDIS_REPLY_TYPE *reply_type, int *reply_info TSRMLS_DC);
6266
PHPAPI int redis_read_variant_line(RedisSock *redis_sock, REDIS_REPLY_TYPE reply_type, zval **z_ret TSRMLS_DC);
6367
PHPAPI int redis_read_variant_bulk(RedisSock *redis_sock, int size, zval **z_ret TSRMLS_DC);

php_redis.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ PHP_METHOD(Redis, config);
186186
PHP_METHOD(Redis, slowlog);
187187
PHP_METHOD(Redis, wait);
188188
PHP_METHOD(Redis, pubsub);
189+
PHP_METHOD(Redis, sentinel);
189190

190191
PHP_METHOD(Redis, client);
191192

0 commit comments

Comments
 (0)
0