cluster_library.h 17.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef _PHPREDIS_CLUSTER_LIBRARY_H
#define _PHPREDIS_CLUSTER_LIBRARY_H

#include "common.h"

#ifdef ZTS
#include "TSRM.h"
#endif

/* Redis cluster hash slots and N-1 which we'll use to find it */
#define REDIS_CLUSTER_SLOTS 16384
#define REDIS_CLUSTER_MOD   (REDIS_CLUSTER_SLOTS-1)

Michael Grunder's avatar
Michael Grunder committed
14
/* Complete representation for various commands in RESP */
15
16
17
18
19
20
#define RESP_MULTI_CMD         "*1\r\n$5\r\nMULTI\r\n"
#define RESP_EXEC_CMD          "*1\r\n$4\r\nEXEC\r\n"
#define RESP_DISCARD_CMD       "*1\r\n$7\r\nDISCARD\r\n"
#define RESP_UNWATCH_CMD       "*1\r\n$7\r\nUNWATCH\r\n"
#define RESP_CLUSTER_SLOTS_CMD "*2\r\n$7\r\nCLUSTER\r\n$5\r\nSLOTS\r\n"
#define RESP_ASKING_CMD        "*1\r\n$6\r\nASKING\r\n"
21
22
#define RESP_READONLY_CMD      "*1\r\n$8\r\nREADONLY\r\n"
#define RESP_READWRITE_CMD     "*1\r\n$9\r\nREADWRITE\r\n"
23

24
25
#define RESP_READONLY_CMD_LEN (sizeof(RESP_READONLY_CMD)-1)

26
27
/* MOVED/ASK comparison macros */
#define IS_MOVED(p) (p[0]=='M' && p[1]=='O' && p[2]=='V' && p[3]=='E' && \
28
                     p[4]=='D' && p[5]==' ')
29
#define IS_ASK(p)   (p[0]=='A' && p[1]=='S' && p[2]=='K' && p[3]==' ')
30
31
32
33
34

/* MOVED/ASK lengths */
#define MOVED_LEN (sizeof("MOVED ")-1)
#define ASK_LEN   (sizeof("ASK ")-1)

Michael Grunder's avatar
Michael Grunder committed
35
36
37
/* Initial allocation size for key distribution container */
#define CLUSTER_KEYDIST_ALLOC 8

38
/* Macros to access nodes, sockets, and streams for a given slot */
39
40
41
#define SLOT(c,s) (c->master[s])
#define SLOT_SOCK(c,s) (SLOT(c,s)->sock)
#define SLOT_STREAM(c,s) (SLOT_SOCK(c,s)->stream)
42
43
44
45
46
#define SLOT_SLAVES(c,s) (c->master[s]->slaves)

/* Macros to access socket and stream for the node we're communicating with */
#define CMD_SOCK(c) (c->cmd_sock)
#define CMD_STREAM(c) (c->cmd_sock->stream)
47
48
49
50

/* Compare redirection slot information with what we have */
#define CLUSTER_REDIR_CMP(c) \
    (SLOT_SOCK(c,c->redir_slot)->port != c->redir_port || \
51
52
    ZSTR_LEN(SLOT_SOCK(c,c->redir_slot)->host) != c->redir_host_len || \
    memcmp(ZSTR_VAL(SLOT_SOCK(c,c->redir_slot)->host),c->redir_host,c->redir_host_len))
53

54
/* Clear out our "last error" */
55
56
57
58
59
60
61
#define CLUSTER_CLEAR_ERROR(c) do { \
    if (c->err) { \
        zend_string_release(c->err); \
        c->err = NULL; \
    } \
    c->clusterdown = 0; \
} while (0)
62

63
64
/* Protected sending of data down the wire to a RedisSock->stream */
#define CLUSTER_SEND_PAYLOAD(sock, buf, len) \
Remi Collet's avatar
Remi Collet committed
65
    (sock && !cluster_sock_open(sock) && sock->stream && !redis_check_eof(sock, 1 ) && \
66
67
68
69
     php_stream_write(sock->stream, buf, len)==len)

/* Macro to read our reply type character */
#define CLUSTER_VALIDATE_REPLY_TYPE(sock, type) \
Remi Collet's avatar
Remi Collet committed
70
    (redis_check_eof(sock, 1) == 0 && \
71
72
     (php_stream_getc(sock->stream) == type))

73
74
75
76
/* Reset our last single line reply buffer and length */
#define CLUSTER_CLEAR_REPLY(c) \
    *c->line_reply = '\0'; c->reply_len = 0;

Michael Grunder's avatar
Michael Grunder committed
77
78
79
80
81
82
83
84
/* Helper to determine if we're in MULTI mode */
#define CLUSTER_IS_ATOMIC(c) (c->flags->mode != MULTI)

/* Helper that either returns false or adds false in multi mode */
#define CLUSTER_RETURN_FALSE(c) \
    if(CLUSTER_IS_ATOMIC(c)) { \
        RETURN_FALSE; \
    } else { \
Pavlo Yatsukhnenko's avatar
Pavlo Yatsukhnenko committed
85
        add_next_index_bool(&c->multi_resp, 0); \
Michael Grunder's avatar
Michael Grunder committed
86
87
88
89
90
91
92
93
94
95
96
97
        return; \
    }

/* Helper to either return a bool value or add it to MULTI response */
#define CLUSTER_RETURN_BOOL(c, b) \
    if(CLUSTER_IS_ATOMIC(c)) { \
        if(b==1) {\
            RETURN_TRUE; \
        } else {\
            RETURN_FALSE; \
        } \
    } else { \
Pavlo Yatsukhnenko's avatar
Pavlo Yatsukhnenko committed
98
        add_next_index_bool(&c->multi_resp, b); \
Michael Grunder's avatar
Michael Grunder committed
99
100
101
102
103
104
105
    }

/* Helper to respond with a double or add it to our MULTI response */
#define CLUSTER_RETURN_DOUBLE(c, d) \
    if(CLUSTER_IS_ATOMIC(c)) { \
        RETURN_DOUBLE(d); \
    } else { \
Pavlo Yatsukhnenko's avatar
Pavlo Yatsukhnenko committed
106
        add_next_index_double(&c->multi_resp, d); \
Michael Grunder's avatar
Michael Grunder committed
107
108
109
110
111
    }

/* Helper to return a string value */
#define CLUSTER_RETURN_STRING(c, str, len) \
    if(CLUSTER_IS_ATOMIC(c)) { \
Pavlo Yatsukhnenko's avatar
Pavlo Yatsukhnenko committed
112
        RETVAL_STRINGL(str, len); \
Michael Grunder's avatar
Michael Grunder committed
113
    } else { \
Pavlo Yatsukhnenko's avatar
Pavlo Yatsukhnenko committed
114
        add_next_index_stringl(&c->multi_resp, str, len); \
Michael Grunder's avatar
Michael Grunder committed
115
116
117
118
119
120
121
    } \

/* Return a LONG value */
#define CLUSTER_RETURN_LONG(c, val) \
    if(CLUSTER_IS_ATOMIC(c)) { \
        RETURN_LONG(val); \
    } else { \
Pavlo Yatsukhnenko's avatar
Pavlo Yatsukhnenko committed
122
        add_next_index_long(&c->multi_resp, val); \
Michael Grunder's avatar
Michael Grunder committed
123
124
    }

Michael Grunder's avatar
MGET    
Michael Grunder committed
125
126
127
128
129
130
131
132
133
134
135
/* Macro to clear out a clusterMultiCmd structure */
#define CLUSTER_MULTI_CLEAR(mc) \
    mc->cmd.len  = 0; \
    mc->args.len = 0; \
    mc->argc     = 0; \

/* Initialzie a clusterMultiCmd with a keyword and length */
#define CLUSTER_MULTI_INIT(mc, keyword, keyword_len) \
    mc.kw     = keyword; \
    mc.kw_len = keyword_len; \

136
137
138
139
140
141
142
/* Cluster redirection enum */
typedef enum CLUSTER_REDIR_TYPE {
    REDIR_NONE,
    REDIR_MOVED,
    REDIR_ASK
} CLUSTER_REDIR_TYPE;

143
/* MULTI BULK response callback typedef */
Remi Collet's avatar
Remi Collet committed
144
typedef int  (*mbulk_cb)(RedisSock*,zval*,long long, void*);
145

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/* A list of covered slot ranges */
typedef struct redisSlotRange {
    unsigned short low;
    unsigned short high;
} redisSlotRange;

/* Simple host/port information for our cache */
typedef struct redisCachedHost {
    zend_string *addr;
    unsigned short port;
} redisCachedHost;

/* Storage for a cached master node */
typedef struct redisCachedMaster {
    redisCachedHost host;

    redisSlotRange *slot;   /* Slots and count */
    size_t slots;

    redisCachedHost *slave; /* Slaves and their count */
    size_t slaves;
} redisCachedMaster;

typedef struct redisCachedCluster {
    // int rsrc_id;               /* Zend resource ID */
    zend_string *hash;         /* What we're cached by */
    redisCachedMaster *master; /* Array of masters */
    size_t count;              /* Number of masters */
} redisCachedCluster;
175
176
177

/* A Redis Cluster master node */
typedef struct redisClusterNode {
178
179
180
181
182
    RedisSock *sock;      /* Our Redis socket in question */
    short slot;           /* One slot we believe this node serves */
    zend_llist slots;     /* List of all slots we believe this node serves */
    unsigned short slave; /* Are we a slave */
    HashTable *slaves;    /* Hash table of slaves */
183
184
} redisClusterNode;

185
/* Forward declarations */
Michael Grunder's avatar
Michael Grunder committed
186
187
typedef struct clusterFoldItem clusterFoldItem;

188
189
/* RedisCluster implementation structure */
typedef struct redisCluster {
Pavlo Yatsukhnenko's avatar
Pavlo Yatsukhnenko committed
190
191
    zend_string *auth;

192
    /* Timeout and read timeout (for normal operations) */
193
194
195
    double timeout;
    double read_timeout;

196
197
198
    /* Are we using persistent connections */
    int persistent;

199
200
201
    /* How long in milliseconds should we wait when being bounced around */
    long waitms;

202
203
204
205
    /* Are we flagged as being in readonly mode, meaning we could fall back to
     * a given master's slave */
    short readonly;

206
207
208
    /* RedisCluster failover options (never, on error, to load balance) */
    short failover;

209
210
211
212
213
214
215
216
    /* Hash table of seed host/ports */
    HashTable *seeds;

    /* RedisCluster masters, by direct slot */
    redisClusterNode *master[REDIS_CLUSTER_SLOTS];

    /* All RedisCluster objects we've created/are connected to */
    HashTable *nodes;
217

Michael Grunder's avatar
Michael Grunder committed
218
219
220
221
    /* Transaction handling linked list, and where we are as we EXEC */
    clusterFoldItem *multi_head;
    clusterFoldItem *multi_curr;

222
223
224
225
    /* When we issue EXEC to nodes, we need to keep track of how many replies
     * we have, as this can fail for various reasons (EXECABORT, watch, etc.) */
    char multi_len[REDIS_CLUSTER_SLOTS];

Michael Grunder's avatar
Michael Grunder committed
226
    /* Variable to store MULTI response */
Pavlo Yatsukhnenko's avatar
Pavlo Yatsukhnenko committed
227
    zval multi_resp;
Michael Grunder's avatar
Michael Grunder committed
228

229
230
    /* Flag for when we get a CLUSTERDOWN error */
    short clusterdown;
231

232
233
234
235
236
    /* Key to our persistent list cache and number of redirections we've
     * received since construction */
    zend_string *cache_key;
    uint64_t redirections;

237
    /* The last ERROR we encountered */
238
    zend_string *err;
239

240
241
242
    /* The slot our command is operating on, as well as it's socket */
    unsigned short cmd_slot;
    RedisSock *cmd_sock;
243

Michael Grunder's avatar
Michael Grunder committed
244
245
246
    /* The slot where we're subscribed */
    short subscribed_slot;

247
    /* One RedisSock struct for serialization and prefix information */
248
249
    RedisSock *flags;

Michael Grunder's avatar
Michael Grunder committed
250
    /* The first line of our last reply, not including our reply type byte
251
252
253
254
255
     * or the trailing \r\n */
    char line_reply[1024];

    /* The last reply type and length or integer response we got */
    REDIS_REPLY_TYPE reply_type;
256
    long long reply_len;
257

258
259
260
261
262
263
    /* Last MOVED or ASK redirection response information */
    CLUSTER_REDIR_TYPE redir_type;
    char               redir_host[255];
    int                redir_host_len;
    unsigned short     redir_slot;
    unsigned short     redir_port;
264
265
266

    /* Zend object handler */
    zend_object std;
267
268
} redisCluster;

Michael Grunder's avatar
Michael Grunder committed
269
270
271
272
273
274
275
276
/* RedisCluster response processing callback */
typedef void (*cluster_cb)(INTERNAL_FUNCTION_PARAMETERS, redisCluster*, void*);

/* Context for processing transactions */
struct clusterFoldItem {
    /* Response processing callback */
    cluster_cb callback;

277
278
    /* The actual socket where we send this request */
    unsigned short slot;
Michael Grunder's avatar
Michael Grunder committed
279
280
281
282
283
284
285
286

    /* Any context we need to send to our callback */
    void *ctx;

    /* Next item in our list */
    struct clusterFoldItem *next;
};

Michael Grunder's avatar
Michael Grunder committed
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/* Key and value container, with info if they need freeing */
typedef struct clusterKeyVal {
    char *key, *val;
    int  key_len,  val_len;
    int  key_free, val_free;
} clusterKeyVal;

/* Container to hold keys (and possibly values) for when we need to distribute
 * commands across more than 1 node (e.g. WATCH, MGET, MSET, etc) */
typedef struct clusterDistList {
    clusterKeyVal *entry;
    size_t len, size;
} clusterDistList;

Michael Grunder's avatar
Michael Grunder committed
301
/* Context for things like MGET/MSET/MSETNX.  When executing in MULTI mode,
Michael Grunder's avatar
MGET    
Michael Grunder committed
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
 * we'll want to re-integrate into one running array, except for the last
 * command execution, in which we'll want to return the value (or add it) */
typedef struct clusterMultiCtx {
    /* Our running array */
    zval *z_multi;

    /* How many keys did we request for this bit */
    int count;

    /* Is this the last entry */
    short last;
} clusterMultiCtx;

/* Container for things like MGET, MSET, and MSETNX, which split the command
 * into a header and payload while aggregating to a specific slot. */
typedef struct clusterMultiCmd {
    /* Keyword and keyword length */
    char *kw;
    int  kw_len;

    /* Arguments in our payload */
    int argc;

    /* The full command, built into cmd, and args as we aggregate */
326
327
    smart_string cmd;
    smart_string args;
Michael Grunder's avatar
MGET    
Michael Grunder committed
328
329
} clusterMultiCmd;

330
331
332
333
334
/* Hiredis like structure for processing any sort of reply Redis Cluster might
 * give us, including N level deep nested multi-bulk replies.  Unlike hiredis
 * we don't encode errors, here as that's handled in the cluster structure. */
typedef struct clusterReply {
    REDIS_REPLY_TYPE type;         /* Our reply type */
Michael Grunder's avatar
Michael Grunder committed
335
336
    size_t integer;                /* Integer reply */
    long long len;                 /* Length of our string */
337
338
339
340
341
342
    char *str;                     /* String reply */
    size_t elements;               /* Count of array elements */
    struct clusterReply **element; /* Array elements */
} clusterReply;

/* Direct variant response handler */
Remi Collet's avatar
Remi Collet committed
343
clusterReply *cluster_read_resp(redisCluster *c, int status_strings);
Michael Grunder's avatar
Michael Grunder committed
344
clusterReply *cluster_read_sock_resp(RedisSock *redis_sock,
Remi Collet's avatar
Remi Collet committed
345
    REDIS_REPLY_TYPE type, char *line_reply, size_t reply_len);
346
347
void cluster_free_reply(clusterReply *reply, int free_data);

Michael Grunder's avatar
MGET    
Michael Grunder committed
348
/* Cluster distribution helpers for WATCH */
Michael Grunder's avatar
Michael Grunder committed
349
350
HashTable *cluster_dist_create();
void cluster_dist_free(HashTable *ht);
Michael Grunder's avatar
Michael Grunder committed
351
int cluster_dist_add_key(redisCluster *c, HashTable *ht, char *key,
352
    size_t key_len, clusterKeyVal **kv);
Michael Grunder's avatar
Michael Grunder committed
353
void cluster_dist_add_val(redisCluster *c, clusterKeyVal *kv, zval *val
Remi Collet's avatar
Remi Collet committed
354
   );
Michael Grunder's avatar
Michael Grunder committed
355

Michael Grunder's avatar
MGET    
Michael Grunder committed
356
357
358
359
360
361
/* Aggregation for multi commands like MGET, MSET, and MSETNX */
void cluster_multi_init(clusterMultiCmd *mc, char *kw, int kw_len);
void cluster_multi_free(clusterMultiCmd *mc);
void cluster_multi_add(clusterMultiCmd *mc, char *data, int data_len);
void cluster_multi_fini(clusterMultiCmd *mc);

362
/* Hash a key to it's slot, using the Redis Cluster hash algorithm */
363
unsigned short cluster_hash_key_zval(zval *key);
364
365
unsigned short cluster_hash_key(const char *key, int len);

Tyson Andre's avatar
Tyson Andre committed
366
/* Get the current time in milliseconds */
367
368
long long mstime(void);

Michael Grunder's avatar
Michael Grunder committed
369
PHP_REDIS_API short cluster_send_command(redisCluster *c, short slot, const char *cmd,
Remi Collet's avatar
Remi Collet committed
370
    int cmd_len);
371

Remi Collet's avatar
Remi Collet committed
372
PHP_REDIS_API void cluster_disconnect(redisCluster *c, int force);
Michael Grunder's avatar
Michael Grunder committed
373

Remi Collet's avatar
Remi Collet committed
374
375
376
PHP_REDIS_API int cluster_send_exec(redisCluster *c, short slot);
PHP_REDIS_API int cluster_send_discard(redisCluster *c, short slot);
PHP_REDIS_API int cluster_abort_exec(redisCluster *c);
377
PHP_REDIS_API int cluster_reset_multi(redisCluster *c);
Michael Grunder's avatar
Michael Grunder committed
378

379
PHP_REDIS_API short cluster_find_slot(redisCluster *c, const char *host,
380
    unsigned short port);
Michael Grunder's avatar
Michael Grunder committed
381
PHP_REDIS_API int cluster_send_slot(redisCluster *c, short slot, char *cmd,
Remi Collet's avatar
Remi Collet committed
382
    int cmd_len, REDIS_REPLY_TYPE rtype);
Michael Grunder's avatar
Michael Grunder committed
383

384
PHP_REDIS_API redisCluster *cluster_create(double timeout, double read_timeout,
385
    int failover, int persistent);
Remi Collet's avatar
Remi Collet committed
386
PHP_REDIS_API void cluster_free(redisCluster *c, int free_ctx);
387
PHP_REDIS_API int cluster_init_seeds(redisCluster *c, HashTable *ht_seeds);
Remi Collet's avatar
Remi Collet committed
388
PHP_REDIS_API int cluster_map_keyspace(redisCluster *c);
389
PHP_REDIS_API void cluster_free_node(redisClusterNode *node);
390

391
392
393
394
395
396
397
/* Functions for interacting with cached slots maps */
PHP_REDIS_API redisCachedCluster *cluster_cache_create(zend_string *hash, HashTable *nodes);
PHP_REDIS_API void cluster_cache_free(redisCachedCluster *rcc);
PHP_REDIS_API void cluster_init_cache(redisCluster *c, redisCachedCluster *rcc);

/* Functions to facilitate cluster slot caching */

398
PHP_REDIS_API char **cluster_sock_read_multibulk_reply(RedisSock *redis_sock,
Remi Collet's avatar
Remi Collet committed
399
    int *len);
400
401
PHP_REDIS_API int cluster_cache_store(HashTable *ht_seeds, HashTable *nodes);
PHP_REDIS_API redisCachedCluster *cluster_cache_load(HashTable *ht_seeds);
402

403
/*
404
 * Redis Cluster response handlers.  Our response handlers generally take the
405
 * following form:
Michael Grunder's avatar
Michael Grunder committed
406
 *      PHP_REDIS_API void handler(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
407
 *          void *ctx)
408
409
410
411
412
 *
 * Reply handlers are responsible for setting the PHP return value (either to
 * something valid, or FALSE in the case of some failures).
 */

Michael Grunder's avatar
Michael Grunder committed
413
PHP_REDIS_API void cluster_bool_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
Michael Grunder's avatar
Michael Grunder committed
414
    void *ctx);
415
PHP_REDIS_API void cluster_ping_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
Michael Grunder's avatar
Michael Grunder committed
416
    void *ctx);
Michael Grunder's avatar
Michael Grunder committed
417
PHP_REDIS_API void cluster_single_line_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
Michael Grunder's avatar
Michael Grunder committed
418
    void *ctx);
Michael Grunder's avatar
Michael Grunder committed
419
PHP_REDIS_API void cluster_bulk_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
420
    void *ctx);
Michael Grunder's avatar
Michael Grunder committed
421
PHP_REDIS_API void cluster_bulk_raw_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
Michael Grunder's avatar
Michael Grunder committed
422
    void *ctx);
Michael Grunder's avatar
Michael Grunder committed
423
PHP_REDIS_API void cluster_dbl_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
Michael Grunder's avatar
Michael Grunder committed
424
    void *ctx);
Michael Grunder's avatar
Michael Grunder committed
425
PHP_REDIS_API void cluster_1_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
Michael Grunder's avatar
Michael Grunder committed
426
    void *ctx);
Michael Grunder's avatar
Michael Grunder committed
427
428
429
PHP_REDIS_API void cluster_long_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
    void *ctx);
PHP_REDIS_API void cluster_type_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
Michael Grunder's avatar
Michael Grunder committed
430
    void *ctx);
431
PHP_REDIS_API void cluster_sub_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
Michael Grunder's avatar
Michael Grunder committed
432
    void *ctx);
433
PHP_REDIS_API void cluster_unsub_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
Michael Grunder's avatar
Michael Grunder committed
434
    void *ctx);
435

436
PHP_REDIS_API void cluster_variant_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
Michael Grunder committed
437
438
    redisCluster *c, void *ctx);

439
440
441
PHP_REDIS_API void cluster_variant_raw_resp(INTERNAL_FUNCTION_PARAMETERS,
    redisCluster *c, void *ctx);

Michael Grunder's avatar
Michael Grunder committed
442
443
444
PHP_REDIS_API void cluster_variant_resp_strings(INTERNAL_FUNCTION_PARAMETERS,
    redisCluster *c, void *ctx);

445
/* MULTI BULK response functions */
Michael Grunder's avatar
Michael Grunder committed
446
PHP_REDIS_API void cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
Michael Grunder committed
447
    redisCluster *c, mbulk_cb func, void *ctx);
Michael Grunder's avatar
Michael Grunder committed
448
PHP_REDIS_API void cluster_mbulk_raw_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
Michael Grunder committed
449
    redisCluster *c, void *ctx);
Michael Grunder's avatar
Michael Grunder committed
450
PHP_REDIS_API void cluster_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
Michael Grunder committed
451
    redisCluster *c, void *ctx);
452
PHP_REDIS_API void cluster_mbulk_zipstr_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
Michael Grunder committed
453
    redisCluster *c, void *ctx);
454
PHP_REDIS_API void cluster_mbulk_zipdbl_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
Michael Grunder committed
455
    redisCluster *c, void *ctx);
Michael Grunder's avatar
Michael Grunder committed
456
PHP_REDIS_API void cluster_mbulk_assoc_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
Michael Grunder committed
457
    redisCluster *c, void *ctx);
458
PHP_REDIS_API void cluster_multi_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
Michael Grunder committed
459
    redisCluster *c, void *ctx);
Michael Grunder's avatar
Michael Grunder committed
460
PHP_REDIS_API zval *cluster_zval_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
Pavlo Yatsukhnenko's avatar
Pavlo Yatsukhnenko committed
461
    redisCluster *c, int pull, mbulk_cb cb, zval *z_ret);
462

Michael Grunder's avatar
Michael Grunder committed
463
/* Handlers for things like DEL/MGET/MSET/MSETNX */
Michael Grunder's avatar
Michael Grunder committed
464
PHP_REDIS_API void cluster_del_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
Michael Grunder committed
465
    redisCluster *c, void *ctx);
Michael Grunder's avatar
Michael Grunder committed
466
PHP_REDIS_API void cluster_mbulk_mget_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
MGET    
Michael Grunder committed
467
    redisCluster *c, void *ctx);
468
PHP_REDIS_API void cluster_mset_resp(INTERNAL_FUNCTION_PARAMETERS,
469
    redisCluster *c, void *ctx);
470
PHP_REDIS_API void cluster_msetnx_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
MGET    
Michael Grunder committed
471
472
    redisCluster *c, void *ctx);

Michael Grunder's avatar
Michael Grunder committed
473
/* Response handler for ZSCAN, SSCAN, and HSCAN */
474
PHP_REDIS_API int cluster_scan_resp(INTERNAL_FUNCTION_PARAMETERS,
Michael Grunder's avatar
Michael Grunder committed
475
476
    redisCluster *c, REDIS_SCAN_TYPE type, long *it);

477
/* INFO response handler */
478
PHP_REDIS_API void cluster_info_resp(INTERNAL_FUNCTION_PARAMETERS,
479
480
    redisCluster *c, void *ctx);

481
/* CLIENT LIST response handler */
Michael Grunder's avatar
Michael Grunder committed
482
483
484
485
486
487
488
489
490
PHP_REDIS_API void cluster_client_list_resp(INTERNAL_FUNCTION_PARAMETERS,
    redisCluster *c, void *ctx);

/* Custom STREAM handlers */
PHP_REDIS_API void cluster_xread_resp(INTERNAL_FUNCTION_PARAMETERS,
    redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_xrange_resp(INTERNAL_FUNCTION_PARAMETERS,
    redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_xclaim_resp(INTERNAL_FUNCTION_PARAMETERS,
491
    redisCluster *c, void *ctx);
Pavlo Yatsukhnenko's avatar
Pavlo Yatsukhnenko committed
492
493
PHP_REDIS_API void cluster_xinfo_resp(INTERNAL_FUNCTION_PARAMETERS,
    redisCluster *c, void *ctx);
494

495
/* MULTI BULK processing callbacks */
Michael Grunder's avatar
Michael Grunder committed
496
int mbulk_resp_loop(RedisSock *redis_sock, zval *z_result,
Remi Collet's avatar
Remi Collet committed
497
    long long count, void *ctx);
Michael Grunder's avatar
Michael Grunder committed
498
int mbulk_resp_loop_raw(RedisSock *redis_sock, zval *z_result,
Remi Collet's avatar
Remi Collet committed
499
    long long count, void *ctx);
500
int mbulk_resp_loop_zipstr(RedisSock *redis_sock, zval *z_result,
Remi Collet's avatar
Remi Collet committed
501
    long long count, void *ctx);
502
int mbulk_resp_loop_zipdbl(RedisSock *redis_sock, zval *z_result,
Remi Collet's avatar
Remi Collet committed
503
    long long count, void *ctx);
Michael Grunder's avatar
Michael Grunder committed
504
int mbulk_resp_loop_assoc(RedisSock *redis_sock, zval *z_result,
Remi Collet's avatar
Remi Collet committed
505
    long long count, void *ctx);
506

507
#endif
508

509
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */