hirlite 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE +28 -0
  3. data/Rakefile +51 -0
  4. data/ext/hirlite_ext/extconf.rb +33 -0
  5. data/ext/hirlite_ext/hirlite_ext.c +14 -0
  6. data/ext/hirlite_ext/hirlite_ext.h +38 -0
  7. data/ext/hirlite_ext/rlite.c +351 -0
  8. data/lib/hirlite/rlite.rb +1 -0
  9. data/lib/hirlite/version.rb +3 -0
  10. data/lib/hirlite.rb +2 -0
  11. data/vendor/rlite/Makefile +6 -0
  12. data/vendor/rlite/deps/crc64.c +191 -0
  13. data/vendor/rlite/deps/crc64.h +3 -0
  14. data/vendor/rlite/deps/endianconv.h +73 -0
  15. data/vendor/rlite/deps/hyperloglog.c +1547 -0
  16. data/vendor/rlite/deps/hyperloglog.h +14 -0
  17. data/vendor/rlite/deps/lzf.h +100 -0
  18. data/vendor/rlite/deps/lzfP.h +159 -0
  19. data/vendor/rlite/deps/lzf_c.c +295 -0
  20. data/vendor/rlite/deps/lzf_d.c +150 -0
  21. data/vendor/rlite/deps/sha1.c +227 -0
  22. data/vendor/rlite/deps/sha1.h +19 -0
  23. data/vendor/rlite/deps/utilfromredis.c +397 -0
  24. data/vendor/rlite/deps/utilfromredis.h +11 -0
  25. data/vendor/rlite/src/Makefile +79 -0
  26. data/vendor/rlite/src/constants.h +15 -0
  27. data/vendor/rlite/src/dump.c +191 -0
  28. data/vendor/rlite/src/dump.h +3 -0
  29. data/vendor/rlite/src/hirlite.c +3985 -0
  30. data/vendor/rlite/src/hirlite.h +186 -0
  31. data/vendor/rlite/src/page_btree.c +1556 -0
  32. data/vendor/rlite/src/page_btree.h +133 -0
  33. data/vendor/rlite/src/page_key.c +283 -0
  34. data/vendor/rlite/src/page_key.h +25 -0
  35. data/vendor/rlite/src/page_list.c +718 -0
  36. data/vendor/rlite/src/page_list.h +70 -0
  37. data/vendor/rlite/src/page_long.c +61 -0
  38. data/vendor/rlite/src/page_long.h +14 -0
  39. data/vendor/rlite/src/page_multi_string.c +538 -0
  40. data/vendor/rlite/src/page_multi_string.h +18 -0
  41. data/vendor/rlite/src/page_skiplist.c +689 -0
  42. data/vendor/rlite/src/page_skiplist.h +70 -0
  43. data/vendor/rlite/src/page_string.c +55 -0
  44. data/vendor/rlite/src/page_string.h +12 -0
  45. data/vendor/rlite/src/pqsort.c +185 -0
  46. data/vendor/rlite/src/pqsort.h +40 -0
  47. data/vendor/rlite/src/restore.c +401 -0
  48. data/vendor/rlite/src/restore.h +3 -0
  49. data/vendor/rlite/src/rlite.c +1309 -0
  50. data/vendor/rlite/src/rlite.h +159 -0
  51. data/vendor/rlite/src/sort.c +530 -0
  52. data/vendor/rlite/src/sort.h +18 -0
  53. data/vendor/rlite/src/status.h +19 -0
  54. data/vendor/rlite/src/type_hash.c +607 -0
  55. data/vendor/rlite/src/type_hash.h +29 -0
  56. data/vendor/rlite/src/type_list.c +477 -0
  57. data/vendor/rlite/src/type_list.h +23 -0
  58. data/vendor/rlite/src/type_set.c +796 -0
  59. data/vendor/rlite/src/type_set.h +34 -0
  60. data/vendor/rlite/src/type_string.c +613 -0
  61. data/vendor/rlite/src/type_string.h +34 -0
  62. data/vendor/rlite/src/type_zset.c +1147 -0
  63. data/vendor/rlite/src/type_zset.h +50 -0
  64. data/vendor/rlite/src/util.c +334 -0
  65. data/vendor/rlite/src/util.h +71 -0
  66. metadata +151 -0
@@ -0,0 +1,3985 @@
1
+ #include <stdio.h>
2
+ #include "constants.h"
3
+ #include <assert.h>
4
+ #include <errno.h>
5
+ #include <ctype.h>
6
+ #include <math.h>
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+ #include <strings.h>
10
+ #include <sys/time.h>
11
+ #include <time.h>
12
+ #include <unistd.h>
13
+
14
+ #include "../deps/hyperloglog.h"
15
+ #include "hirlite.h"
16
+ #include "util.h"
17
+
18
+ #define UNSIGN(val) ((unsigned char *)val)
19
+
20
+ #define RLITE_SERVER_ERR(c, retval)\
21
+ if (retval == RL_WRONG_TYPE) {\
22
+ c->reply = createErrorObject(RLITE_WRONGTYPEERR);\
23
+ goto cleanup;\
24
+ }\
25
+ if (retval == RL_OVERFLOW) {\
26
+ c->reply = createErrorObject("ERR increment would produce NaN or Infinity");\
27
+ return;\
28
+ }\
29
+ if (retval == RL_NAN) {\
30
+ c->reply = createErrorObject("ERR resulting score is not a number (NaN)");\
31
+ goto cleanup;\
32
+ }\
33
+
34
+ static struct rliteCommand *lookupCommand(const char *name, size_t UNUSED(len));
35
+ static void __rliteSetError(rliteContext *c, int type, const char *str);
36
+
37
+ static int catvprintf(char** s, size_t *slen, const char *fmt, va_list ap) {
38
+ va_list cpy;
39
+ char *buf, *t;
40
+ size_t buflen = 16;
41
+
42
+ while(1) {
43
+ buf = malloc(buflen);
44
+ if (buf == NULL) return RLITE_ERR;
45
+ buf[buflen-2] = '\0';
46
+ va_copy(cpy,ap);
47
+ vsnprintf(buf, buflen, fmt, cpy);
48
+ if (buf[buflen-2] != '\0') {
49
+ free(buf);
50
+ buflen *= 2;
51
+ continue;
52
+ }
53
+ break;
54
+ }
55
+ t = realloc(*s, sizeof(char) * (*slen + buflen));
56
+ if (!t) {
57
+ free(buf);
58
+ return RLITE_ERR;
59
+ }
60
+ memmove(&t[*slen], buf, buflen);
61
+ free(buf);
62
+ return RLITE_OK;
63
+ }
64
+
65
+ static rliteReply *createReplyObject(int type) {
66
+ rliteReply *r = calloc(1,sizeof(*r));
67
+
68
+ if (r == NULL)
69
+ return NULL;
70
+
71
+ r->type = type;
72
+ return r;
73
+ }
74
+
75
+ static rliteReply *createStringTypeObject(int type, const char *str, const int len) {
76
+ rliteReply *reply = createReplyObject(type);
77
+ reply->str = malloc(sizeof(char) * (len + 1));
78
+ if (!reply->str) {
79
+ rliteFreeReplyObject(reply);
80
+ return NULL;
81
+ }
82
+ memcpy(reply->str, str, len);
83
+ reply->str[len] = 0;
84
+ reply->len = len;
85
+ return reply;
86
+ }
87
+
88
+ static rliteReply *createStringObject(const char *str, const int len) {
89
+ return createStringTypeObject(RLITE_REPLY_STRING, str, len);
90
+ }
91
+
92
+ static rliteReply *createCStringObject(const char *str) {
93
+ return createStringObject(str, strlen(str));
94
+ }
95
+
96
+ static rliteReply *createErrorObject(const char *str) {
97
+ return createStringTypeObject(RLITE_REPLY_ERROR, str, strlen((char *)str));
98
+ }
99
+
100
+ static rliteReply *createStatusObject(const char *str) {
101
+ return createStringTypeObject(RLITE_REPLY_STATUS, str, strlen((char *)str));
102
+ }
103
+
104
+ static rliteReply *createDoubleObject(double d) {
105
+ char dbuf[128];
106
+ int dlen;
107
+ if (isinf(d)) {
108
+ /* Libc in odd systems (Hi Solaris!) will format infinite in a
109
+ * different way, so better to handle it in an explicit way. */
110
+ return createCStringObject(d > 0 ? "inf" : "-inf");
111
+ } else {
112
+ dlen = snprintf(dbuf,sizeof(dbuf),"%.17g",d);
113
+ return createStringObject(dbuf, dlen);
114
+ }
115
+ }
116
+
117
+ static rliteReply *createLongLongObject(long long value) {
118
+ rliteReply *reply = createReplyObject(RLITE_REPLY_INTEGER);
119
+ reply->integer = value;
120
+ return reply;
121
+ }
122
+
123
+ static void addZsetIteratorReply(rliteClient *c, int retval, rl_zset_iterator *iterator, int withscores)
124
+ {
125
+ unsigned char *vstr;
126
+ long vlen, i;
127
+ double score;
128
+
129
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
130
+ if (retval == RL_NOT_FOUND) {
131
+ c->reply->elements = 0;
132
+ return;
133
+ }
134
+ c->reply->elements = withscores ? (iterator->size * 2) : iterator->size;
135
+ c->reply->element = malloc(sizeof(rliteReply*) * c->reply->elements);
136
+ i = 0;
137
+ while ((retval = rl_zset_iterator_next(iterator, withscores ? &score : NULL, &vstr, &vlen)) == RL_OK) {
138
+ c->reply->element[i] = createStringObject((char *)vstr, vlen);
139
+ i++;
140
+ if (withscores) {
141
+ c->reply->element[i] = createDoubleObject(score);
142
+ i++;
143
+ }
144
+ rl_free(vstr);
145
+ }
146
+
147
+ if (retval != RL_END) {
148
+ __rliteSetError(c->context, RLITE_ERR, "Unexpected early end");
149
+ goto cleanup;
150
+ }
151
+ iterator = NULL;
152
+ cleanup:
153
+ if (iterator) {
154
+ rl_zset_iterator_destroy(iterator);
155
+ }
156
+ }
157
+
158
+ static int addReply(rliteContext* c, rliteReply *reply) {
159
+ if (c->replyPosition == c->replyAlloc) {
160
+ void *tmp;
161
+ c->replyAlloc *= 2;
162
+ tmp = realloc(c->replies, sizeof(rliteReply*) * c->replyAlloc);
163
+ if (!tmp) {
164
+ __rliteSetError(c,RLITE_ERR_OOM,"Out of memory");
165
+ return RLITE_ERR;
166
+ }
167
+ c->replies = tmp;
168
+ }
169
+
170
+ c->replies[c->replyPosition] = reply;
171
+ c->replyLength++;
172
+ return RLITE_OK;
173
+ }
174
+
175
+ static int addReplyStatusFormat(rliteContext *c, const char *fmt, ...) {
176
+ int maxlen = strlen(fmt) * 2;
177
+ char *str = malloc(maxlen * sizeof(char));
178
+ va_list ap;
179
+ va_start(ap, fmt);
180
+ int written = vsnprintf(str, maxlen, fmt, ap);
181
+ va_end(ap);
182
+ if (written < 0) {
183
+ fprintf(stderr, "Failed to vsnprintf near line %d, got %d\n", __LINE__, written);
184
+ free(str);
185
+ return RLITE_ERR;
186
+ }
187
+ rliteReply *reply = createReplyObject(RLITE_REPLY_STATUS);
188
+ if (!reply) {
189
+ free(str);
190
+ __rliteSetError(c,RLITE_ERR_OOM,"Out of memory");
191
+ return RLITE_ERR;
192
+ }
193
+ reply->str = str;
194
+ reply->len = written;
195
+ addReply(c, reply);
196
+ return RLITE_OK;
197
+ }
198
+
199
+ static int addReplyErrorFormat(rliteContext *c, const char *fmt, ...) {
200
+ int maxlen = strlen(fmt) * 2;
201
+ char *str = malloc(maxlen * sizeof(char));
202
+ va_list ap;
203
+ va_start(ap, fmt);
204
+ int written = vsnprintf(str, maxlen, fmt, ap);
205
+ va_end(ap);
206
+ if (written < 0) {
207
+ fprintf(stderr, "Failed to vsnprintf near line %d, got %d\n", __LINE__, written);
208
+ free(str);
209
+ return RLITE_ERR;
210
+ }
211
+ rliteReply *reply = createReplyObject(RLITE_REPLY_ERROR);
212
+ if (!reply) {
213
+ free(str);
214
+ __rliteSetError(c,RLITE_ERR_OOM,"Out of memory");
215
+ return RLITE_ERR;
216
+ }
217
+ reply->str = str;
218
+ reply->len = written;
219
+ addReply(c, reply);
220
+ return RLITE_OK;
221
+ }
222
+
223
+ static int getDoubleFromObject(const char *_o, long olen, double *target) {
224
+ double value;
225
+ char *eptr;
226
+ char o[64];
227
+
228
+ if (_o == NULL) {
229
+ *target = 0;
230
+ return RLITE_OK;
231
+ }
232
+ if (olen > 63) {
233
+ return RLITE_ERR;
234
+ }
235
+ memcpy(o, _o, olen * sizeof(char));
236
+ // valgrind likes to read 8 bytes at a time
237
+ memset(&o[olen], 0, 64 - olen);
238
+
239
+ errno = 0;
240
+ value = strtod(o, &eptr);
241
+ if (isspace(((char*)o)[0]) || eptr[0] != '\0' ||
242
+ (errno == ERANGE && (value == HUGE_VAL ||
243
+ value == -HUGE_VAL || value == 0)) ||
244
+ errno == EINVAL || isnan(value))
245
+ return RLITE_ERR;
246
+ *target = value;
247
+ return RLITE_OK;
248
+ }
249
+
250
+ static int getDoubleFromObjectOrReply(rliteClient *c, const char *o, long olen, double *target, const char *msg) {
251
+ if (getDoubleFromObject(o, olen, target) != RLITE_OK) {
252
+ if (msg != NULL) {
253
+ c->reply = createErrorObject(msg);
254
+ } else {
255
+ c->reply = createErrorObject("ERR value is not a valid float");
256
+ }
257
+ return RLITE_ERR;
258
+ }
259
+ return RLITE_OK;
260
+ }
261
+
262
+ static int getLongLongFromObject(const char *o, long long *target) {
263
+ long long value;
264
+ char *eptr;
265
+
266
+ if (o == NULL) {
267
+ value = 0;
268
+ } else {
269
+ errno = 0;
270
+ value = strtoll(o, &eptr, 10);
271
+ if (isspace(((char*)o)[0]) || eptr[0] != '\0' || errno == ERANGE) {
272
+ return RLITE_ERR;
273
+ }
274
+ }
275
+ if (target) *target = value;
276
+ return RLITE_OK;
277
+ }
278
+
279
+ static int getLongLongFromObjectOrReply(rliteClient *c, const char *o, long long *target, const char *msg) {
280
+ long long value;
281
+ if (getLongLongFromObject(o, &value) != RLITE_OK) {
282
+ if (msg != NULL) {
283
+ c->reply = createErrorObject(msg);
284
+ } else {
285
+ c->reply = createErrorObject("ERR value is not an integer or out of range");
286
+ }
287
+ return RLITE_ERR;
288
+ }
289
+ *target = value;
290
+ return RLITE_OK;
291
+ }
292
+
293
+ static int getLongFromObjectOrReply(rliteClient *c, const char *o, long *target, const char *msg) {
294
+ long long value;
295
+
296
+ if (getLongLongFromObjectOrReply(c, o, &value, msg) != RLITE_OK) return RLITE_ERR;
297
+ if (value < LONG_MIN || value > LONG_MAX) {
298
+ if (msg != NULL) {
299
+ c->reply = createErrorObject(msg);
300
+ } else {
301
+ c->reply = createErrorObject("ERR value is out of range");
302
+ }
303
+ return RLITE_ERR;
304
+ }
305
+ *target = value;
306
+ return RLITE_OK;
307
+ }
308
+ static void __rliteSetError(rliteContext *c, int type, const char *str) {
309
+ size_t len;
310
+
311
+ c->err = type;
312
+ if (str != NULL) {
313
+ len = strlen(str);
314
+ len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1);
315
+ memcpy(c->errstr,str,len);
316
+ c->errstr[len] = '\0';
317
+ } else {
318
+ /* Only RLITE_ERR_IO may lack a description! */
319
+ assert(type == RLITE_ERR_IO);
320
+ strerror_r(errno,c->errstr,sizeof(c->errstr));
321
+ }
322
+ }
323
+ /* Free a reply object */
324
+ void rliteFreeReplyObject(void *reply) {
325
+ rliteReply *r = reply;
326
+ size_t j;
327
+
328
+ if (r == NULL)
329
+ return;
330
+
331
+ switch(r->type) {
332
+ case RLITE_REPLY_INTEGER:
333
+ break; /* Nothing to free */
334
+ case RLITE_REPLY_ARRAY:
335
+ if (r->element != NULL) {
336
+ for (j = 0; j < r->elements; j++)
337
+ if (r->element[j] != NULL)
338
+ rliteFreeReplyObject(r->element[j]);
339
+ free(r->element);
340
+ }
341
+ break;
342
+ case RLITE_REPLY_ERROR:
343
+ case RLITE_REPLY_STATUS:
344
+ case RLITE_REPLY_STRING:
345
+ if (r->str != NULL)
346
+ free(r->str);
347
+ break;
348
+ }
349
+ free(r);
350
+ }
351
+
352
+ int rlitevFormatCommand(rliteClient *client, const char *format, va_list ap) {
353
+ const char *c = format;
354
+ char *curarg, *newarg; /* current argument */
355
+ size_t curarglen;
356
+ int touched = 0; /* was the current argument touched? */
357
+ char **curargv = NULL, **newargv = NULL;
358
+ size_t *curargvlen = NULL, *newargvlen = NULL;
359
+ int argc = 0;
360
+
361
+ /* Build the command string accordingly to protocol */
362
+ curarg = NULL;
363
+ curarglen = 0;
364
+
365
+ while(*c != '\0') {
366
+ if (*c != '%' || c[1] == '\0') {
367
+ if (*c == ' ') {
368
+ if (touched) {
369
+ newargv = realloc(curargv, sizeof(char*)*(argc+1));
370
+ if (newargv == NULL) goto err;
371
+ newargvlen = realloc(curargvlen, sizeof(size_t)*(argc+1));
372
+ if (newargvlen == NULL) goto err;
373
+ curargv = newargv;
374
+ curargvlen = newargvlen;
375
+ curargv[argc] = curarg;
376
+ curargvlen[argc++] = curarglen;
377
+
378
+ /* curarg is put in argv so it can be overwritten. */
379
+ curarg = NULL;
380
+ curarglen = 0;
381
+ touched = 0;
382
+ }
383
+ } else {
384
+ newarg = realloc(curarg, sizeof(char) * (curarglen + 1));
385
+ if (newarg == NULL) goto err;
386
+ newarg[curarglen++] = *c;
387
+ curarg = newarg;
388
+ touched = 1;
389
+ }
390
+ } else {
391
+ char *arg;
392
+ size_t size;
393
+
394
+ /* Set newarg so it can be checked even if it is not touched. */
395
+ newarg = curarg;
396
+
397
+ switch(c[1]) {
398
+ case 's':
399
+ arg = va_arg(ap,char*);
400
+ size = strlen(arg);
401
+ if (size > 0) {
402
+ newarg = realloc(curarg, sizeof(char) * (curarglen + size));
403
+ memcpy(&newarg[curarglen], arg, size);
404
+ curarglen += size;
405
+ }
406
+ break;
407
+ case 'b':
408
+ arg = va_arg(ap,char*);
409
+ size = va_arg(ap,size_t);
410
+ if (size > 0) {
411
+ newarg = realloc(curarg, sizeof(char) * (curarglen + size));
412
+ memcpy(&newarg[curarglen], arg, size);
413
+ curarglen += size;
414
+ }
415
+ break;
416
+ case '%':
417
+ newarg = realloc(curarg, sizeof(char) * (curarglen + 1));
418
+ newarg[curarglen] = '%';
419
+ curarglen += 1;
420
+ break;
421
+ default:
422
+ /* Try to detect printf format */
423
+ {
424
+ static const char intfmts[] = "diouxX";
425
+ char _format[16];
426
+ const char *_p = c+1;
427
+ size_t _l = 0;
428
+ va_list _cpy;
429
+
430
+ /* Flags */
431
+ if (*_p != '\0' && *_p == '#') _p++;
432
+ if (*_p != '\0' && *_p == '0') _p++;
433
+ if (*_p != '\0' && *_p == '-') _p++;
434
+ if (*_p != '\0' && *_p == ' ') _p++;
435
+ if (*_p != '\0' && *_p == '+') _p++;
436
+
437
+ /* Field width */
438
+ while (*_p != '\0' && isdigit(*_p)) _p++;
439
+
440
+ /* Precision */
441
+ if (*_p == '.') {
442
+ _p++;
443
+ while (*_p != '\0' && isdigit(*_p)) _p++;
444
+ }
445
+
446
+ /* Copy va_list before consuming with va_arg */
447
+ va_copy(_cpy,ap);
448
+
449
+ /* Integer conversion (without modifiers) */
450
+ if (strchr(intfmts,*_p) != NULL) {
451
+ va_arg(ap,int);
452
+ goto fmt_valid;
453
+ }
454
+
455
+ /* Double conversion (without modifiers) */
456
+ if (strchr("eEfFgGaA",*_p) != NULL) {
457
+ va_arg(ap,double);
458
+ goto fmt_valid;
459
+ }
460
+
461
+ /* Size: char */
462
+ if (_p[0] == 'h' && _p[1] == 'h') {
463
+ _p += 2;
464
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
465
+ va_arg(ap,int); /* char gets promoted to int */
466
+ goto fmt_valid;
467
+ }
468
+ goto fmt_invalid;
469
+ }
470
+
471
+ /* Size: short */
472
+ if (_p[0] == 'h') {
473
+ _p += 1;
474
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
475
+ va_arg(ap,int); /* short gets promoted to int */
476
+ goto fmt_valid;
477
+ }
478
+ goto fmt_invalid;
479
+ }
480
+
481
+ /* Size: long long */
482
+ if (_p[0] == 'l' && _p[1] == 'l') {
483
+ _p += 2;
484
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
485
+ va_arg(ap,long long);
486
+ goto fmt_valid;
487
+ }
488
+ goto fmt_invalid;
489
+ }
490
+
491
+ /* Size: long */
492
+ if (_p[0] == 'l') {
493
+ _p += 1;
494
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
495
+ va_arg(ap,long);
496
+ goto fmt_valid;
497
+ }
498
+ goto fmt_invalid;
499
+ }
500
+
501
+ fmt_invalid:
502
+ va_end(_cpy);
503
+ goto err;
504
+
505
+ fmt_valid:
506
+ _l = (_p+1)-c;
507
+ if (_l < sizeof(_format)-2) {
508
+ memcpy(_format,c,_l);
509
+ _format[_l] = '\0';
510
+ newarg = curarg;
511
+ if (RLITE_ERR == catvprintf(&newarg, &curarglen, _format,_cpy)) {
512
+ goto err;
513
+ }
514
+
515
+ c = _p-1;
516
+ }
517
+
518
+ va_end(_cpy);
519
+ break;
520
+ }
521
+ }
522
+
523
+ if (newarg == NULL) goto err;
524
+ curarg = newarg;
525
+
526
+ touched = 1;
527
+ c++;
528
+ }
529
+ c++;
530
+ }
531
+
532
+ /* Add the last argument if needed */
533
+ if (touched) {
534
+ newargv = realloc(curargv,sizeof(char*)*(argc+1));
535
+ if (newargv == NULL) goto err;
536
+ newargvlen = realloc(curargvlen,sizeof(char*)*(argc+1));
537
+ if (newargvlen == NULL) goto err;
538
+ curargv = newargv;
539
+ curargvlen = newargvlen;
540
+ curargv[argc] = curarg;
541
+ curargvlen[argc++] = curarglen;
542
+ } else {
543
+ free(curarg);
544
+ }
545
+
546
+ /* Clear curarg because it was put in curargv or was free'd. */
547
+ curarg = NULL;
548
+
549
+ client->argc = argc;
550
+ client->argv = curargv;
551
+ client->argvlen = curargvlen;
552
+ return RLITE_OK;
553
+ err:
554
+ while(argc--)
555
+ free(curargv[argc]);
556
+ free(curargv);
557
+
558
+ if (curarg != NULL)
559
+ free(curarg);
560
+
561
+ return RLITE_ERR;
562
+ }
563
+
564
+ int rliteFormatCommand(rliteClient *client, const char *format, ...) {
565
+ va_list ap;
566
+ int retval;
567
+ va_start(ap,format);
568
+ retval = rlitevFormatCommand(client, format, ap);
569
+ va_end(ap);
570
+ return retval;
571
+ }
572
+
573
+ int rliteFormatCommandArgv(rliteClient *client, int argc, char **argv, size_t *argvlen) {
574
+ client->argc = argc;
575
+ client->argv = argv;
576
+ client->argvlen = argvlen;
577
+ return RLITE_OK;
578
+ }
579
+
580
+ #define DEFAULT_REPLIES_SIZE 16
581
+ static rliteContext *_rliteConnect(const char *path) {
582
+ rliteContext *context = malloc(sizeof(*context));
583
+ if (!context) {
584
+ return NULL;
585
+ }
586
+ context->replies = malloc(sizeof(rliteReply*) * DEFAULT_REPLIES_SIZE);
587
+ if (!context->replies) {
588
+ free(context);
589
+ context = NULL;
590
+ goto cleanup;
591
+ }
592
+ context->writeCommand = NULL;
593
+ context->replyPosition = 0;
594
+ context->replyLength = 0;
595
+ context->replyAlloc = DEFAULT_REPLIES_SIZE;
596
+ context->debugSkiplist = 0;
597
+ context->hashtableLimitEntries = 0;
598
+ context->cluster_enabled = 0;
599
+ context->hashtableLimitValue = 0;
600
+ int retval = rl_open(path, &context->db, RLITE_OPEN_READWRITE | RLITE_OPEN_CREATE);
601
+ if (retval != RL_OK) {
602
+ free(context);
603
+ context = NULL;
604
+ goto cleanup;
605
+ }
606
+ context->inTransaction = 0;
607
+ context->transactionFailed = 0;
608
+ context->watchedKeysLength = context->enqueuedCommandsLength = 0;
609
+ context->watchedKeysAlloc = context->enqueuedCommandsAlloc = 0;
610
+ context->watchedKeys = NULL;
611
+ context->enqueuedCommands = NULL;
612
+ cleanup:
613
+ return context;
614
+ }
615
+
616
+ rliteContext *rliteConnect(const char *ip, int UNUSED(port)) {
617
+ return _rliteConnect(ip);
618
+ }
619
+
620
+ rliteContext *rliteConnectWithTimeout(const char *ip, int UNUSED(port), const struct timeval UNUSED(tv)) {
621
+ return _rliteConnect(ip);
622
+ }
623
+
624
+ rliteContext *rliteConnectNonBlock(const char *ip, int UNUSED(port)) {
625
+ return _rliteConnect(ip);
626
+ }
627
+
628
+ rliteContext *rliteConnectBindNonBlock(const char *ip, int UNUSED(port), const char *UNUSED(source_addr)) {
629
+ return _rliteConnect(ip);
630
+ }
631
+
632
+ rliteContext *rliteConnectUnix(const char *path) {
633
+ return _rliteConnect(path);
634
+ }
635
+
636
+ rliteContext *rliteConnectUnixWithTimeout(const char *path, const struct timeval UNUSED(tv)) {
637
+ return _rliteConnect(path);
638
+ }
639
+
640
+ rliteContext *rliteConnectUnixNonBlock(const char *path) {
641
+ return _rliteConnect(path);
642
+ }
643
+
644
+ rliteContext *rliteConnectFd(int UNUSED(fd)) {
645
+ return NULL;
646
+ }
647
+ int rliteSetTimeout(rliteContext *UNUSED(c), const struct timeval UNUSED(tv)) {
648
+ return 0;
649
+ }
650
+
651
+ int rliteEnableKeepAlive(rliteContext *UNUSED(c)) {
652
+ return 0;
653
+ }
654
+ void rliteFree(rliteContext *c) {
655
+ rl_close(c->db);
656
+ int i;
657
+ for (i = c->replyPosition; i < c->replyLength; i++) {
658
+ rliteFreeReplyObject(c->replies[i]);
659
+ }
660
+ free(c->replies);
661
+ free(c);
662
+ }
663
+
664
+ int rliteFreeKeepFd(rliteContext *UNUSED(c)) {
665
+ return 0;
666
+ }
667
+
668
+ int rliteBufferRead(rliteContext *UNUSED(c)) {
669
+ return 0;
670
+ }
671
+
672
+ int rliteBufferWrite(rliteContext *UNUSED(c), int *UNUSED(done)) {
673
+ return 0;
674
+ }
675
+
676
+ static void multiCommand(rliteClient *c) {
677
+ if (c->context->inTransaction) {
678
+ c->reply = createErrorObject("ERR MULTI calls can not be nested");
679
+ return;
680
+ }
681
+ c->context->inTransaction = 1;
682
+ c->context->transactionFailed = 0;
683
+ c->reply = createStatusObject(RLITE_STR_OK);
684
+ }
685
+
686
+ static void discard(rliteClient *c) {
687
+ size_t i;
688
+ int j;
689
+ for (i = 0; i < c->context->watchedKeysLength; i++) {
690
+ rl_free(c->context->watchedKeys[i]);
691
+ }
692
+ free(c->context->watchedKeys);
693
+ c->context->watchedKeys = NULL;
694
+ c->context->watchedKeysLength = 0;
695
+ c->context->watchedKeysAlloc = 0;
696
+
697
+ for (i = 0; i < c->context->enqueuedCommandsLength; i++) {
698
+ for (j = 0; j < c->context->enqueuedCommands[i]->argc; j++) {
699
+ free(c->context->enqueuedCommands[i]->argv[j]);
700
+ }
701
+ free(c->context->enqueuedCommands[i]->argv);
702
+ free(c->context->enqueuedCommands[i]->argvlen);
703
+ free(c->context->enqueuedCommands[i]);
704
+ }
705
+ free(c->context->enqueuedCommands);
706
+ c->context->enqueuedCommands = NULL;
707
+ c->context->enqueuedCommandsLength = 0;
708
+ c->context->enqueuedCommandsAlloc = 0;
709
+
710
+ c->context->inTransaction = 0;
711
+ c->context->transactionFailed = 0;
712
+ }
713
+
714
+ static void discardCommand(rliteClient *c) {
715
+ discard(c);
716
+ c->reply = createStatusObject(RLITE_STR_OK);
717
+ }
718
+
719
+ static void execCommand(rliteClient *c) {
720
+ short written = 0;
721
+ int retval;
722
+ size_t i;
723
+ unsigned char *oldhash = NULL, *newhash = NULL;
724
+ if (!c->context->inTransaction) {
725
+ c->reply = createErrorObject("ERR EXEC without MULTI");
726
+ return;
727
+ }
728
+ if (c->context->transactionFailed) {
729
+ c->reply = createErrorObject("EXECABORT Transaction discarded because of previous errors.");
730
+ goto cleanup;
731
+ }
732
+ retval = rl_check_watched_keys(c->context->db, c->context->watchedKeysLength, c->context->watchedKeys);
733
+ RLITE_SERVER_ERR(c, retval);
734
+ if (retval != RL_OK) {
735
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
736
+ goto cleanup;
737
+ }
738
+
739
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
740
+ if (retval == RL_NOT_FOUND) {
741
+ c->reply->elements = 0;
742
+ return;
743
+ }
744
+ c->reply->elements = c->context->enqueuedCommandsLength;
745
+ c->reply->element = malloc(sizeof(rliteReply*) * c->reply->elements);
746
+ rliteClient *client;
747
+ struct rliteCommand *command;
748
+ for (i = 0; i < c->reply->elements; i++) {
749
+ client = c->context->enqueuedCommands[i];
750
+ client->reply = NULL;
751
+ command = lookupCommand(client->argv[0], client->argvlen[0]);
752
+
753
+ if (client->context->writeCommand) {
754
+ RL_CALL(rl_dirty_hash, RL_OK, client->context->db, &oldhash);
755
+ }
756
+
757
+ command->proc(client);
758
+ c->reply->element[i] = client->reply;
759
+
760
+ if (client->context->writeCommand) {
761
+ if (!written) {
762
+ // ugly code warning!
763
+ // redis replication writes the multi/exec command when there
764
+ // is a write command, regardless any data is changed
765
+ int i;
766
+ for (i = strlen(command->sflags) - 1; i >= 0; i--) {
767
+ if (command->sflags[i] == 'w') {
768
+ char *argv[] = {"multi"};
769
+ size_t argvlen[] = {5};
770
+ c->context->writeCommand(c->context->db->selected_database, 1, argv, argvlen);
771
+ written = 1;
772
+ break;
773
+ }
774
+ }
775
+ }
776
+ RL_CALL(rl_dirty_hash, RL_OK, client->context->db, &newhash);
777
+ if (newhash && (!oldhash || memcmp(newhash, oldhash, 20) != 0)) {
778
+ client->context->writeCommand(client->context->db->selected_database, client->argc, client->argv, client->argvlen);
779
+ }
780
+ }
781
+ rl_free(oldhash);
782
+ rl_free(newhash);
783
+ oldhash = NULL;
784
+ newhash = NULL;
785
+ }
786
+
787
+ if (written) {
788
+ char *argv[] = {"exec"};
789
+ size_t argvlen[] = {4};
790
+ c->context->writeCommand(c->context->db->selected_database, 1, argv, argvlen);
791
+ }
792
+
793
+ retval = rl_commit(c->context->db);
794
+ RLITE_SERVER_ERR(c, retval);
795
+ if (retval != RL_OK) {
796
+ goto cleanup;
797
+ }
798
+
799
+ cleanup:
800
+ rl_free(oldhash);
801
+ rl_free(newhash);
802
+ discard(c);
803
+ return;
804
+ }
805
+
806
+ static void watchCommand(rliteClient *c) {
807
+ int retval;
808
+ void *tmp;
809
+ size_t newAlloc;
810
+ size_t i, watchc = c->argc - 1;
811
+ if (c->context->inTransaction) {
812
+ c->reply = createErrorObject("ERR WATCH inside MULTI is not allowed");
813
+ return;
814
+ }
815
+ if (watchc + c->context->watchedKeysLength > c->context->watchedKeysAlloc) {
816
+ newAlloc = c->context->watchedKeysAlloc ? c->context->watchedKeysAlloc : 4;
817
+ while (newAlloc < watchc + c->context->watchedKeysLength) {
818
+ newAlloc *= 2;
819
+ }
820
+ tmp = realloc(c->context->watchedKeys, sizeof(struct watched_key*) * newAlloc);
821
+ if (tmp == NULL) {
822
+ c->reply = NULL;
823
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
824
+ return;
825
+ }
826
+ c->context->watchedKeysAlloc = newAlloc;
827
+ c->context->watchedKeys = tmp;
828
+ }
829
+ for (i = 0; i < watchc; i++) {
830
+ retval = rl_watch(c->context->db, &c->context->watchedKeys[c->context->watchedKeysLength++], (unsigned char *)c->argv[1 + i], c->argvlen[1 + i]);
831
+ RLITE_SERVER_ERR(c, retval);
832
+ if (retval != RL_OK) {
833
+ goto cleanup;
834
+ }
835
+ }
836
+ retval = RL_OK;
837
+ c->reply = createStatusObject(RLITE_STR_OK);
838
+ cleanup:
839
+ if (retval != RL_OK) {
840
+ for (; ; i--) {
841
+ rl_free(c->context->watchedKeys[--c->context->watchedKeysLength]);
842
+ if (i == 0) {
843
+ break;
844
+ }
845
+ }
846
+ }
847
+ }
848
+
849
+ static void unwatchCommand(rliteClient *c) {
850
+ size_t i;
851
+ for (i = 0; i < c->context->watchedKeysLength; i++) {
852
+ rl_free(c->context->watchedKeys[i]);
853
+ }
854
+ free(c->context->watchedKeys);
855
+ c->context->watchedKeys = NULL;
856
+ c->context->watchedKeysLength = 0;
857
+ c->context->watchedKeysAlloc = 0;
858
+ c->reply = createStatusObject(RLITE_STR_OK);
859
+ }
860
+
861
+ static void *_popReply(rliteContext *c) {
862
+ if (c->replyPosition < c->replyLength) {
863
+ void *ret;
864
+ ret = c->replies[c->replyPosition];
865
+ c->replyPosition++;
866
+ if (c->replyPosition == c->replyLength) {
867
+ c->replyPosition = c->replyLength = 0;
868
+ }
869
+ return ret;
870
+ } else {
871
+ return NULL;
872
+ }
873
+ }
874
+
875
+ int rliteGetReply(rliteContext *c, void **reply) {
876
+ *reply = _popReply(c);
877
+ return RLITE_OK;
878
+ }
879
+
880
+ static void flagTransactions(rliteClient *c) {
881
+ if (c->context->inTransaction) {
882
+ c->context->transactionFailed = 1;
883
+ }
884
+ }
885
+
886
+ static int __rliteAppendCommandClient(rliteClient *client) {
887
+ if (client->argc == 0) {
888
+ return RLITE_ERR;
889
+ }
890
+
891
+ unsigned char *oldhash = NULL, *newhash = NULL;
892
+ void *tmp;
893
+ size_t newAlloc;
894
+ struct rliteCommand *command = lookupCommand(client->argv[0], client->argvlen[0]);
895
+ int i, retval = RLITE_OK;
896
+ if (!command) {
897
+ retval = addReplyErrorFormat(client->context, "unknown command '%s'", (char*)client->argv[0]);
898
+ flagTransactions(client);
899
+ } else if ((command->arity > 0 && command->arity != client->argc) ||
900
+ (client->argc < -command->arity)) {
901
+ retval = addReplyErrorFormat(client->context, "wrong number of arguments for '%s' command", command->name);
902
+ flagTransactions(client);
903
+ } else {
904
+ if (client->context->inTransaction && (command->proc != execCommand && command->proc != discardCommand &&
905
+ command->proc != multiCommand && command->proc != watchCommand)) {
906
+ if (client->context->enqueuedCommandsLength == client->context->enqueuedCommandsAlloc) {
907
+ newAlloc = client->context->enqueuedCommandsAlloc * 2;
908
+ if (newAlloc == 0) {
909
+ newAlloc = 4;
910
+ }
911
+ tmp = realloc(client->context->enqueuedCommands, sizeof(rliteClient *) * newAlloc);
912
+ if (!tmp) {
913
+ retval = RL_OUT_OF_MEMORY;
914
+ __rliteSetError(client->context, RLITE_ERR_OOM, "Out of memory");
915
+ goto cleanup;
916
+ }
917
+ client->context->enqueuedCommands = tmp;
918
+ client->context->enqueuedCommandsAlloc = newAlloc;
919
+ }
920
+ client->context->enqueuedCommands[client->context->enqueuedCommandsLength] = malloc(sizeof(rliteClient));
921
+ if (!client->context->enqueuedCommands[client->context->enqueuedCommandsLength]) {
922
+ retval = RL_OUT_OF_MEMORY;
923
+ __rliteSetError(client->context, RLITE_ERR_OOM, "Out of memory");
924
+ goto cleanup;
925
+ }
926
+ #define COMMAND client->context->enqueuedCommands[client->context->enqueuedCommandsLength]
927
+ COMMAND->argc = client->argc;
928
+ COMMAND->argvlen = malloc(sizeof(size_t) * client->argc);
929
+ COMMAND->argv = malloc(sizeof(char *) * client->argc);
930
+ for (i = 0; i < client->argc; i++) {
931
+ COMMAND->argvlen[i] = client->argvlen[i];
932
+ COMMAND->argv[i] = malloc(sizeof(char) * (client->argvlen[i] + 1));
933
+ memcpy(COMMAND->argv[i], client->argv[i], client->argvlen[i]);
934
+ COMMAND->argv[i][client->argvlen[i]] = 0;
935
+ }
936
+
937
+ client->context->enqueuedCommands[client->context->enqueuedCommandsLength]->context = client->context;
938
+ client->context->enqueuedCommandsLength++;
939
+ client->reply = createStatusObject(RLITE_QUEUED);
940
+ retval = addReply(client->context, client->reply);
941
+ } else {
942
+ client->reply = NULL;
943
+
944
+ if (client->context->writeCommand) {
945
+ RL_CALL(rl_dirty_hash, RL_OK, client->context->db, &oldhash);
946
+ }
947
+
948
+ command->proc(client);
949
+ if (client->reply) {
950
+ retval = addReply(client->context, client->reply);
951
+ }
952
+
953
+ if (client->context->writeCommand) {
954
+ RL_CALL(rl_dirty_hash, RL_OK, client->context->db, &newhash);
955
+ if (newhash && (!oldhash || memcmp(newhash, oldhash, 20) != 0)) {
956
+ client->context->writeCommand(client->context->db->selected_database, client->argc, client->argv, client->argvlen);
957
+ }
958
+ }
959
+ RL_CALL(rl_commit, RL_OK, client->context->db);
960
+ }
961
+ }
962
+ cleanup:
963
+ rl_free(oldhash);
964
+ rl_free(newhash);
965
+ return retval;
966
+ }
967
+
968
+ int rliteAppendFormattedCommand(rliteContext *UNUSED(c), const char *UNUSED(cmd), size_t UNUSED(len)) {
969
+ // Not implemented
970
+ // cmd is formatted for redis server, and we don't have a parser for it... yet.
971
+ return RLITE_ERR;
972
+ }
973
+
974
+ int rlitevAppendCommand(rliteContext *c, const char *format, va_list ap) {
975
+ rliteClient client;
976
+ client.context = c;
977
+ if (rlitevFormatCommand(&client, format, ap) != RLITE_OK) {
978
+ return RLITE_ERR;
979
+ }
980
+
981
+ int retval = __rliteAppendCommandClient(&client);
982
+ int i;
983
+ for (i = 0; i < client.argc; i++) {
984
+ free(client.argv[i]);
985
+ }
986
+ free(client.argv);
987
+ free(client.argvlen);
988
+
989
+ return retval;
990
+ }
991
+
992
+ int rliteAppendCommand(rliteContext *c, const char *format, ...) {
993
+ va_list ap;
994
+ int retval;
995
+ va_start(ap,format);
996
+ retval = rlitevAppendCommand(c, format, ap);
997
+ va_end(ap);
998
+ return retval;
999
+ }
1000
+
1001
+ int rliteAppendCommandArgv(rliteContext *c, int argc, char **argv, size_t *argvlen) {
1002
+ rliteClient client;
1003
+ client.context = c;
1004
+ client.argc = argc;
1005
+ client.argv = argv;
1006
+ client.argvlen = argvlen;
1007
+
1008
+ return __rliteAppendCommandClient(&client);
1009
+ }
1010
+
1011
+ void *rlitevCommand(rliteContext *c, const char *format, va_list ap) {
1012
+ if (rlitevAppendCommand(c,format,ap) != RLITE_OK)
1013
+ return NULL;
1014
+ return _popReply(c);
1015
+ }
1016
+
1017
+ void *rliteCommand(rliteContext *c, const char *format, ...) {
1018
+ va_list ap;
1019
+ void *reply = NULL;
1020
+ va_start(ap,format);
1021
+ reply = rlitevCommand(c,format,ap);
1022
+ va_end(ap);
1023
+ return reply;
1024
+ }
1025
+
1026
+ void *rliteCommandArgv(rliteContext *c, int argc, char **argv, size_t *argvlen) {
1027
+ if (rliteAppendCommandArgv(c,argc,argv,argvlen) != RLITE_OK)
1028
+ return NULL;
1029
+ return _popReply(c);
1030
+ }
1031
+
1032
+ static void echoCommand(rliteClient *c)
1033
+ {
1034
+ c->reply = createStringObject(c->argv[1], c->argvlen[1]);
1035
+ }
1036
+
1037
+ static void pingCommand(rliteClient *c)
1038
+ {
1039
+ if (c->argc == 2) {
1040
+ c->reply = createStringTypeObject(RLITE_REPLY_STATUS, c->argv[1], c->argvlen[1]);
1041
+ } else if (c->argc == 1) {
1042
+ c->reply = createStatusObject("PONG");
1043
+ } else {
1044
+ addReplyErrorFormat(c->context, RLITE_WRONGNUMBEROFARGUMENTS, c->argv[0]);
1045
+ }
1046
+ }
1047
+
1048
+ static void zaddGenericCommand(rliteClient *c, int incr) {
1049
+ const unsigned char *key = UNSIGN(c->argv[1]);
1050
+ size_t keylen = c->argvlen[1];
1051
+ double score = 0, *scores = NULL;
1052
+ int j, elements = (c->argc - 2) / 2;
1053
+ int added = 0;
1054
+
1055
+ if (c->argc % 2) {
1056
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
1057
+ return;
1058
+ }
1059
+
1060
+ /* Start parsing all the scores, we need to emit any syntax error
1061
+ * before executing additions to the sorted set, as the command should
1062
+ * either execute fully or nothing at all. */
1063
+ scores = malloc(sizeof(double) * elements);
1064
+ for (j = 0; j < elements; j++) {
1065
+ if (getDoubleFromObjectOrReply(c, c->argv[2+j*2], c->argvlen[2+j*2], &scores[j],NULL)
1066
+ != RLITE_OK) goto cleanup;
1067
+ }
1068
+
1069
+ int retval;
1070
+ for (j = 0; j < elements; j++) {
1071
+ score = scores[j];
1072
+ if (incr) {
1073
+ retval = rl_zincrby(c->context->db, key, keylen, score, UNSIGN(c->argv[3+j*2]), c->argvlen[3+j*2], NULL);
1074
+ RLITE_SERVER_ERR(c, retval);
1075
+ } else {
1076
+ retval = rl_zadd(c->context->db, key, keylen, score, UNSIGN(c->argv[3+j*2]), c->argvlen[3+j*2]);
1077
+ RLITE_SERVER_ERR(c, retval);
1078
+ if (retval == RL_OK) {
1079
+ added++;
1080
+ }
1081
+ }
1082
+ }
1083
+ if (incr) /* ZINCRBY */
1084
+ c->reply = createDoubleObject(score);
1085
+ else /* ZADD */
1086
+ c->reply = createLongLongObject(added);
1087
+
1088
+ cleanup:
1089
+ free(scores);
1090
+ }
1091
+
1092
+ static void zaddCommand(rliteClient *c) {
1093
+ zaddGenericCommand(c,0);
1094
+ }
1095
+
1096
+ static void zincrbyCommand(rliteClient *c) {
1097
+ zaddGenericCommand(c,1);
1098
+ }
1099
+
1100
+ static void zrangeGenericCommand(rliteClient *c, int reverse) {
1101
+ rl_zset_iterator *iterator;
1102
+ int withscores = 0;
1103
+ long start;
1104
+ long end;
1105
+
1106
+ if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != RLITE_OK) ||
1107
+ (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != RLITE_OK)) return;
1108
+
1109
+ if (c->argc == 5 && !strcasecmp(c->argv[4], "withscores")) {
1110
+ withscores = 1;
1111
+ } else if (c->argc >= 5) {
1112
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
1113
+ return;
1114
+ }
1115
+
1116
+ int retval = (reverse ? rl_zrevrange : rl_zrange)(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], start, end, &iterator);
1117
+ addZsetIteratorReply(c, retval, iterator, withscores);
1118
+ }
1119
+
1120
+ static void zrangeCommand(rliteClient *c) {
1121
+ zrangeGenericCommand(c, 0);
1122
+ }
1123
+
1124
+ static void zrevrangeCommand(rliteClient *c) {
1125
+ zrangeGenericCommand(c, 1);
1126
+ }
1127
+
1128
+ static void zremCommand(rliteClient *c) {
1129
+ const unsigned char *key = UNSIGN(c->argv[1]);
1130
+ const size_t keylen = c->argvlen[1];
1131
+ long deleted = 0;
1132
+ int j;
1133
+
1134
+ // memberslen needs long, we have size_t (unsigned long)
1135
+ // it would be great not to need this
1136
+ long *memberslen = malloc(sizeof(long) * (c->argc - 2));
1137
+ if (!memberslen) {
1138
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1139
+ goto cleanup;
1140
+ }
1141
+ for (j = 2; j < c->argc; j++) {
1142
+ memberslen[j - 2] = c->argvlen[j];
1143
+ }
1144
+ int retval = rl_zrem(c->context->db, key, keylen, c->argc - 2, (unsigned char **)&c->argv[2], memberslen, &deleted);
1145
+ free(memberslen);
1146
+ RLITE_SERVER_ERR(c, retval);
1147
+
1148
+ c->reply = createLongLongObject(deleted);
1149
+ cleanup:
1150
+ return;
1151
+ }
1152
+
1153
+ /* Populate the rangespec according to the objects min and max. */
1154
+ static int zslParseRange(const char *min, const char *max, rl_zrangespec *spec) {
1155
+ char *eptr;
1156
+ spec->minex = spec->maxex = 0;
1157
+
1158
+ /* Parse the min-max interval. If one of the values is prefixed
1159
+ * by the "(" character, it's considered "open". For instance
1160
+ * ZRANGEBYSCORE zset (1.5 (2.5 will match min < x < max
1161
+ * ZRANGEBYSCORE zset 1.5 2.5 will instead match min <= x <= max */
1162
+ if (min[0] == '(') {
1163
+ spec->min = strtod((char*)min+1,&eptr);
1164
+ if (eptr[0] != '\0' || isnan(spec->min)) return RLITE_ERR;
1165
+ spec->minex = 1;
1166
+ } else {
1167
+ spec->min = strtod((char*)min,&eptr);
1168
+ if (eptr[0] != '\0' || isnan(spec->min)) return RLITE_ERR;
1169
+ }
1170
+ if (((char*)max)[0] == '(') {
1171
+ spec->max = strtod((char*)max+1,&eptr);
1172
+ if (eptr[0] != '\0' || isnan(spec->max)) return RLITE_ERR;
1173
+ spec->maxex = 1;
1174
+ } else {
1175
+ spec->max = strtod((char*)max,&eptr);
1176
+ if (eptr[0] != '\0' || isnan(spec->max)) return RLITE_ERR;
1177
+ }
1178
+
1179
+ return RLITE_OK;
1180
+ }
1181
+ /* Implements ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZREMRANGEBYLEX commands. */
1182
+ #define ZRANGE_RANK 0
1183
+ #define ZRANGE_SCORE 1
1184
+ #define ZRANGE_LEX 2
1185
+ static void zremrangeGenericCommand(rliteClient *c, int rangetype) {
1186
+ int retval;
1187
+ long deleted;
1188
+ rl_zrangespec rlrange;
1189
+ long start, end;
1190
+
1191
+ /* Step 1: Parse the range. */
1192
+ if (rangetype == ZRANGE_RANK) {
1193
+ if ((getLongFromObjectOrReply(c,c->argv[2],&start,NULL) != RLITE_OK) ||
1194
+ (getLongFromObjectOrReply(c,c->argv[3],&end,NULL) != RLITE_OK))
1195
+ return;
1196
+ retval = rl_zremrangebyrank(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], start, end, &deleted);
1197
+ } else if (rangetype == ZRANGE_SCORE) {
1198
+ if (zslParseRange(c->argv[2],c->argv[3],&rlrange) != RLITE_OK) {
1199
+ c->reply = createErrorObject("ERR min or max is not a float");
1200
+ return;
1201
+ }
1202
+ retval = rl_zremrangebyscore(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], &rlrange, &deleted);
1203
+ } else if (rangetype == ZRANGE_LEX) {
1204
+ retval = rl_zremrangebylex(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], UNSIGN(c->argv[2]), c->argvlen[2], UNSIGN(c->argv[3]), c->argvlen[3], &deleted);
1205
+ } else {
1206
+ __rliteSetError(c->context, RLITE_ERR, "Unexpected rangetype");
1207
+ goto cleanup;
1208
+ }
1209
+ RLITE_SERVER_ERR(c, retval);
1210
+
1211
+ c->reply = createLongLongObject(deleted);
1212
+ cleanup:
1213
+ return;
1214
+ }
1215
+
1216
+ static void zremrangebyrankCommand(rliteClient *c) {
1217
+ zremrangeGenericCommand(c,ZRANGE_RANK);
1218
+ }
1219
+
1220
+ static void zremrangebyscoreCommand(rliteClient *c) {
1221
+ zremrangeGenericCommand(c,ZRANGE_SCORE);
1222
+ }
1223
+
1224
+ static void zremrangebylexCommand(rliteClient *c) {
1225
+ zremrangeGenericCommand(c,ZRANGE_LEX);
1226
+ }
1227
+
1228
+ static void zcardCommand(rliteClient *c) {
1229
+ long card = 0;
1230
+ int retval = rl_zcard(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], &card);
1231
+ RLITE_SERVER_ERR(c, retval);
1232
+ c->reply = createLongLongObject(card);
1233
+ cleanup:
1234
+ return;
1235
+ }
1236
+ #define RLITE_AGGR_SUM 1
1237
+ #define RLITE_AGGR_MIN 2
1238
+ #define RLITE_AGGR_MAX 3
1239
+ #define RLITE_OP_UNION 1
1240
+ #define RLITE_OP_INTER 2
1241
+
1242
+ static void zunionInterGenericCommand(rliteClient *c, int op) {
1243
+ int i, j;
1244
+ long setnum;
1245
+ int aggregate = RL_ZSET_AGGREGATE_SUM;
1246
+ double *weights = NULL;
1247
+
1248
+ /* expect setnum input keys to be given */
1249
+ if ((getLongFromObjectOrReply(c, c->argv[2], &setnum, NULL) != RLITE_OK))
1250
+ return;
1251
+
1252
+ if (setnum < 1) {
1253
+ c->reply = createErrorObject("ERR at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE");
1254
+ return;
1255
+ }
1256
+
1257
+ /* test if the expected number of keys would overflow */
1258
+ if (setnum > c->argc - 3) {
1259
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
1260
+ return;
1261
+ }
1262
+
1263
+ if (c->argc > 3 + setnum) {
1264
+ j = 3 + setnum;
1265
+ if (strcasecmp(c->argv[j], "weights") == 0) {
1266
+ if (j + 1 + setnum > c->argc) {
1267
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
1268
+ return;
1269
+ }
1270
+ weights = malloc(sizeof(double) * setnum);
1271
+ for (i = 0; i < setnum; i++) {
1272
+ if (getDoubleFromObjectOrReply(c,c->argv[j + 1 + i],c->argvlen[j + 1 + i], &weights[i],
1273
+ "weight value is not a float") != RLITE_OK) {
1274
+ free(weights);
1275
+ return;
1276
+ }
1277
+ }
1278
+ j += setnum + 1;
1279
+ }
1280
+ if (c->argc > j && c->argvlen[j] == 9 && memcmp(c->argv[j], "aggregate", 9) == 0) {
1281
+ if (strcasecmp(c->argv[j + 1], "min") == 0) {
1282
+ aggregate = RL_ZSET_AGGREGATE_MIN;
1283
+ } else if (strcasecmp(c->argv[j + 1], "max") == 0) {
1284
+ aggregate = RL_ZSET_AGGREGATE_MAX;
1285
+ } else if (strcasecmp(c->argv[j + 1], "sum") == 0) {
1286
+ aggregate = RL_ZSET_AGGREGATE_SUM;
1287
+ } else {
1288
+ free(weights);
1289
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
1290
+ return;
1291
+ }
1292
+ j += 2;
1293
+ }
1294
+ if (j != c->argc) {
1295
+ free(weights);
1296
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
1297
+ return;
1298
+ }
1299
+ }
1300
+
1301
+ unsigned char **keys = malloc(sizeof(unsigned char *) * (1 + setnum));
1302
+ long *keys_len = malloc(sizeof(long) * (1 + setnum));
1303
+ keys[0] = UNSIGN(c->argv[1]);
1304
+ keys_len[0] = (long)c->argvlen[1];
1305
+ for (i = 0; i < setnum; i++) {
1306
+ keys[i + 1] = UNSIGN(c->argv[3 + i]);
1307
+ keys_len[i + 1] = c->argvlen[3 + i];
1308
+ }
1309
+ int retval = (op == RLITE_OP_UNION ? rl_zunionstore : rl_zinterstore)(c->context->db, setnum + 1, keys, keys_len, weights, aggregate);
1310
+ free(keys);
1311
+ free(keys_len);
1312
+ free(weights);
1313
+ RLITE_SERVER_ERR(c, retval);
1314
+ zcardCommand(c);
1315
+ cleanup:
1316
+ return;
1317
+ }
1318
+
1319
+ static void zunionstoreCommand(rliteClient *c) {
1320
+ zunionInterGenericCommand(c, RLITE_OP_UNION);
1321
+ }
1322
+
1323
+ static void zinterstoreCommand(rliteClient *c) {
1324
+ zunionInterGenericCommand(c, RLITE_OP_INTER);
1325
+ }
1326
+
1327
+ /* This command implements ZRANGEBYSCORE, ZREVRANGEBYSCORE. */
1328
+ static void genericZrangebyscoreCommand(rliteClient *c, int reverse) {
1329
+ rl_zrangespec range;
1330
+ long offset = 0, limit = -1;
1331
+ int withscores = 0;
1332
+ int minidx, maxidx;
1333
+
1334
+ /* Parse the range arguments. */
1335
+ if (reverse) {
1336
+ /* Range is given as [max,min] */
1337
+ maxidx = 2; minidx = 3;
1338
+ } else {
1339
+ /* Range is given as [min,max] */
1340
+ minidx = 2; maxidx = 3;
1341
+ }
1342
+
1343
+ if (zslParseRange(c->argv[minidx],c->argv[maxidx],&range) != RLITE_OK) {
1344
+ c->reply = createErrorObject("ERR min or max is not a float");
1345
+ return;
1346
+ }
1347
+
1348
+ /* Parse optional extra arguments. Note that ZCOUNT will exactly have
1349
+ * 4 arguments, so we'll never enter the following code path. */
1350
+ if (c->argc > 4) {
1351
+ int remaining = c->argc - 4;
1352
+ int pos = 4;
1353
+
1354
+ while (remaining) {
1355
+ if (remaining >= 1 && !strcasecmp(c->argv[pos],"withscores")) {
1356
+ pos++; remaining--;
1357
+ withscores = 1;
1358
+ } else if (remaining >= 3 && !strcasecmp(c->argv[pos],"limit")) {
1359
+ if ((getLongFromObjectOrReply(c, c->argv[pos+1], &offset, NULL) != RLITE_OK) ||
1360
+ (getLongFromObjectOrReply(c, c->argv[pos+2], &limit, NULL) != RLITE_OK)) return;
1361
+ pos += 3; remaining -= 3;
1362
+ } else {
1363
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
1364
+ return;
1365
+ }
1366
+ }
1367
+ }
1368
+
1369
+ rl_zset_iterator *iterator;
1370
+ int retval = (reverse ? rl_zrevrangebyscore : rl_zrangebyscore)(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], &range, offset, limit, &iterator);
1371
+ addZsetIteratorReply(c, retval, iterator, withscores);
1372
+ }
1373
+
1374
+ static void zrangebyscoreCommand(rliteClient *c) {
1375
+ genericZrangebyscoreCommand(c, 0);
1376
+ }
1377
+
1378
+ static void zrevrangebyscoreCommand(rliteClient *c) {
1379
+ genericZrangebyscoreCommand(c, 1);
1380
+ }
1381
+
1382
+ static void zlexcountCommand(rliteClient *c) {
1383
+ long count = 0;
1384
+
1385
+ int retval = rl_zlexcount(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], UNSIGN(c->argv[2]), c->argvlen[2], UNSIGN(c->argv[3]), c->argvlen[3], &count);
1386
+ RLITE_SERVER_ERR(c, retval);
1387
+ if (retval == RL_NOT_FOUND) {
1388
+ count = 0;
1389
+ }
1390
+ c->reply = createLongLongObject(count);
1391
+ cleanup:
1392
+ return;
1393
+ }
1394
+
1395
+ /* This command implements ZRANGEBYLEX, ZREVRANGEBYLEX. */
1396
+ static void genericZrangebylexCommand(rliteClient *c, int reverse) {
1397
+ rl_zset_iterator *iterator;
1398
+ long offset = 0, limit = -1;
1399
+
1400
+ if (c->argc > 4) {
1401
+ int remaining = c->argc - 4;
1402
+ int pos = 4;
1403
+
1404
+ while (remaining) {
1405
+ if (remaining >= 3 && !strcasecmp(c->argv[pos],"limit")) {
1406
+ if ((getLongFromObjectOrReply(c, c->argv[pos+1], &offset, NULL) != RLITE_OK) ||
1407
+ (getLongFromObjectOrReply(c, c->argv[pos+2], &limit, NULL) != RLITE_OK)) return;
1408
+ pos += 3; remaining -= 3;
1409
+ } else {
1410
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
1411
+ return;
1412
+ }
1413
+ }
1414
+ }
1415
+
1416
+ int retval = (reverse ? rl_zrevrangebylex : rl_zrangebylex)(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], UNSIGN(c->argv[2]), c->argvlen[2], UNSIGN(c->argv[3]), c->argvlen[3], offset, limit, &iterator);
1417
+ if (retval == RL_UNEXPECTED) {
1418
+ c->reply = createErrorObject(RLITE_INVALIDMINMAXERR);
1419
+ } else {
1420
+ addZsetIteratorReply(c, retval, iterator, 0);
1421
+ }
1422
+ }
1423
+
1424
+ static void zrangebylexCommand(rliteClient *c) {
1425
+ genericZrangebylexCommand(c,0);
1426
+ }
1427
+
1428
+ static void zrevrangebylexCommand(rliteClient *c) {
1429
+ genericZrangebylexCommand(c,1);
1430
+ }
1431
+
1432
+ static void zscoreCommand(rliteClient *c) {
1433
+ double score;
1434
+
1435
+ int retval = rl_zscore(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], UNSIGN(c->argv[2]), c->argvlen[2], &score);
1436
+ RLITE_SERVER_ERR(c, retval);
1437
+
1438
+ if (retval == RL_FOUND) {
1439
+ c->reply = createDoubleObject(score);
1440
+ } else if (retval == RL_NOT_FOUND) {
1441
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
1442
+ }
1443
+
1444
+ cleanup:
1445
+ return;
1446
+ }
1447
+
1448
+ static void zrankGenericCommand(rliteClient *c, int reverse) {
1449
+ long rank;
1450
+
1451
+ int retval = (reverse ? rl_zrevrank : rl_zrank)(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], UNSIGN(c->argv[2]), c->argvlen[2], &rank);
1452
+ RLITE_SERVER_ERR(c, retval);
1453
+
1454
+ if (retval == RL_NOT_FOUND) {
1455
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
1456
+ } else if (retval == RL_FOUND) {
1457
+ c->reply = createLongLongObject(rank);
1458
+ }
1459
+ cleanup:
1460
+ return;
1461
+ }
1462
+
1463
+ static void zrankCommand(rliteClient *c) {
1464
+ zrankGenericCommand(c, 0);
1465
+ }
1466
+
1467
+ static void zrevrankCommand(rliteClient *c) {
1468
+ zrankGenericCommand(c, 1);
1469
+ }
1470
+
1471
+ static void zcountCommand(rliteClient *c) {
1472
+ rl_zrangespec rlrange;
1473
+ long count;
1474
+
1475
+ /* Parse the range arguments */
1476
+ if (zslParseRange(c->argv[2],c->argv[3],&rlrange) != RLITE_OK) {
1477
+ c->reply = createErrorObject("ERR min or max is not a float");
1478
+ return;
1479
+ }
1480
+
1481
+ int retval = rl_zcount(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], &rlrange, &count);
1482
+ RLITE_SERVER_ERR(c, retval);
1483
+ if (retval == RL_NOT_FOUND) {
1484
+ count = 0;
1485
+ }
1486
+ c->reply = createLongLongObject(count);
1487
+ cleanup:
1488
+ return;
1489
+ }
1490
+
1491
+ static void hsetGenericCommand(rliteClient *c, int update) {
1492
+ unsigned char *key = UNSIGN(c->argv[1]);
1493
+ size_t keylen = c->argvlen[1];
1494
+ unsigned char *field = UNSIGN(c->argv[2]);
1495
+ size_t fieldlen = c->argvlen[2];
1496
+ unsigned char *value = UNSIGN(c->argv[3]);
1497
+ size_t valuelen = c->argvlen[3];
1498
+ long added;
1499
+
1500
+ int retval;
1501
+ retval = rl_hset(c->context->db, key, keylen, field, fieldlen, value, valuelen, &added, update);
1502
+ RLITE_SERVER_ERR(c, retval);
1503
+ c->reply = createLongLongObject(added);
1504
+
1505
+ cleanup:
1506
+ return;
1507
+ }
1508
+
1509
+ static void hsetCommand(rliteClient *c) {
1510
+ hsetGenericCommand(c, 1);
1511
+ }
1512
+
1513
+ static void hsetnxCommand(rliteClient *c) {
1514
+ hsetGenericCommand(c, 0);
1515
+ }
1516
+
1517
+ static void hgetCommand(rliteClient *c) {
1518
+ unsigned char *key = UNSIGN(c->argv[1]);
1519
+ size_t keylen = c->argvlen[1];
1520
+ unsigned char *field = UNSIGN(c->argv[2]);
1521
+ size_t fieldlen = c->argvlen[2];
1522
+ unsigned char *value = NULL;
1523
+ long valuelen;
1524
+
1525
+ int retval;
1526
+ retval = rl_hget(c->context->db, key, keylen, field, fieldlen, &value, &valuelen);
1527
+ RLITE_SERVER_ERR(c, retval);
1528
+ if (retval == RL_NOT_FOUND) {
1529
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
1530
+ } else {
1531
+ c->reply = createStringObject((char *)value, valuelen);
1532
+ }
1533
+
1534
+ rl_free(value);
1535
+ cleanup:
1536
+ return;
1537
+ }
1538
+
1539
+ static void hexistsCommand(rliteClient *c) {
1540
+ unsigned char *key = UNSIGN(c->argv[1]);
1541
+ size_t keylen = c->argvlen[1];
1542
+ unsigned char *field = UNSIGN(c->argv[2]);
1543
+ size_t fieldlen = c->argvlen[2];
1544
+
1545
+ int retval;
1546
+ retval = rl_hget(c->context->db, key, keylen, field, fieldlen, NULL, NULL);
1547
+ RLITE_SERVER_ERR(c, retval);
1548
+ c->reply = createLongLongObject(retval == RL_NOT_FOUND ? 0 : 1);
1549
+ cleanup:
1550
+ return;
1551
+ }
1552
+
1553
+ static void hmsetCommand(rliteClient *c) {
1554
+ unsigned char *key = UNSIGN(c->argv[1]);
1555
+ size_t keylen = c->argvlen[1];
1556
+
1557
+ int i, j, retval;
1558
+ if (c->argc % 2) {
1559
+ addReplyErrorFormat(c->context, RLITE_WRONGNUMBEROFARGUMENTS, c->argv[0]);
1560
+ return;
1561
+ }
1562
+
1563
+ int fieldc = (c->argc - 2) / 2;
1564
+ unsigned char **fields = NULL;
1565
+ long *fieldslen = NULL;
1566
+ unsigned char **values = NULL;
1567
+ long *valueslen = NULL;
1568
+
1569
+ fields = malloc(sizeof(unsigned char *) * fieldc);
1570
+ if (!fields) {
1571
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1572
+ goto cleanup;
1573
+ }
1574
+ fieldslen = malloc(sizeof(long) * fieldc);
1575
+ if (!fieldslen) {
1576
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1577
+ goto cleanup;
1578
+ }
1579
+ values = malloc(sizeof(unsigned char *) * fieldc);
1580
+ if (!values) {
1581
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1582
+ goto cleanup;
1583
+ }
1584
+ valueslen = malloc(sizeof(long) * fieldc);
1585
+ if (!valueslen) {
1586
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1587
+ goto cleanup;
1588
+ }
1589
+ for (i = 0, j = 2; i < fieldc; i++) {
1590
+ fields[i] = UNSIGN(c->argv[j]);
1591
+ fieldslen[i] = c->argvlen[j++];
1592
+ values[i] = UNSIGN(c->argv[j]);
1593
+ valueslen[i] = c->argvlen[j++];
1594
+ }
1595
+ retval = rl_hmset(c->context->db, key, keylen, fieldc, fields, fieldslen, values, valueslen);
1596
+ RLITE_SERVER_ERR(c, retval);
1597
+ c->reply = createStatusObject(RLITE_STR_OK);
1598
+ cleanup:
1599
+ free(fields);
1600
+ free(fieldslen);
1601
+ free(values);
1602
+ free(valueslen);
1603
+ return;
1604
+ }
1605
+
1606
+ static void bitcountCommand(rliteClient *c) {
1607
+ unsigned char *key = UNSIGN(c->argv[1]);
1608
+ long keylen = c->argvlen[1];
1609
+ long start = 0, stop = -1;
1610
+ int retval;
1611
+ long bitcount;
1612
+
1613
+ if (c->argc != 2 && c->argc != 4) {
1614
+ addReplyErrorFormat(c->context, RLITE_SYNTAXERR, c->argv[0]);
1615
+ return;
1616
+ }
1617
+
1618
+ if (c->argc == 4) {
1619
+ if (getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != RLITE_OK ||
1620
+ getLongFromObjectOrReply(c, c->argv[3], &stop, NULL) != RLITE_OK)
1621
+ return;
1622
+ }
1623
+
1624
+ retval = rl_bitcount(c->context->db, key, keylen, start, stop, &bitcount);
1625
+ RLITE_SERVER_ERR(c, retval);
1626
+ if (retval == RL_NOT_FOUND) {
1627
+ c->reply = createLongLongObject(0);
1628
+ } else if (retval == RL_OK) {
1629
+ c->reply = createLongLongObject(bitcount);
1630
+ }
1631
+ cleanup:
1632
+ return;
1633
+ }
1634
+
1635
+ static void bitopCommand(rliteClient *c) {
1636
+ unsigned char *destkey = UNSIGN(c->argv[2]);
1637
+ long destkeylen = c->argvlen[2];
1638
+ char *opname = c->argv[1];
1639
+ int op, retval;
1640
+ long j, length;
1641
+
1642
+ /* Parse the operation name. */
1643
+ if ((opname[0] == 'a' || opname[0] == 'A') && !strcasecmp(opname,"and"))
1644
+ op = BITOP_AND;
1645
+ else if((opname[0] == 'o' || opname[0] == 'O') && !strcasecmp(opname,"or"))
1646
+ op = BITOP_OR;
1647
+ else if((opname[0] == 'x' || opname[0] == 'X') && !strcasecmp(opname,"xor"))
1648
+ op = BITOP_XOR;
1649
+ else if((opname[0] == 'n' || opname[0] == 'N') && !strcasecmp(opname,"not"))
1650
+ op = BITOP_NOT;
1651
+ else {
1652
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
1653
+ return;
1654
+ }
1655
+
1656
+ /* Sanity check: NOT accepts only a single key argument. */
1657
+ if (op == BITOP_NOT && c->argc != 4) {
1658
+ c->reply = createErrorObject("ERR BITOP NOT must be called with a single source key.");
1659
+ return;
1660
+ }
1661
+
1662
+ long *memberslen = malloc(sizeof(long) * (c->argc - 2));
1663
+ if (!memberslen) {
1664
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1665
+ goto cleanup;
1666
+ }
1667
+ for (j = 3; j < c->argc; j++) {
1668
+ memberslen[j - 3] = c->argvlen[j];
1669
+ }
1670
+
1671
+ retval = rl_bitop(c->context->db, op, destkey, destkeylen, c->argc - 3, (const unsigned char **)&c->argv[3], memberslen);
1672
+ free(memberslen);
1673
+ RLITE_SERVER_ERR(c, retval);
1674
+
1675
+ retval = rl_get(c->context->db, destkey, destkeylen, NULL, &length);
1676
+ RLITE_SERVER_ERR(c, retval);
1677
+ if (retval == RL_OK) {
1678
+ c->reply = createLongLongObject(length);
1679
+ }
1680
+ cleanup:
1681
+ return;
1682
+ }
1683
+
1684
+ static void bitposCommand(rliteClient *c) {
1685
+ unsigned char *key = UNSIGN(c->argv[1]);
1686
+ long keylen = c->argvlen[1];
1687
+ long start = 0, stop = -1;
1688
+ int retval;
1689
+ int bit;
1690
+ long pos;
1691
+
1692
+ if (c->argc != 3 && c->argc != 4 && c->argc != 5) {
1693
+ addReplyErrorFormat(c->context, RLITE_WRONGNUMBEROFARGUMENTS, c->argv[0]);
1694
+ return;
1695
+ }
1696
+
1697
+ if (c->argvlen[2] != 1 || (c->argv[2][0] != '0' && c->argv[2][0] != '1')) {
1698
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
1699
+ return;
1700
+ }
1701
+ bit = c->argv[2][0] == '0' ? 0 : 1;
1702
+
1703
+ if (c->argc >= 4) {
1704
+ if (getLongFromObjectOrReply(c, c->argv[3], &start, NULL) != RLITE_OK)
1705
+ return;
1706
+ }
1707
+
1708
+ int end_given = 0;
1709
+ if (c->argc == 5) {
1710
+ end_given = 1;
1711
+ if (getLongFromObjectOrReply(c, c->argv[4], &stop, NULL) != RLITE_OK)
1712
+ return;
1713
+ }
1714
+
1715
+ retval = rl_bitpos(c->context->db, key, keylen, bit, start, stop, end_given, &pos);
1716
+ RLITE_SERVER_ERR(c, retval);
1717
+ if (retval == RL_OK) {
1718
+ c->reply = createLongLongObject(pos);
1719
+ } else if (retval == RL_NOT_FOUND) {
1720
+ if (bit == 0) {
1721
+ c->reply = createLongLongObject(0);
1722
+ } else {
1723
+ c->reply = createLongLongObject(-1);
1724
+ }
1725
+ }
1726
+ cleanup:
1727
+ return;
1728
+ }
1729
+
1730
+ static void hdelCommand(rliteClient *c) {
1731
+ unsigned char *key = UNSIGN(c->argv[1]);
1732
+ size_t keylen = c->argvlen[1];
1733
+ long delcount = 0;
1734
+
1735
+ int j, retval;
1736
+ // memberslen needs long, we have size_t (unsigned long)
1737
+ // it would be great not to need this
1738
+ long *memberslen = malloc(sizeof(long) * (c->argc - 2));
1739
+ if (!memberslen) {
1740
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1741
+ goto cleanup;
1742
+ }
1743
+ for (j = 2; j < c->argc; j++) {
1744
+ memberslen[j - 2] = c->argvlen[j];
1745
+ }
1746
+ retval = rl_hdel(c->context->db, key, keylen, c->argc - 2, (unsigned char **)&c->argv[2], memberslen, &delcount);
1747
+ free(memberslen);
1748
+ RLITE_SERVER_ERR(c, retval);
1749
+ c->reply = createLongLongObject(delcount);
1750
+ cleanup:
1751
+ return;
1752
+ }
1753
+
1754
+ static void hlenCommand(rliteClient *c) {
1755
+ unsigned char *key = UNSIGN(c->argv[1]);
1756
+ size_t keylen = c->argvlen[1];
1757
+ long len;
1758
+ int retval;
1759
+
1760
+ retval = rl_hlen(c->context->db, key, keylen, &len);
1761
+ RLITE_SERVER_ERR(c, retval);
1762
+ c->reply = createLongLongObject(len);
1763
+ cleanup:
1764
+ return;
1765
+ }
1766
+
1767
+ static void hincrbyCommand(rliteClient *c) {
1768
+ unsigned char *key = UNSIGN(c->argv[1]);
1769
+ size_t keylen = c->argvlen[1];
1770
+ int retval;
1771
+ long increment, newvalue;
1772
+
1773
+ if ((getLongFromObjectOrReply(c, c->argv[3], &increment, NULL) != RLITE_OK)) return;
1774
+
1775
+ retval = rl_hincrby(c->context->db, key, keylen, UNSIGN(c->argv[2]), c->argvlen[2], increment, &newvalue);
1776
+ if (retval == RL_NAN) {
1777
+ c->reply = createErrorObject("ERR hash value is not an integer");
1778
+ goto cleanup;
1779
+ }
1780
+ else if (retval == RL_OVERFLOW) {
1781
+ c->reply = createErrorObject("ERR increment or decrement would overflow");
1782
+ goto cleanup;
1783
+ }
1784
+ RLITE_SERVER_ERR(c, retval);
1785
+ c->reply = createLongLongObject(newvalue);
1786
+ cleanup:
1787
+ return;
1788
+ }
1789
+
1790
+ static void hincrbyfloatCommand(rliteClient *c) {
1791
+ unsigned char *key = UNSIGN(c->argv[1]);
1792
+ size_t keylen = c->argvlen[1];
1793
+ int retval;
1794
+ double increment, newvalue;
1795
+
1796
+ if ((getDoubleFromObjectOrReply(c, c->argv[3], c->argvlen[3], &increment, NULL) != RLITE_OK)) return;
1797
+
1798
+ retval = rl_hincrbyfloat(c->context->db, key, keylen, UNSIGN(c->argv[2]), c->argvlen[2], increment, &newvalue);
1799
+ if (retval == RL_NAN) {
1800
+ c->reply = createErrorObject("ERR hash value is not a float");
1801
+ goto cleanup;
1802
+ }
1803
+ RLITE_SERVER_ERR(c, retval);
1804
+ c->reply = createDoubleObject(newvalue);
1805
+ cleanup:
1806
+ return;
1807
+ }
1808
+
1809
+ static void addHashIteratorReply(rliteClient *c, int retval, rl_hash_iterator *iterator, int fields, int values)
1810
+ {
1811
+ unsigned char *field, *value;
1812
+ long fieldlen, valuelen;
1813
+ long i = 0;
1814
+
1815
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
1816
+ if (retval == RL_NOT_FOUND) {
1817
+ c->reply->elements = 0;
1818
+ return;
1819
+ }
1820
+ c->reply->elements = iterator->size * (fields + values);
1821
+ c->reply->element = malloc(sizeof(rliteReply*) * c->reply->elements);
1822
+ while ((retval = rl_hash_iterator_next(iterator,
1823
+ fields ? &field : NULL, fields ? &fieldlen : NULL,
1824
+ values ? &value : NULL, values ? &valuelen : NULL
1825
+ )) == RL_OK) {
1826
+ if (fields) {
1827
+ c->reply->element[i] = createStringObject((char *)field, fieldlen);
1828
+ rl_free(field);
1829
+ i++;
1830
+ }
1831
+ if (values) {
1832
+ c->reply->element[i] = createStringObject((char *)value, valuelen);
1833
+ rl_free(value);
1834
+ i++;
1835
+ }
1836
+ }
1837
+
1838
+ if (retval != RL_END) {
1839
+ __rliteSetError(c->context, RLITE_ERR, "Unexpected early end");
1840
+ goto cleanup;
1841
+ }
1842
+ iterator = NULL;
1843
+ cleanup:
1844
+ if (iterator) {
1845
+ rl_hash_iterator_destroy(iterator);
1846
+ }
1847
+ }
1848
+
1849
+ static void hgetallCommand(rliteClient *c) {
1850
+ unsigned char *key = UNSIGN(c->argv[1]);
1851
+ size_t keylen = c->argvlen[1];
1852
+ rl_hash_iterator *iterator;
1853
+ int retval = rl_hgetall(c->context->db, &iterator, key, keylen);
1854
+ RLITE_SERVER_ERR(c, retval);
1855
+ addHashIteratorReply(c, retval, iterator, 1, 1);
1856
+ cleanup:
1857
+ return;
1858
+ }
1859
+
1860
+ static void hkeysCommand(rliteClient *c) {
1861
+ unsigned char *key = UNSIGN(c->argv[1]);
1862
+ size_t keylen = c->argvlen[1];
1863
+ rl_hash_iterator *iterator;
1864
+ int retval = rl_hgetall(c->context->db, &iterator, key, keylen);
1865
+ RLITE_SERVER_ERR(c, retval);
1866
+ addHashIteratorReply(c, retval, iterator, 1, 0);
1867
+ cleanup:
1868
+ return;
1869
+ }
1870
+
1871
+ static void hvalsCommand(rliteClient *c) {
1872
+ unsigned char *key = UNSIGN(c->argv[1]);
1873
+ size_t keylen = c->argvlen[1];
1874
+ rl_hash_iterator *iterator;
1875
+ int retval = rl_hgetall(c->context->db, &iterator, key, keylen);
1876
+ RLITE_SERVER_ERR(c, retval);
1877
+ addHashIteratorReply(c, retval, iterator, 0, 1);
1878
+ cleanup:
1879
+ return;
1880
+ }
1881
+
1882
+ static void hmgetCommand(rliteClient *c) {
1883
+ unsigned char *key = UNSIGN(c->argv[1]);
1884
+ size_t keylen = c->argvlen[1];
1885
+
1886
+ int i, fieldc = c->argc - 2;
1887
+ unsigned char **fields = NULL;
1888
+ long *fieldslen = NULL;
1889
+ unsigned char **values = NULL;
1890
+ long *valueslen = NULL;
1891
+
1892
+ fields = malloc(sizeof(unsigned char *) * fieldc);
1893
+ if (!fields) {
1894
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1895
+ goto cleanup;
1896
+ }
1897
+ fieldslen = malloc(sizeof(long) * fieldc);
1898
+ if (!fieldslen) {
1899
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1900
+ goto cleanup;
1901
+ }
1902
+ for (i = 0; i < fieldc; i++) {
1903
+ fields[i] = (unsigned char *)c->argv[2 + i];
1904
+ fieldslen[i] = (long)c->argvlen[2 + i];
1905
+ }
1906
+
1907
+ int retval = rl_hmget(c->context->db, key, keylen, fieldc, fields, fieldslen, &values, &valueslen);
1908
+ RLITE_SERVER_ERR(c, retval);
1909
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
1910
+ c->reply->elements = fieldc;
1911
+ c->reply->element = malloc(sizeof(rliteReply*) * c->reply->elements);
1912
+ if (!c->reply->element) {
1913
+ free(c->reply);
1914
+ c->reply = NULL;
1915
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1916
+ goto cleanup;
1917
+ }
1918
+
1919
+ for (i = 0; i < fieldc; i++) {
1920
+ if (retval == RL_NOT_FOUND || valueslen[i] < 0) {
1921
+ c->reply->element[i] = createReplyObject(RLITE_REPLY_NIL);
1922
+ } else {
1923
+ c->reply->element[i] = createStringObject((char *)values[i], valueslen[i]);
1924
+ rl_free(values[i]);
1925
+ }
1926
+ }
1927
+ cleanup:
1928
+ free(fields);
1929
+ free(fieldslen);
1930
+ rl_free(values);
1931
+ rl_free(valueslen);
1932
+ }
1933
+
1934
+ static void saddCommand(rliteClient *c) {
1935
+ unsigned char *key = UNSIGN(c->argv[1]);
1936
+ size_t keylen = c->argvlen[1];
1937
+
1938
+ int i, memberc = c->argc - 2;
1939
+ unsigned char **members = NULL;
1940
+ long *memberslen = NULL;
1941
+ long count;
1942
+
1943
+ members = malloc(sizeof(unsigned char *) * memberc);
1944
+ if (!members) {
1945
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1946
+ goto cleanup;
1947
+ }
1948
+ memberslen = malloc(sizeof(long) * memberc);
1949
+ if (!memberslen) {
1950
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
1951
+ goto cleanup;
1952
+ }
1953
+ for (i = 0; i < memberc; i++) {
1954
+ members[i] = (unsigned char *)c->argv[2 + i];
1955
+ memberslen[i] = (long)c->argvlen[2 + i];
1956
+ }
1957
+
1958
+ int retval = rl_sadd(c->context->db, key, keylen, memberc, members, memberslen, &count);
1959
+ RLITE_SERVER_ERR(c, retval);
1960
+ c->reply = createLongLongObject(count);
1961
+ cleanup:
1962
+ free(members);
1963
+ free(memberslen);
1964
+ }
1965
+
1966
+ static void scardCommand(rliteClient *c) {
1967
+ long card = 0;
1968
+ int retval = rl_scard(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], &card);
1969
+ RLITE_SERVER_ERR(c, retval);
1970
+ c->reply = createLongLongObject(card);
1971
+ cleanup:
1972
+ return;
1973
+ }
1974
+
1975
+ static void sismemberCommand(rliteClient *c) {
1976
+ int retval = rl_sismember(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], UNSIGN(c->argv[2]), c->argvlen[2]);
1977
+ RLITE_SERVER_ERR(c, retval);
1978
+ c->reply = createLongLongObject(retval == RL_FOUND ? 1 : 0);
1979
+ cleanup:
1980
+ return;
1981
+ }
1982
+
1983
+ static void smoveCommand(rliteClient *c) {
1984
+ int retval = rl_smove(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], UNSIGN(c->argv[2]), c->argvlen[2], UNSIGN(c->argv[3]), c->argvlen[3]);
1985
+ RLITE_SERVER_ERR(c, retval);
1986
+ c->reply = createLongLongObject(retval == RL_OK ? 1 : 0);
1987
+ cleanup:
1988
+ return;
1989
+ }
1990
+
1991
+ static void spopCommand(rliteClient *c) {
1992
+ unsigned char *member;
1993
+ long memberlen;
1994
+ int retval = rl_spop(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], &member, &memberlen);
1995
+ RLITE_SERVER_ERR(c, retval);
1996
+ if (retval == RL_NOT_FOUND) {
1997
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
1998
+ } else if (retval == RL_OK) {
1999
+ c->reply = createStringObject((char *)member, memberlen);
2000
+ rl_free(member);
2001
+ }
2002
+ cleanup:
2003
+ return;
2004
+ }
2005
+
2006
+ static void srandmemberCommand(rliteClient *c) {
2007
+ unsigned char **members = NULL;
2008
+ long *memberslen = NULL;
2009
+ long count, i;
2010
+ int repeat;
2011
+
2012
+ if (c->argc == 2) {
2013
+ count = 1;
2014
+ repeat = 0;
2015
+ } else {
2016
+ if ((getLongFromObjectOrReply(c, c->argv[2], &count, NULL) != RLITE_OK)) return;
2017
+ repeat = count < 0 ? 1 : 0;
2018
+ count = count >= 0 ? count : -count;
2019
+ }
2020
+
2021
+ int retval = rl_srandmembers(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], repeat, &count, &members, &memberslen);
2022
+ RLITE_SERVER_ERR(c, retval);
2023
+ if (retval == RL_OK && count > 0) {
2024
+ if (c->argc == 2) {
2025
+ c->reply = createStringObject((char *)members[0], memberslen[0]);
2026
+ } else {
2027
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
2028
+ c->reply->elements = count;
2029
+ c->reply->element = malloc(sizeof(rliteReply*) * count);
2030
+ for (i = 0; i < count; i++) {
2031
+ c->reply->element[i] = createStringObject((char *)members[i], memberslen[i]);
2032
+ }
2033
+ }
2034
+ for (i = 0; i < count; i++) {
2035
+ rl_free(members[i]);
2036
+ }
2037
+ } else {
2038
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
2039
+ c->reply->elements = 0;
2040
+ }
2041
+ cleanup:
2042
+ rl_free(members);
2043
+ rl_free(memberslen);
2044
+ return;
2045
+ }
2046
+
2047
+ static void sremCommand(rliteClient *c) {
2048
+ unsigned char *key = UNSIGN(c->argv[1]);
2049
+ size_t keylen = c->argvlen[1];
2050
+
2051
+ int i, memberc = c->argc - 2;
2052
+ unsigned char **members = NULL;
2053
+ long *memberslen = NULL;
2054
+ long count;
2055
+
2056
+ members = malloc(sizeof(unsigned char *) * memberc);
2057
+ if (!members) {
2058
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2059
+ goto cleanup;
2060
+ }
2061
+ memberslen = malloc(sizeof(long) * memberc);
2062
+ if (!memberslen) {
2063
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2064
+ goto cleanup;
2065
+ }
2066
+ for (i = 0; i < memberc; i++) {
2067
+ members[i] = (unsigned char *)c->argv[2 + i];
2068
+ memberslen[i] = (long)c->argvlen[2 + i];
2069
+ }
2070
+
2071
+ int retval = rl_srem(c->context->db, key, keylen, memberc, members, memberslen, &count);
2072
+ RLITE_SERVER_ERR(c, retval);
2073
+ c->reply = createLongLongObject(count);
2074
+ cleanup:
2075
+ free(members);
2076
+ free(memberslen);
2077
+ }
2078
+
2079
+ static void sinterCommand(rliteClient *c) {
2080
+ int keyc = c->argc - 1, i, retval;
2081
+ unsigned char **keys = NULL, **members = NULL;
2082
+ long *keyslen = NULL, j, membersc, *memberslen = NULL;
2083
+
2084
+ keys = malloc(sizeof(unsigned char *) * keyc);
2085
+ if (!keys) {
2086
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2087
+ goto cleanup;
2088
+ }
2089
+ keyslen = malloc(sizeof(long) * keyc);
2090
+ if (!keyslen) {
2091
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2092
+ goto cleanup;
2093
+ }
2094
+ for (i = 0; i < keyc; i++) {
2095
+ keys[i] = UNSIGN(c->argv[1 + i]);
2096
+ keyslen[i] = c->argvlen[1 + i];
2097
+ }
2098
+ retval = rl_sinter(c->context->db, keyc, keys, keyslen, &membersc, &members, &memberslen);
2099
+ RLITE_SERVER_ERR(c, retval);
2100
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
2101
+ c->reply->elements = membersc;
2102
+ if (membersc > 0) {
2103
+ c->reply->element = malloc(sizeof(rliteReply*) * membersc);
2104
+ if (!c->reply->element) {
2105
+ free(c->reply);
2106
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2107
+ goto cleanup;
2108
+ }
2109
+ for (j = 0; j < membersc; j++) {
2110
+ c->reply->element[j] = createStringObject((char *)members[j], memberslen[j]);
2111
+ }
2112
+ }
2113
+ cleanup:
2114
+ if (members) {
2115
+ for (j = 0; j < membersc; j++) {
2116
+ rl_free(members[j]);
2117
+ }
2118
+ rl_free(members);
2119
+ rl_free(memberslen);
2120
+ }
2121
+ free(keys);
2122
+ free(keyslen);
2123
+ return;
2124
+ }
2125
+
2126
+ static void sinterstoreCommand(rliteClient *c) {
2127
+ int keyc = c->argc - 2, i, retval;
2128
+ unsigned char **keys = NULL;
2129
+ long *keyslen = NULL, membersc;
2130
+ unsigned char *target = UNSIGN(c->argv[1]);
2131
+ long targetlen = c->argvlen[1];
2132
+
2133
+ keys = malloc(sizeof(unsigned char *) * keyc);
2134
+ if (!keys) {
2135
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2136
+ goto cleanup;
2137
+ }
2138
+ keyslen = malloc(sizeof(long) * keyc);
2139
+ if (!keyslen) {
2140
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2141
+ goto cleanup;
2142
+ }
2143
+ for (i = 0; i < keyc; i++) {
2144
+ keys[i] = UNSIGN(c->argv[2 + i]);
2145
+ keyslen[i] = c->argvlen[2 + i];
2146
+ }
2147
+ retval = rl_sinterstore(c->context->db, target, targetlen, keyc, keys, keyslen, &membersc);
2148
+ RLITE_SERVER_ERR(c, retval);
2149
+ c->reply = createLongLongObject(membersc);
2150
+ cleanup:
2151
+ free(keys);
2152
+ free(keyslen);
2153
+ return;
2154
+ }
2155
+
2156
+ static void sunionCommand(rliteClient *c) {
2157
+ int keyc = c->argc - 1, i, retval;
2158
+ unsigned char **keys = NULL, **members = NULL;
2159
+ long *keyslen = NULL, j, membersc, *memberslen = NULL;
2160
+
2161
+ keys = malloc(sizeof(unsigned char *) * keyc);
2162
+ if (!keys) {
2163
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2164
+ goto cleanup;
2165
+ }
2166
+ keyslen = malloc(sizeof(long) * keyc);
2167
+ if (!keyslen) {
2168
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2169
+ goto cleanup;
2170
+ }
2171
+ for (i = 0; i < keyc; i++) {
2172
+ keys[i] = UNSIGN(c->argv[1 + i]);
2173
+ keyslen[i] = c->argvlen[1 + i];
2174
+ }
2175
+ retval = rl_sunion(c->context->db, keyc, keys, keyslen, &membersc, &members, &memberslen);
2176
+ RLITE_SERVER_ERR(c, retval);
2177
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
2178
+ c->reply->elements = membersc;
2179
+ if (membersc > 0) {
2180
+ c->reply->element = malloc(sizeof(rliteReply*) * membersc);
2181
+ if (!c->reply->element) {
2182
+ free(c->reply);
2183
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2184
+ goto cleanup;
2185
+ }
2186
+ for (j = 0; j < membersc; j++) {
2187
+ c->reply->element[j] = createStringObject((char *)members[j], memberslen[j]);
2188
+ }
2189
+ }
2190
+ cleanup:
2191
+ if (members) {
2192
+ for (j = 0; j < membersc; j++) {
2193
+ rl_free(members[j]);
2194
+ }
2195
+ rl_free(members);
2196
+ rl_free(memberslen);
2197
+ }
2198
+ free(keys);
2199
+ free(keyslen);
2200
+ return;
2201
+ }
2202
+
2203
+ static void sunionstoreCommand(rliteClient *c) {
2204
+ int keyc = c->argc - 2, i, retval;
2205
+ unsigned char **keys = NULL;
2206
+ long *keyslen = NULL, membersc;
2207
+ unsigned char *target = UNSIGN(c->argv[1]);
2208
+ long targetlen = c->argvlen[1];
2209
+
2210
+ keys = malloc(sizeof(unsigned char *) * keyc);
2211
+ if (!keys) {
2212
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2213
+ goto cleanup;
2214
+ }
2215
+ keyslen = malloc(sizeof(long) * keyc);
2216
+ if (!keyslen) {
2217
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2218
+ goto cleanup;
2219
+ }
2220
+ for (i = 0; i < keyc; i++) {
2221
+ keys[i] = UNSIGN(c->argv[2 + i]);
2222
+ keyslen[i] = c->argvlen[2 + i];
2223
+ }
2224
+ retval = rl_sunionstore(c->context->db, target, targetlen, keyc, keys, keyslen, &membersc);
2225
+ RLITE_SERVER_ERR(c, retval);
2226
+ c->reply = createLongLongObject(membersc);
2227
+ cleanup:
2228
+ free(keys);
2229
+ free(keyslen);
2230
+ return;
2231
+ }
2232
+
2233
+ static void sdiffCommand(rliteClient *c) {
2234
+ int keyc = c->argc - 1, i, retval;
2235
+ unsigned char **keys = NULL, **members = NULL;
2236
+ long *keyslen = NULL, j, membersc, *memberslen = NULL;
2237
+
2238
+ keys = malloc(sizeof(unsigned char *) * keyc);
2239
+ if (!keys) {
2240
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2241
+ goto cleanup;
2242
+ }
2243
+ keyslen = malloc(sizeof(long) * keyc);
2244
+ if (!keyslen) {
2245
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2246
+ goto cleanup;
2247
+ }
2248
+ for (i = 0; i < keyc; i++) {
2249
+ keys[i] = UNSIGN(c->argv[1 + i]);
2250
+ keyslen[i] = c->argvlen[1 + i];
2251
+ }
2252
+ retval = rl_sdiff(c->context->db, keyc, keys, keyslen, &membersc, &members, &memberslen);
2253
+ RLITE_SERVER_ERR(c, retval);
2254
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
2255
+ c->reply->elements = membersc;
2256
+ if (membersc > 0) {
2257
+ c->reply->element = malloc(sizeof(rliteReply*) * membersc);
2258
+ if (!c->reply->element) {
2259
+ free(c->reply);
2260
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2261
+ goto cleanup;
2262
+ }
2263
+ for (j = 0; j < membersc; j++) {
2264
+ c->reply->element[j] = createStringObject((char *)members[j], memberslen[j]);
2265
+ }
2266
+ }
2267
+ cleanup:
2268
+ if (members) {
2269
+ for (j = 0; j < membersc; j++) {
2270
+ rl_free(members[j]);
2271
+ }
2272
+ rl_free(members);
2273
+ rl_free(memberslen);
2274
+ }
2275
+ free(keys);
2276
+ free(keyslen);
2277
+ return;
2278
+ }
2279
+
2280
+ static void sdiffstoreCommand(rliteClient *c) {
2281
+ int keyc = c->argc - 2, i, retval;
2282
+ unsigned char **keys = NULL;
2283
+ long *keyslen = NULL, membersc;
2284
+ unsigned char *target = UNSIGN(c->argv[1]);
2285
+ long targetlen = c->argvlen[1];
2286
+
2287
+ keys = malloc(sizeof(unsigned char *) * keyc);
2288
+ if (!keys) {
2289
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2290
+ goto cleanup;
2291
+ }
2292
+ keyslen = malloc(sizeof(long) * keyc);
2293
+ if (!keyslen) {
2294
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2295
+ goto cleanup;
2296
+ }
2297
+ for (i = 0; i < keyc; i++) {
2298
+ keys[i] = UNSIGN(c->argv[2 + i]);
2299
+ keyslen[i] = c->argvlen[2 + i];
2300
+ }
2301
+ retval = rl_sdiffstore(c->context->db, target, targetlen, keyc, keys, keyslen, &membersc);
2302
+ RLITE_SERVER_ERR(c, retval);
2303
+ c->reply = createLongLongObject(membersc);
2304
+ cleanup:
2305
+ free(keys);
2306
+ free(keyslen);
2307
+ return;
2308
+ }
2309
+
2310
+ static void pushGenericCommand(rliteClient *c, int create, int left) {
2311
+ unsigned char *key = UNSIGN(c->argv[1]);
2312
+ size_t keylen = c->argvlen[1];
2313
+
2314
+ int i, valuec = c->argc - 2;
2315
+ unsigned char **values = NULL;
2316
+ long *valueslen = NULL;
2317
+ long count;
2318
+
2319
+ values = malloc(sizeof(unsigned char *) * valuec);
2320
+ if (!values) {
2321
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2322
+ goto cleanup;
2323
+ }
2324
+ valueslen = malloc(sizeof(long) * valuec);
2325
+ if (!valueslen) {
2326
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2327
+ goto cleanup;
2328
+ }
2329
+ for (i = 0; i < valuec; i++) {
2330
+ values[i] = (unsigned char *)c->argv[2 + i];
2331
+ valueslen[i] = (long)c->argvlen[2 + i];
2332
+ }
2333
+
2334
+ int retval = rl_push(c->context->db, key, keylen, create, left, valuec, values, valueslen, &count);
2335
+ if (retval == RL_NOT_FOUND) {
2336
+ c->reply = createLongLongObject(0);
2337
+ } else {
2338
+ RLITE_SERVER_ERR(c, retval);
2339
+ c->reply = createLongLongObject(count);
2340
+ }
2341
+ cleanup:
2342
+ free(values);
2343
+ free(valueslen);
2344
+ }
2345
+
2346
+ static void lpushCommand(rliteClient *c) {
2347
+ pushGenericCommand(c, 1, 1);
2348
+ }
2349
+
2350
+ static void lpushxCommand(rliteClient *c) {
2351
+ pushGenericCommand(c, 0, 1);
2352
+ }
2353
+
2354
+ static void rpushCommand(rliteClient *c) {
2355
+ pushGenericCommand(c, 1, 0);
2356
+ }
2357
+
2358
+ static void rpushxCommand(rliteClient *c) {
2359
+ pushGenericCommand(c, 0, 0);
2360
+ }
2361
+
2362
+ static void llenCommand(rliteClient *c) {
2363
+ long len = 0;
2364
+ int retval = rl_llen(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], &len);
2365
+ RLITE_SERVER_ERR(c, retval);
2366
+ c->reply = createLongLongObject(len);
2367
+ cleanup:
2368
+ return;
2369
+ }
2370
+
2371
+ static void popGenericCommand(rliteClient *c, int left) {
2372
+ unsigned char *value;
2373
+ long valuelen;
2374
+ int retval = rl_pop(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], &value, &valuelen, left);
2375
+ RLITE_SERVER_ERR(c, retval);
2376
+ if (retval == RL_NOT_FOUND) {
2377
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
2378
+ } else if (retval == RL_OK) {
2379
+ c->reply = createStringObject((char *)value, valuelen);
2380
+ rl_free(value);
2381
+ }
2382
+ cleanup:
2383
+ return;
2384
+ }
2385
+
2386
+ static void rpopCommand(rliteClient *c) {
2387
+ popGenericCommand(c, 0);
2388
+ }
2389
+
2390
+ static void lpopCommand(rliteClient *c) {
2391
+ popGenericCommand(c, 1);
2392
+ }
2393
+
2394
+ static void lindexCommand(rliteClient *c) {
2395
+ long index;
2396
+ unsigned char *value;
2397
+ long valuelen;
2398
+
2399
+ if ((getLongFromObjectOrReply(c, c->argv[2], &index, NULL) != RLITE_OK))
2400
+ return;
2401
+
2402
+ int retval = rl_lindex(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], index, &value, &valuelen);
2403
+ RLITE_SERVER_ERR(c, retval);
2404
+ if (retval == RL_INVALID_PARAMETERS || retval == RL_NOT_FOUND) {
2405
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
2406
+ } else if (retval == RL_OK) {
2407
+ c->reply = createStringObject((char *)value, valuelen);
2408
+ rl_free(value);
2409
+ }
2410
+ cleanup:
2411
+ return;
2412
+ }
2413
+
2414
+ static void linsertCommand(rliteClient *c) {
2415
+ int after;
2416
+ if (strcasecmp(c->argv[2], "after") == 0) {
2417
+ after = 1;
2418
+ } else if (strcasecmp(c->argv[2], "before") == 0) {
2419
+ after = 0;
2420
+ } else {
2421
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
2422
+ return;
2423
+ }
2424
+
2425
+ unsigned char *key = UNSIGN(c->argv[1]);
2426
+ size_t keylen = c->argvlen[1];
2427
+
2428
+ long size;
2429
+ int retval = rl_linsert(c->context->db, key, keylen, after, UNSIGN(c->argv[3]), c->argvlen[3], UNSIGN(c->argv[4]), c->argvlen[4], &size);
2430
+ RLITE_SERVER_ERR(c, retval);
2431
+ if (retval == RL_OK) {
2432
+ c->reply = createLongLongObject(size);
2433
+ } else {
2434
+ c->reply = createLongLongObject(-1);
2435
+ }
2436
+ cleanup:
2437
+ return;
2438
+ }
2439
+
2440
+ static void lrangeCommand(rliteClient *c) {
2441
+ unsigned char *key = UNSIGN(c->argv[1]);
2442
+ size_t keylen = c->argvlen[1];
2443
+
2444
+ unsigned char **values = NULL;
2445
+ long size = 0, *valueslen = NULL;
2446
+
2447
+ long start, stop, i;
2448
+
2449
+ if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != RLITE_OK) ||
2450
+ (getLongFromObjectOrReply(c, c->argv[3], &stop, NULL) != RLITE_OK)) return;
2451
+
2452
+ int retval = rl_lrange(c->context->db, key, keylen, start, stop, &size, &values, &valueslen);
2453
+ RLITE_SERVER_ERR(c, retval);
2454
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
2455
+ if (retval == RL_NOT_FOUND) {
2456
+ c->reply->elements = 0;
2457
+ return;
2458
+ }
2459
+ c->reply->elements = size;
2460
+ c->reply->element = malloc(sizeof(rliteReply*) * c->reply->elements);
2461
+ for (i = 0; i < size; i++) {
2462
+ c->reply->element[i] = createStringObject((char *)values[i], valueslen[i]);
2463
+ }
2464
+ cleanup:
2465
+ if (values) {
2466
+ for (i = 0; i < size; i++) {
2467
+ rl_free(values[i]);
2468
+ }
2469
+ rl_free(values);
2470
+ rl_free(valueslen);
2471
+ }
2472
+ }
2473
+
2474
+ static void lremCommand(rliteClient *c) {
2475
+ unsigned char *key = UNSIGN(c->argv[1]);
2476
+ size_t keylen = c->argvlen[1];
2477
+ long count, maxcount, resultcount;
2478
+ int direction;
2479
+
2480
+ if ((getLongFromObjectOrReply(c, c->argv[2], &count, NULL) != RLITE_OK)) return;
2481
+
2482
+ if (count >= 0) {
2483
+ direction = 1;
2484
+ maxcount = count;
2485
+ } else {
2486
+ direction = -1;
2487
+ maxcount = -count;
2488
+ }
2489
+ int retval = rl_lrem(c->context->db, key, keylen, direction, maxcount, UNSIGN(c->argv[3]), c->argvlen[3], &resultcount);
2490
+ RLITE_SERVER_ERR(c, retval);
2491
+ c->reply = createLongLongObject(resultcount);
2492
+ cleanup:
2493
+ return;
2494
+ }
2495
+
2496
+ static void lsetCommand(rliteClient *c) {
2497
+ unsigned char *key = UNSIGN(c->argv[1]);
2498
+ size_t keylen = c->argvlen[1];
2499
+ long index;
2500
+
2501
+ if ((getLongFromObjectOrReply(c, c->argv[2], &index, NULL) != RLITE_OK)) return;
2502
+
2503
+ int retval = rl_lset(c->context->db, key, keylen, index, UNSIGN(c->argv[3]), c->argvlen[3]);
2504
+ RLITE_SERVER_ERR(c, retval);
2505
+ if (retval == RL_NOT_FOUND) {
2506
+ c->reply = createErrorObject(RLITE_NOKEYERR);
2507
+ } else if (retval == RL_INVALID_PARAMETERS) {
2508
+ c->reply = createErrorObject(RLITE_OUTOFRANGEERR);
2509
+ } else if (retval == RL_OK) {
2510
+ c->reply = createStatusObject(RLITE_STR_OK);
2511
+ }
2512
+ cleanup:
2513
+ return;
2514
+ }
2515
+
2516
+ static void ltrimCommand(rliteClient *c) {
2517
+ unsigned char *key = UNSIGN(c->argv[1]);
2518
+ size_t keylen = c->argvlen[1];
2519
+ long start, stop;
2520
+
2521
+ if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != RLITE_OK) ||
2522
+ (getLongFromObjectOrReply(c, c->argv[3], &stop, NULL) != RLITE_OK)) return;
2523
+
2524
+ int retval = rl_ltrim(c->context->db, key, keylen, start, stop);
2525
+ RLITE_SERVER_ERR(c, retval);
2526
+ c->reply = createStatusObject(RLITE_STR_OK);
2527
+ cleanup:
2528
+ return;
2529
+ }
2530
+
2531
+ static void rpoplpushCommand(rliteClient *c) {
2532
+ unsigned char *value;
2533
+ long valuelen;
2534
+ int retval = rl_pop(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], &value, &valuelen, 0);
2535
+ RLITE_SERVER_ERR(c, retval);
2536
+ if (retval == RL_NOT_FOUND) {
2537
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
2538
+ goto cleanup;
2539
+ }
2540
+ if (retval != RL_OK) {
2541
+ goto cleanup;
2542
+ }
2543
+ retval = rl_push(c->context->db, UNSIGN(c->argv[2]), c->argvlen[2], 1, 1, 1, &value, &valuelen, NULL);
2544
+ RLITE_SERVER_ERR(c, retval);
2545
+
2546
+ c->reply = createStringObject((char *)value, valuelen);
2547
+ rl_free(value);
2548
+ cleanup:
2549
+ return;
2550
+ }
2551
+
2552
+ #define REDIS_SET_NO_FLAGS 0
2553
+ #define REDIS_SET_NX (1<<0) /* Set if key not exists. */
2554
+ #define REDIS_SET_XX (1<<1) /* Set if key exists. */
2555
+
2556
+ static void setGenericCommand(rliteClient *c, int flags, const unsigned char *key, long keylen, unsigned char *value, long valuelen, long long expire) {
2557
+ int retval;
2558
+ long long milliseconds = 0; /* initialized to avoid any harmness warning */
2559
+
2560
+ if (expire) {
2561
+ if (expire <= 0) {
2562
+ addReplyErrorFormat(c->context, "invalid expire time in %s", c->argv[0]);
2563
+ return;
2564
+ }
2565
+
2566
+ milliseconds = rl_mstime() + expire;
2567
+ }
2568
+
2569
+ if ((flags & REDIS_SET_NX) || (flags & REDIS_SET_XX)) {
2570
+ retval = rl_key_get(c->context->db, key, keylen, NULL, NULL, NULL, NULL, NULL);
2571
+ if (((flags & REDIS_SET_NX) && retval == RL_FOUND) ||
2572
+ ((flags & REDIS_SET_XX) && retval == RL_NOT_FOUND)) {
2573
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
2574
+ return;
2575
+ }
2576
+ }
2577
+
2578
+ retval = rl_set(c->context->db, key, keylen, value, valuelen, 0, milliseconds);
2579
+ RLITE_SERVER_ERR(c, retval);
2580
+ c->reply = createStatusObject(RLITE_STR_OK);
2581
+ cleanup:
2582
+ return;
2583
+ }
2584
+
2585
+ /* SET key value [NX] [XX] [EX <seconds>] [PX <milliseconds>] */
2586
+ static void setCommand(rliteClient *c) {
2587
+ const unsigned char *key = UNSIGN(c->argv[1]);
2588
+ size_t keylen = c->argvlen[1];
2589
+ int j;
2590
+ long long expire = 0, next;
2591
+ int flags = REDIS_SET_NO_FLAGS;
2592
+
2593
+ for (j = 3; j < c->argc; j++) {
2594
+ char *a = c->argv[j];
2595
+
2596
+ next = 0;
2597
+ if (j < c->argc - 1 && getLongLongFromObject(c->argv[j + 1], &next) != RLITE_OK) {
2598
+ next = 0;
2599
+ }
2600
+
2601
+ if ((a[0] == 'n' || a[0] == 'N') &&
2602
+ (a[1] == 'x' || a[1] == 'X') && a[2] == '\0') {
2603
+ flags |= REDIS_SET_NX;
2604
+ } else if ((a[0] == 'x' || a[0] == 'X') &&
2605
+ (a[1] == 'x' || a[1] == 'X') && a[2] == '\0') {
2606
+ flags |= REDIS_SET_XX;
2607
+ } else if ((a[0] == 'e' || a[0] == 'E') &&
2608
+ (a[1] == 'x' || a[1] == 'X') && a[2] == '\0' && next) {
2609
+ expire = next * 1000;
2610
+ j++;
2611
+ } else if ((a[0] == 'p' || a[0] == 'P') &&
2612
+ (a[1] == 'x' || a[1] == 'X') && a[2] == '\0' && next) {
2613
+ expire = next;
2614
+ j++;
2615
+ } else {
2616
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
2617
+ return;
2618
+ }
2619
+ }
2620
+
2621
+ setGenericCommand(c, flags, key, keylen, UNSIGN(c->argv[2]), c->argvlen[2], expire);
2622
+ }
2623
+
2624
+ static void setnxCommand(rliteClient *c) {
2625
+ rliteReply *reply;
2626
+ setGenericCommand(c, REDIS_SET_NX, UNSIGN(c->argv[1]), c->argvlen[1], UNSIGN(c->argv[2]), c->argvlen[2], 0);
2627
+ reply = c->reply;
2628
+ if (reply->type == RLITE_REPLY_NIL) {
2629
+ c->reply = createLongLongObject(0);
2630
+ } else {
2631
+ c->reply = createLongLongObject(1);
2632
+ }
2633
+ rliteFreeReplyObject(reply);
2634
+ }
2635
+
2636
+ static void setexCommand(rliteClient *c) {
2637
+ long long expire;
2638
+ if (getLongLongFromObject(c->argv[2], &expire) != RLITE_OK) {
2639
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
2640
+ return;
2641
+ }
2642
+ setGenericCommand(c, REDIS_SET_NO_FLAGS, UNSIGN(c->argv[1]), c->argvlen[1], UNSIGN(c->argv[3]), c->argvlen[3], expire * 1000);
2643
+ }
2644
+
2645
+ static void psetexCommand(rliteClient *c) {
2646
+ long long expire;
2647
+ if (getLongLongFromObject(c->argv[2], &expire) != RLITE_OK) {
2648
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
2649
+ return;
2650
+ }
2651
+ setGenericCommand(c, REDIS_SET_NO_FLAGS, UNSIGN(c->argv[1]), c->argvlen[1], UNSIGN(c->argv[3]), c->argvlen[3], expire);
2652
+ }
2653
+
2654
+ static void getCommand(rliteClient *c) {
2655
+ unsigned char *key = UNSIGN(c->argv[1]);
2656
+ long keylen = c->argvlen[1];
2657
+ unsigned char *value = NULL;
2658
+ long valuelen;
2659
+
2660
+ int retval;
2661
+ retval = rl_get(c->context->db, key, keylen, &value, &valuelen);
2662
+ RLITE_SERVER_ERR(c, retval);
2663
+ if (retval == RL_NOT_FOUND) {
2664
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
2665
+ } else {
2666
+ c->reply = createStringObject((char *)value, valuelen);
2667
+ }
2668
+
2669
+ rl_free(value);
2670
+ cleanup:
2671
+ return;
2672
+ }
2673
+
2674
+ static void appendCommand(rliteClient *c) {
2675
+ unsigned char *key = UNSIGN(c->argv[1]);
2676
+ long keylen = c->argvlen[1];
2677
+ unsigned char *value = UNSIGN(c->argv[2]);
2678
+ long valuelen = c->argvlen[2];
2679
+ long newlen;
2680
+
2681
+ int retval;
2682
+ retval = rl_append(c->context->db, key, keylen, value, valuelen, &newlen);
2683
+ RLITE_SERVER_ERR(c, retval);
2684
+ if (retval == RL_OK) {
2685
+ c->reply = createLongLongObject(newlen);
2686
+ }
2687
+ cleanup:
2688
+ return;
2689
+ }
2690
+
2691
+ static void getsetCommand(rliteClient *c) {
2692
+ unsigned char *key = UNSIGN(c->argv[1]);
2693
+ long keylen = c->argvlen[1];
2694
+ unsigned char *value = UNSIGN(c->argv[2]);
2695
+ long valuelen = c->argvlen[2];
2696
+ unsigned char *prevvalue = NULL;
2697
+ long prevvaluelen;
2698
+
2699
+ int retval;
2700
+ retval = rl_get(c->context->db, key, keylen, &prevvalue, &prevvaluelen);
2701
+ RLITE_SERVER_ERR(c, retval);
2702
+ if (retval == RL_NOT_FOUND) {
2703
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
2704
+ } else {
2705
+ c->reply = createStringObject((char *)prevvalue, prevvaluelen);
2706
+ }
2707
+ rl_free(prevvalue);
2708
+
2709
+ retval = rl_set(c->context->db, key, keylen, value, valuelen, 0, 0);
2710
+ RLITE_SERVER_ERR(c, retval);
2711
+ cleanup:
2712
+ return;
2713
+ }
2714
+
2715
+ static void mgetCommand(rliteClient *c) {
2716
+ int retval = RL_OK, i = 0, keyc = c->argc - 1;
2717
+ unsigned char *key;
2718
+ long keylen;
2719
+ unsigned char *value;
2720
+ long valuelen;
2721
+
2722
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
2723
+ c->reply->elements = keyc;
2724
+ c->reply->element = malloc(sizeof(rliteReply*) * c->reply->elements);
2725
+ if (!c->reply->element) {
2726
+ free(c->reply);
2727
+ c->reply = NULL;
2728
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
2729
+ goto cleanup;
2730
+ }
2731
+
2732
+ for (i = 0; i < keyc; i++) {
2733
+ key = (unsigned char *)c->argv[1 + i];
2734
+ keylen = (long)c->argvlen[1 + i];
2735
+ retval = rl_get(c->context->db, key, keylen, &value, &valuelen);
2736
+ // return nil for keys that are not strings
2737
+ if (retval == RL_WRONG_TYPE) {
2738
+ retval = RL_NOT_FOUND;
2739
+ }
2740
+ RLITE_SERVER_ERR(c, retval);
2741
+ if (retval == RL_NOT_FOUND) {
2742
+ c->reply->element[i] = createReplyObject(RLITE_REPLY_NIL);
2743
+ } else {
2744
+ c->reply->element[i] = createStringObject((char *)value, valuelen);
2745
+ rl_free(value);
2746
+ }
2747
+ }
2748
+ retval = RL_OK;
2749
+ cleanup:
2750
+ if (retval != RL_OK) {
2751
+ for (; i >= 0; i--) {
2752
+ free(c->reply->element[i]);
2753
+ }
2754
+ free(c->reply);
2755
+ c->reply = NULL;
2756
+ }
2757
+ return;
2758
+ }
2759
+
2760
+ static void msetCommand(rliteClient *c) {
2761
+ int retval, i = 0, keyc = c->argc - 1;
2762
+ unsigned char *key;
2763
+ long keylen;
2764
+ unsigned char *value;
2765
+ long valuelen;
2766
+
2767
+ if (c->argc % 2 == 0) {
2768
+ addReplyErrorFormat(c->context, RLITE_WRONGNUMBEROFARGUMENTS, c->argv[0]);
2769
+ return;
2770
+ }
2771
+
2772
+ for (i = 1; i < keyc; i += 2) {
2773
+ key = (unsigned char *)c->argv[i];
2774
+ keylen = (long)c->argvlen[i];
2775
+ value = (unsigned char *)c->argv[i + 1];
2776
+ valuelen = (long)c->argvlen[i + 1];
2777
+ retval = rl_set(c->context->db, key, keylen, value, valuelen, 0, 0);
2778
+ RLITE_SERVER_ERR(c, retval);
2779
+ }
2780
+ c->reply = createStatusObject(RLITE_STR_OK);
2781
+ cleanup:
2782
+ return;
2783
+ }
2784
+
2785
+ static void msetnxCommand(rliteClient *c) {
2786
+ int retval, i = 0, keyc = c->argc - 1;
2787
+ unsigned char *key;
2788
+ long keylen;
2789
+ unsigned char *value;
2790
+ long valuelen;
2791
+
2792
+ if (c->argc % 2 == 0) {
2793
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
2794
+ return;
2795
+ }
2796
+
2797
+ for (i = 1; i < keyc; i += 2) {
2798
+ key = (unsigned char *)c->argv[i];
2799
+ keylen = (long)c->argvlen[i];
2800
+ retval = rl_get(c->context->db, key, keylen, NULL, NULL);
2801
+ if (retval != RL_NOT_FOUND) {
2802
+ retval = RL_FOUND;
2803
+ goto cleanup;
2804
+ }
2805
+ }
2806
+
2807
+ for (i = 1; i < keyc; i += 2) {
2808
+ key = (unsigned char *)c->argv[i];
2809
+ keylen = (long)c->argvlen[i];
2810
+ value = (unsigned char *)c->argv[i + 1];
2811
+ valuelen = (long)c->argvlen[i + 1];
2812
+ retval = rl_set(c->context->db, key, keylen, value, valuelen, 1, 0);
2813
+ RLITE_SERVER_ERR(c, retval);
2814
+ if (retval != RL_OK) {
2815
+ goto cleanup;
2816
+ }
2817
+ }
2818
+ retval = RL_OK;
2819
+ cleanup:
2820
+ c->reply = createLongLongObject(retval == RL_OK ? 1 : 0);
2821
+ return;
2822
+ }
2823
+
2824
+ static void getrangeCommand(rliteClient *c) {
2825
+ unsigned char *key = UNSIGN(c->argv[1]);
2826
+ long keylen = c->argvlen[1];
2827
+ unsigned char *value = NULL;
2828
+ long valuelen;
2829
+ long long start, stop;
2830
+
2831
+ if (getLongLongFromObject(c->argv[2], &start) != RLITE_OK ||
2832
+ getLongLongFromObject(c->argv[3], &stop) != RLITE_OK) {
2833
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
2834
+ return;
2835
+ }
2836
+
2837
+ int retval;
2838
+ retval = rl_getrange(c->context->db, key, keylen, start, stop, &value, &valuelen);
2839
+ RLITE_SERVER_ERR(c, retval);
2840
+ if (retval == RL_NOT_FOUND) {
2841
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
2842
+ } else {
2843
+ c->reply = createStringObject((char *)value, valuelen);
2844
+ }
2845
+
2846
+ rl_free(value);
2847
+ cleanup:
2848
+ return;
2849
+ }
2850
+
2851
+ static void setrangeCommand(rliteClient *c) {
2852
+ unsigned char *key = UNSIGN(c->argv[1]);
2853
+ long keylen = c->argvlen[1];
2854
+ unsigned char *value = UNSIGN(c->argv[3]);
2855
+ long valuelen = c->argvlen[3];
2856
+ long long offset;
2857
+ long newlength;
2858
+ int retval;
2859
+
2860
+ if (getLongLongFromObject(c->argv[2], &offset) != RLITE_OK) {
2861
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
2862
+ return;
2863
+ }
2864
+
2865
+ if (offset == 0 && valuelen == 0) {
2866
+ retval = rl_get(c->context->db, key, keylen, NULL, &newlength);
2867
+ RLITE_SERVER_ERR(c, retval);
2868
+ if (retval == RL_OK) {
2869
+ c->reply = createLongLongObject(newlength);
2870
+ } else {
2871
+ c->reply = createLongLongObject(0);
2872
+ }
2873
+ goto cleanup;
2874
+ }
2875
+ if (offset < 0) {
2876
+ c->reply = createErrorObject("ERR offset is out of range");
2877
+ goto cleanup;
2878
+ }
2879
+
2880
+ retval = rl_setrange(c->context->db, key, keylen, offset, value, valuelen, &newlength);
2881
+ RLITE_SERVER_ERR(c, retval);
2882
+ if (retval == RL_OK) {
2883
+ c->reply = createLongLongObject(newlength);
2884
+ } else if (retval == RL_INVALID_PARAMETERS) {
2885
+ c->reply = createErrorObject("ERR string exceeds maximum allowed size (512MB)");
2886
+ }
2887
+ cleanup:
2888
+ return;
2889
+ }
2890
+
2891
+ static void strlenCommand(rliteClient *c) {
2892
+ unsigned char *key = UNSIGN(c->argv[1]);
2893
+ long keylen = c->argvlen[1];
2894
+ long length;
2895
+
2896
+ int retval = rl_get(c->context->db, key, keylen, NULL, &length);
2897
+ RLITE_SERVER_ERR(c, retval);
2898
+ if (retval == RL_OK) {
2899
+ c->reply = createLongLongObject(length);
2900
+ } else if (retval == RL_NOT_FOUND) {
2901
+ c->reply = createLongLongObject(0);
2902
+ }
2903
+ cleanup:
2904
+ return;
2905
+ }
2906
+
2907
+ static void incrGenericCommand(rliteClient *c, long long increment) {
2908
+ unsigned char *key = UNSIGN(c->argv[1]);
2909
+ long keylen = c->argvlen[1];
2910
+ long long newvalue;
2911
+
2912
+ int retval = rl_incr(c->context->db, key, keylen, increment, &newvalue);
2913
+ if (retval == RL_NAN) {
2914
+ c->reply = createErrorObject("ERR value is not an integer or out of range");
2915
+ goto cleanup;
2916
+ }
2917
+ RLITE_SERVER_ERR(c, retval);
2918
+ if (retval == RL_OK) {
2919
+ c->reply = createLongLongObject(newvalue);
2920
+ }
2921
+ cleanup:
2922
+ return;
2923
+ }
2924
+
2925
+ static void incrCommand(rliteClient *c) {
2926
+ incrGenericCommand(c, 1);
2927
+ }
2928
+
2929
+ static void decrCommand(rliteClient *c) {
2930
+ incrGenericCommand(c, -1);
2931
+ }
2932
+
2933
+ static void incrbyCommand(rliteClient *c) {
2934
+ long long increment;
2935
+ if (getLongLongFromObjectOrReply(c, c->argv[2], &increment, RLITE_SYNTAXERR) != RLITE_OK) {
2936
+ return;
2937
+ }
2938
+ incrGenericCommand(c, increment);
2939
+ }
2940
+
2941
+ static void decrbyCommand(rliteClient *c) {
2942
+ long long decrement;
2943
+ if (getLongLongFromObjectOrReply(c, c->argv[2], &decrement, RLITE_SYNTAXERR) != RLITE_OK) {
2944
+ return;
2945
+ }
2946
+ incrGenericCommand(c, -decrement);
2947
+ }
2948
+
2949
+ static void incrbyfloatCommand(rliteClient *c) {
2950
+ unsigned char *key = UNSIGN(c->argv[1]);
2951
+ long keylen = c->argvlen[1];
2952
+ double increment;
2953
+ double newvalue;
2954
+
2955
+ if ((getDoubleFromObjectOrReply(c, c->argv[2], c->argvlen[2], &increment, NULL) != RLITE_OK)) return;
2956
+
2957
+ int retval = rl_incrbyfloat(c->context->db, key, keylen, increment, &newvalue);
2958
+ if (retval == RL_NAN) {
2959
+ c->reply = createErrorObject("ERR value is not a valid float");
2960
+ goto cleanup;
2961
+ }
2962
+ RLITE_SERVER_ERR(c, retval);
2963
+ if (retval == RL_OK) {
2964
+ c->reply = createDoubleObject(newvalue);
2965
+ }
2966
+ cleanup:
2967
+ return;
2968
+ }
2969
+
2970
+ static void getbitCommand(rliteClient *c) {
2971
+ unsigned char *key = UNSIGN(c->argv[1]);
2972
+ long keylen = c->argvlen[1];
2973
+ long long offset;
2974
+ int value;
2975
+
2976
+ if (getLongLongFromObjectOrReply(c, c->argv[2], &offset, RLITE_SYNTAXERR) != RLITE_OK) {
2977
+ return;
2978
+ }
2979
+ int retval = rl_getbit(c->context->db, key, keylen, offset, &value);
2980
+ RLITE_SERVER_ERR(c, retval);
2981
+ if (retval == RL_OK) {
2982
+ c->reply = createLongLongObject(value);
2983
+ }
2984
+ cleanup:
2985
+ return;
2986
+ }
2987
+
2988
+ static void setbitCommand(rliteClient *c) {
2989
+ unsigned char *key = UNSIGN(c->argv[1]);
2990
+ long keylen = c->argvlen[1];
2991
+ long long offset;
2992
+ int previousvalue;
2993
+ int bit;
2994
+
2995
+ if (getLongLongFromObjectOrReply(c, c->argv[2], &offset, RLITE_SYNTAXERR) != RLITE_OK) {
2996
+ return;
2997
+ }
2998
+
2999
+ if (c->argvlen[3] != 1 || (c->argv[3][0] != '0' && c->argv[3][0] != '1')) {
3000
+ c->reply = createErrorObject(RLITE_OUTOFRANGEERR);
3001
+ return;
3002
+ }
3003
+
3004
+ bit = c->argv[3][0] == '0' ? 0 : 1;
3005
+ int retval = rl_setbit(c->context->db, key, keylen, offset, bit, &previousvalue);
3006
+ RLITE_SERVER_ERR(c, retval);
3007
+ if (retval == RL_OK) {
3008
+ c->reply = createLongLongObject(previousvalue);
3009
+ } else if (retval == RL_INVALID_PARAMETERS) {
3010
+ c->reply = createErrorObject("ERR bit offset is not an integer or out of range");
3011
+ }
3012
+ cleanup:
3013
+ return;
3014
+ }
3015
+
3016
+ static void pfselftestCommand(rliteClient *c) {
3017
+ if (rl_str_pfselftest() == 0) {
3018
+ c->reply = createStatusObject(RLITE_STR_OK);
3019
+ }
3020
+ }
3021
+
3022
+ static void pfaddCommand(rliteClient *c) {
3023
+ unsigned char *key = UNSIGN(c->argv[1]);
3024
+ long keylen = c->argvlen[1];
3025
+ int updated;
3026
+ unsigned char **elements = NULL;
3027
+ long *elementslen = NULL;
3028
+ int i, elementc = c->argc - 2;
3029
+
3030
+ if (elementc > 0) {
3031
+ elements = malloc(sizeof(unsigned char *) * elementc);
3032
+ if (!elements) {
3033
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
3034
+ goto cleanup;
3035
+ }
3036
+ elementslen = malloc(sizeof(long) * elementc);
3037
+ if (!elementslen) {
3038
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
3039
+ goto cleanup;
3040
+ }
3041
+ for (i = 0; i < elementc; i++) {
3042
+ elements[i] = UNSIGN(c->argv[i + 2]);
3043
+ elementslen[i] = c->argvlen[i + 2];
3044
+ }
3045
+ }
3046
+
3047
+ int retval = rl_pfadd(c->context->db, key, keylen, elementc, elements, elementslen, &updated);
3048
+ RLITE_SERVER_ERR(c, retval);
3049
+ if (retval == RL_OK) {
3050
+ c->reply = createLongLongObject(updated);
3051
+ } else if (retval == RL_INVALID_STATE) {
3052
+ c->reply = createErrorObject("WRONGTYPE Key is not a valid HyperLogLog string value.");
3053
+ }
3054
+ cleanup:
3055
+ free(elements);
3056
+ free(elementslen);
3057
+ return;
3058
+ }
3059
+
3060
+ static void pfcountCommand(rliteClient *c) {
3061
+ long count;
3062
+ const unsigned char **elements = NULL;
3063
+ long *elementslen = NULL;
3064
+ int i, elementc = c->argc - 1;
3065
+
3066
+ elements = malloc(sizeof(unsigned char *) * elementc);
3067
+ if (!elements) {
3068
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
3069
+ goto cleanup;
3070
+ }
3071
+ elementslen = malloc(sizeof(long) * elementc);
3072
+ if (!elementslen) {
3073
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
3074
+ goto cleanup;
3075
+ }
3076
+ for (i = 0; i < elementc; i++) {
3077
+ elements[i] = UNSIGN(c->argv[i + 1]);
3078
+ elementslen[i] = c->argvlen[i + 1];
3079
+ }
3080
+ int retval = rl_pfcount(c->context->db, elementc, elements, elementslen, &count);
3081
+ RLITE_SERVER_ERR(c, retval);
3082
+ if (retval == RL_OK) {
3083
+ c->reply = createLongLongObject(count);
3084
+ } else if (retval == RL_INVALID_STATE) {
3085
+ c->reply = createErrorObject("WRONGTYPE Key is not a valid HyperLogLog string value.");
3086
+ }
3087
+ cleanup:
3088
+ free(elements);
3089
+ free(elementslen);
3090
+ return;
3091
+ }
3092
+
3093
+ static void pfmergeCommand(rliteClient *c) {
3094
+ unsigned char *key = UNSIGN(c->argv[1]);
3095
+ long keylen = c->argvlen[1];
3096
+ const unsigned char **elements = NULL;
3097
+ long *elementslen = NULL;
3098
+ int i, elementc = c->argc - 2;
3099
+
3100
+ elements = malloc(sizeof(unsigned char *) * elementc);
3101
+ if (!elements) {
3102
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
3103
+ goto cleanup;
3104
+ }
3105
+ elementslen = malloc(sizeof(long) * elementc);
3106
+ if (!elementslen) {
3107
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
3108
+ goto cleanup;
3109
+ }
3110
+ for (i = 0; i < elementc; i++) {
3111
+ elements[i] = UNSIGN(c->argv[i + 2]);
3112
+ elementslen[i] = c->argvlen[i + 2];
3113
+ }
3114
+
3115
+ int retval = rl_pfmerge(c->context->db, key, keylen, elementc, elements, elementslen);
3116
+ RLITE_SERVER_ERR(c, retval);
3117
+ if (retval == RL_OK) {
3118
+ c->reply = createStatusObject(RLITE_STR_OK);
3119
+ } else if (retval == RL_INVALID_STATE) {
3120
+ c->reply = createErrorObject("WRONGTYPE Key is not a valid HyperLogLog string value.");
3121
+ }
3122
+ cleanup:
3123
+ free(elements);
3124
+ free(elementslen);
3125
+ return;
3126
+ }
3127
+
3128
+ static void pfdebugCommand(rliteClient *c) {
3129
+ unsigned char *key = UNSIGN(c->argv[2]);
3130
+ long keylen = c->argvlen[2];
3131
+ int retval;
3132
+ int i, size;
3133
+ long *elements = NULL;
3134
+ unsigned char *value = NULL;
3135
+ long valuelen = 0;
3136
+
3137
+ if (!strcasecmp(c->argv[1],"getreg")) {
3138
+ retval = rl_pfdebug_getreg(c->context->db, key, keylen, &size, &elements);
3139
+ RLITE_SERVER_ERR(c, retval);
3140
+ if (retval == RL_OK) {
3141
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
3142
+ c->reply->elements = size;
3143
+ c->reply->element = malloc(sizeof(rliteReply*) * c->reply->elements);
3144
+ if (!c->reply->element) {
3145
+ free(c->reply);
3146
+ c->reply = NULL;
3147
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
3148
+ goto cleanup;
3149
+ }
3150
+ for (i = 0; i < size; i++) {
3151
+ c->reply->element[i] = createLongLongObject(elements[i]);
3152
+ }
3153
+ }
3154
+ }
3155
+ else if (!strcasecmp(c->argv[1],"decode")) {
3156
+ retval = rl_pfdebug_decode(c->context->db, key, keylen, &value, &valuelen);
3157
+ RLITE_SERVER_ERR(c, retval);
3158
+ if (retval == RL_OK) {
3159
+ c->reply = createStringObject((char *)value, valuelen);
3160
+ }
3161
+ }
3162
+ else if (!strcasecmp(c->argv[1],"encoding")) {
3163
+ retval = rl_pfdebug_encoding(c->context->db, key, keylen, &value, &valuelen);
3164
+ RLITE_SERVER_ERR(c, retval);
3165
+ if (retval == RL_OK) {
3166
+ c->reply = createStringObject((char *)value, valuelen);
3167
+ }
3168
+ }
3169
+ else if (!strcasecmp(c->argv[1],"todense")) {
3170
+ retval = rl_pfdebug_todense(c->context->db, key, keylen, &size);
3171
+ RLITE_SERVER_ERR(c, retval);
3172
+ if (retval == RL_OK) {
3173
+ c->reply = createLongLongObject(size);
3174
+ }
3175
+ }
3176
+ cleanup:
3177
+ free(elements);
3178
+ free(value);
3179
+ return;
3180
+ }
3181
+
3182
+ static void expireGenericCommand(rliteClient *c, unsigned long long expires) {
3183
+ unsigned char *key = UNSIGN(c->argv[1]);
3184
+ long keylen = c->argvlen[1];
3185
+ int retval = rl_key_expires(c->context->db, key, keylen, expires);
3186
+ RLITE_SERVER_ERR(c, retval);
3187
+ if (retval == RL_NOT_FOUND) {
3188
+ c->reply = createLongLongObject(0);
3189
+ } else if (retval == RL_OK) {
3190
+ c->reply = createLongLongObject(1);
3191
+ }
3192
+ cleanup:
3193
+ return;
3194
+ }
3195
+
3196
+ static void expireCommand(rliteClient *c) {
3197
+ unsigned long long now = rl_mstime();
3198
+ long long arg;
3199
+ if (getLongLongFromObjectOrReply(c, c->argv[2], &arg, RLITE_SYNTAXERR) != RLITE_OK) {
3200
+ return;
3201
+ }
3202
+ expireGenericCommand(c, now + arg * 1000);
3203
+ }
3204
+
3205
+ static void expireatCommand(rliteClient *c) {
3206
+ long long arg;
3207
+ if (getLongLongFromObjectOrReply(c, c->argv[2], &arg, RLITE_SYNTAXERR) != RLITE_OK) {
3208
+ return;
3209
+ }
3210
+ expireGenericCommand(c, arg * 1000);
3211
+ }
3212
+
3213
+ static void pexpireCommand(rliteClient *c) {
3214
+ unsigned long long now = rl_mstime();
3215
+ long long arg;
3216
+ if (getLongLongFromObjectOrReply(c, c->argv[2], &arg, RLITE_SYNTAXERR) != RLITE_OK) {
3217
+ return;
3218
+ }
3219
+ expireGenericCommand(c, now + arg);
3220
+ }
3221
+
3222
+ static void pexpireatCommand(rliteClient *c) {
3223
+ long long arg;
3224
+ if (getLongLongFromObjectOrReply(c, c->argv[2], &arg, RLITE_SYNTAXERR) != RLITE_OK) {
3225
+ return;
3226
+ }
3227
+ expireGenericCommand(c, arg);
3228
+ }
3229
+
3230
+ static void selectCommand(rliteClient *c) {
3231
+ long long db;
3232
+ if (getLongLongFromObjectOrReply(c, c->argv[1], &db, RLITE_SYNTAXERR) != RLITE_OK) {
3233
+ return;
3234
+ }
3235
+ int retval = rl_select(c->context->db, db);
3236
+ if (retval == RL_INVALID_PARAMETERS) {
3237
+ c->reply = createErrorObject("ERR invalid DB index");
3238
+ return;
3239
+ }
3240
+ RLITE_SERVER_ERR(c, retval);
3241
+ if (retval == RL_OK) {
3242
+ c->reply = createStatusObject(RLITE_STR_OK);
3243
+ }
3244
+ cleanup:
3245
+ return;
3246
+ }
3247
+
3248
+ static void moveCommand(rliteClient *c) {
3249
+ unsigned char *key = UNSIGN(c->argv[1]);
3250
+ long keylen = c->argvlen[1];
3251
+ long long db;
3252
+ if (getLongLongFromObjectOrReply(c, c->argv[2], &db, "ERR index out of range") != RLITE_OK) {
3253
+ return;
3254
+ }
3255
+ int retval = rl_move(c->context->db, key, keylen, db);
3256
+ RLITE_SERVER_ERR(c, retval);
3257
+ if (retval == RL_FOUND || retval == RL_NOT_FOUND) {
3258
+ c->reply = createLongLongObject(0);
3259
+ } else if (retval == RL_OK) {
3260
+ c->reply = createLongLongObject(1);
3261
+ }
3262
+ cleanup:
3263
+ return;
3264
+ }
3265
+
3266
+ static void flushdbCommand(rliteClient *c) {
3267
+ int retval = rl_flushdb(c->context->db);
3268
+ RLITE_SERVER_ERR(c, retval);
3269
+ if (retval == RL_OK) {
3270
+ c->reply = createStatusObject(RLITE_STR_OK);
3271
+ }
3272
+ cleanup:
3273
+ return;
3274
+ }
3275
+
3276
+ static void flushallCommand(rliteClient *c) {
3277
+ int retval = rl_flushall(c->context->db);
3278
+ RLITE_SERVER_ERR(c, retval);
3279
+ if (retval == RL_OK) {
3280
+ c->reply = createStatusObject(RLITE_STR_OK);
3281
+ }
3282
+ cleanup:
3283
+ return;
3284
+ }
3285
+
3286
+ static void delCommand(rliteClient *c) {
3287
+ int deleted = 0, j, retval;
3288
+
3289
+ for (j = 1; j < c->argc; j++) {
3290
+ retval = rl_key_delete_with_value(c->context->db, UNSIGN(c->argv[j]), c->argvlen[j]);
3291
+ if (retval == RL_OK) {
3292
+ deleted++;
3293
+ }
3294
+ }
3295
+ c->reply = createLongLongObject(deleted);
3296
+ }
3297
+ static void renameGenericCommand(rliteClient *c, int overwrite) {
3298
+ unsigned char *src = UNSIGN(c->argv[1]);
3299
+ long srclen = c->argvlen[1];
3300
+ unsigned char *target = UNSIGN(c->argv[2]);
3301
+ long targetlen = c->argvlen[2];
3302
+ int retval = rl_rename(c->context->db, src, srclen, target, targetlen, overwrite);
3303
+ RLITE_SERVER_ERR(c, retval);
3304
+ if (retval == RL_OK && overwrite) {
3305
+ c->reply = createStatusObject(RLITE_STR_OK);
3306
+ } else if (retval == RL_OK && !overwrite) {
3307
+ c->reply = createLongLongObject(1);
3308
+ } else if (retval == RL_FOUND && !overwrite) {
3309
+ c->reply = createLongLongObject(0);
3310
+ }
3311
+ cleanup:
3312
+ return;
3313
+ }
3314
+
3315
+ static void ttlGenericCommand(rliteClient *c, long divisor) {
3316
+ unsigned char *key = UNSIGN(c->argv[1]);
3317
+ long keylen = c->argvlen[1];
3318
+ unsigned long long expires, now;
3319
+ int retval = rl_key_get(c->context->db, key, keylen, NULL, NULL, NULL, &expires, NULL);
3320
+ RLITE_SERVER_ERR(c, retval);
3321
+ if (retval == RL_NOT_FOUND) {
3322
+ c->reply = createLongLongObject(-2);
3323
+ } else if (retval == RL_FOUND) {
3324
+ if (expires == 0) {
3325
+ c->reply = createLongLongObject(-1);
3326
+ } else {
3327
+ now = rl_mstime();
3328
+ c->reply = createLongLongObject((expires - now) / divisor);
3329
+ }
3330
+ }
3331
+ cleanup:
3332
+ return;
3333
+ }
3334
+
3335
+ static void ttlCommand(rliteClient *c) {
3336
+ ttlGenericCommand(c, 1000);
3337
+ }
3338
+
3339
+ static void pttlCommand(rliteClient *c) {
3340
+ ttlGenericCommand(c, 1);
3341
+ }
3342
+
3343
+ static void persistCommand(rliteClient *c) {
3344
+ unsigned char *key = UNSIGN(c->argv[1]);
3345
+ long keylen = c->argvlen[1];
3346
+ long page;
3347
+ unsigned char type;
3348
+ unsigned long long expires;
3349
+ long version = 0;
3350
+ int retval = rl_key_get(c->context->db, key, keylen, &type, NULL, &page, &expires, &version);
3351
+ RLITE_SERVER_ERR(c, retval);
3352
+ if (retval == RL_NOT_FOUND || expires == 0) {
3353
+ c->reply = createLongLongObject(0);
3354
+ goto cleanup;
3355
+ }
3356
+ retval = rl_key_set(c->context->db, key, keylen, type, page, 0, version + 1);
3357
+ RLITE_SERVER_ERR(c, retval);
3358
+ c->reply = createLongLongObject(1);
3359
+ cleanup:
3360
+ return;
3361
+ }
3362
+
3363
+ static void renameCommand(rliteClient *c) {
3364
+ renameGenericCommand(c, 1);
3365
+ }
3366
+
3367
+ static void renamenxCommand(rliteClient *c) {
3368
+ renameGenericCommand(c, 0);
3369
+ }
3370
+
3371
+ static void dbsizeCommand(rliteClient *c) {
3372
+ long size;
3373
+ int retval = rl_dbsize(c->context->db, &size);
3374
+ RLITE_SERVER_ERR(c, retval);
3375
+ if (retval != RL_OK) {
3376
+ goto cleanup;
3377
+ }
3378
+ c->reply = createLongLongObject(size);
3379
+ cleanup:
3380
+ return;
3381
+ }
3382
+
3383
+ static void randomkeyCommand(rliteClient *c) {
3384
+ unsigned char *key = NULL;
3385
+ long keylen;
3386
+ int retval = rl_randomkey(c->context->db, &key, &keylen);
3387
+ RLITE_SERVER_ERR(c, retval);
3388
+ if (retval == RL_OK) {
3389
+ c->reply = createStringObject((char *)key, keylen);
3390
+ } else {
3391
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
3392
+ }
3393
+ cleanup:
3394
+ rl_free(key);
3395
+ return;
3396
+ }
3397
+
3398
+ static void keysCommand(rliteClient *c) {
3399
+ long i, size = 0;
3400
+ unsigned char **result = NULL;
3401
+ long *resultlen = NULL;
3402
+ int retval = rl_keys(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], &size, &result, &resultlen);
3403
+ RLITE_SERVER_ERR(c, retval);
3404
+ if (retval != RL_OK) {
3405
+ goto cleanup;
3406
+ }
3407
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
3408
+ if (retval == RL_NOT_FOUND) {
3409
+ c->reply->elements = 0;
3410
+ return;
3411
+ }
3412
+ c->reply->elements = size;
3413
+ c->reply->element = malloc(sizeof(rliteReply*) * c->reply->elements);
3414
+ if (!c->reply->element) {
3415
+ free(c->reply);
3416
+ c->reply = NULL;
3417
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
3418
+ goto cleanup;
3419
+ }
3420
+
3421
+ for (i = 0; i < size; i++) {
3422
+ c->reply->element[i] = createStringObject((char *)result[i], resultlen[i]);
3423
+ rl_free(result[i]);
3424
+ }
3425
+ rl_free(result);
3426
+ rl_free(resultlen);
3427
+ cleanup:
3428
+ return;
3429
+ }
3430
+
3431
+ static void existsCommand(rliteClient *c) {
3432
+ int retval = rl_key_get(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], NULL, NULL, NULL, NULL, NULL);
3433
+ c->reply = createLongLongObject(retval == RL_FOUND ? 1 : 0);
3434
+ }
3435
+
3436
+ static void typeCommand(rliteClient *c) {
3437
+ unsigned char type;
3438
+ int retval = rl_key_get(c->context->db, UNSIGN(c->argv[1]), c->argvlen[1], &type, NULL, NULL, NULL, NULL);
3439
+ RLITE_SERVER_ERR(c, retval);
3440
+ if (retval == RL_NOT_FOUND) {
3441
+ c->reply = createStringObject("none", 4);
3442
+ }
3443
+ else if (retval == RL_FOUND) {
3444
+ if (type == RL_TYPE_ZSET) {
3445
+ c->reply = createStringObject("zset", 4);
3446
+ }
3447
+ else if (type == RL_TYPE_SET) {
3448
+ c->reply = createStringObject("set", 3);
3449
+ }
3450
+ else if (type == RL_TYPE_HASH) {
3451
+ c->reply = createStringObject("hash", 4);
3452
+ }
3453
+ else if (type == RL_TYPE_LIST) {
3454
+ c->reply = createStringObject("list", 4);
3455
+ }
3456
+ else if (type == RL_TYPE_STRING) {
3457
+ c->reply = createStringObject("string", 6);
3458
+ }
3459
+ }
3460
+ cleanup:
3461
+ return;
3462
+ }
3463
+
3464
+ static void getKeyEncoding(rliteClient *c, char *encoding, unsigned char *key, long keylen)
3465
+ {
3466
+ unsigned char type;
3467
+ encoding[0] = 0;
3468
+ if (rl_key_get(c->context->db, UNSIGN(key), keylen, &type, NULL, NULL, NULL, NULL)) {
3469
+ if (type == RL_TYPE_STRING) {
3470
+ const char *enc = "int";
3471
+ memcpy(encoding, enc, (strlen(enc) + 1) * sizeof(char));
3472
+ }
3473
+ else if (type == RL_TYPE_ZSET) {
3474
+ const char *enc = c->context->debugSkiplist ? "skiplist" : "ziplist";
3475
+ memcpy(encoding, enc, (strlen(enc) + 1) * sizeof(char));
3476
+ }
3477
+ else if (type == RL_TYPE_HASH) {
3478
+ unsigned char *key = UNSIGN(c->argv[2]), *value = NULL;
3479
+ long keylen = c->argvlen[2];
3480
+ long len, valuelen;
3481
+ rl_hash_iterator *iterator = NULL;
3482
+ int retval = rl_hlen(c->context->db, key, keylen, &len);
3483
+ int hashtable = c->context->hashtableLimitEntries < (size_t)len;
3484
+ if (!hashtable) {
3485
+ int retval = rl_hgetall(c->context->db, &iterator, key, keylen);
3486
+ RLITE_SERVER_ERR(c, retval);
3487
+ while ((retval = rl_hash_iterator_next(iterator, NULL, NULL, &value, &valuelen)) == RL_OK) {
3488
+ rl_free(value);
3489
+ if ((size_t)valuelen > c->context->hashtableLimitValue) {
3490
+ hashtable = 1;
3491
+ rl_hash_iterator_destroy(iterator);
3492
+ retval = RL_END;
3493
+ break;
3494
+ }
3495
+ }
3496
+ if (retval != RL_END) {
3497
+ goto cleanup;
3498
+ }
3499
+ }
3500
+ RLITE_SERVER_ERR(c, retval);
3501
+ const char *enc = hashtable ? "hashtable" : "ziplist";
3502
+ memcpy(encoding, enc, (strlen(enc) + 1) * sizeof(char));
3503
+ }
3504
+ else if (type == RL_TYPE_SET) {
3505
+ unsigned char *key = UNSIGN(c->argv[2]), *value = NULL;
3506
+ long keylen = c->argvlen[2];
3507
+ long len, valuelen;
3508
+ rl_set_iterator *iterator = NULL;
3509
+ int retval = rl_scard(c->context->db, key, keylen, &len);
3510
+ RLITE_SERVER_ERR(c, retval);
3511
+ int hashtable = 512 < (size_t)len;
3512
+ if (!hashtable) {
3513
+ char o[40];
3514
+ int retval = rl_smembers(c->context->db, &iterator, key, keylen);
3515
+ RLITE_SERVER_ERR(c, retval);
3516
+ while ((retval = rl_set_iterator_next(iterator, &value, &valuelen)) == RL_OK) {
3517
+ if (valuelen > 38) {
3518
+ hashtable = 1;
3519
+ rl_free(value);
3520
+ rl_set_iterator_destroy(iterator);
3521
+ retval = RL_END;
3522
+ break;
3523
+ }
3524
+ memcpy(o, value, sizeof(char) * valuelen);
3525
+ o[valuelen] = 0;
3526
+ if (getLongLongFromObject(o, NULL) != RLITE_OK) {
3527
+ hashtable = 1;
3528
+ rl_free(value);
3529
+ rl_set_iterator_destroy(iterator);
3530
+ retval = RL_END;
3531
+ break;
3532
+ }
3533
+ rl_free(value);
3534
+ }
3535
+ if (retval != RL_END) {
3536
+ goto cleanup;
3537
+ }
3538
+ }
3539
+ const char *enc = hashtable ? "hashtable" : "intset";
3540
+ memcpy(encoding, enc, (strlen(enc) + 1) * sizeof(char));
3541
+ }
3542
+ else if (type == RL_TYPE_LIST) {
3543
+ unsigned char **values;
3544
+ long *valueslen, size;
3545
+ unsigned char *key = UNSIGN(c->argv[2]);
3546
+ long keylen = c->argvlen[2];
3547
+ long len, i;
3548
+ int retval = rl_llen(c->context->db, key, keylen, &len);
3549
+ RLITE_SERVER_ERR(c, retval);
3550
+ int linkedlist = 256 < (size_t)len;
3551
+ if (!linkedlist) {
3552
+ int retval = rl_lrange(c->context->db, key, keylen, 0, -1, &size, &values, &valueslen);
3553
+ RLITE_SERVER_ERR(c, retval);
3554
+ for (i = 0; i < size; i++) {
3555
+ linkedlist = linkedlist || (valueslen[i] > 16);
3556
+ rl_free(values[i]);
3557
+ }
3558
+ rl_free(values);
3559
+ rl_free(valueslen);
3560
+ }
3561
+ const char *enc = linkedlist ? "linkedlist" : "ziplist";
3562
+ memcpy(encoding, enc, (strlen(enc) + 1) * sizeof(char));
3563
+ }
3564
+ }
3565
+ cleanup:
3566
+ return;
3567
+ }
3568
+
3569
+ static void debugCommand(rliteClient *c) {
3570
+ if (!strcasecmp(c->argv[1],"segfault")) {
3571
+ *((char*)-1) = 'x';
3572
+ } else if (!strcasecmp(c->argv[1],"oom")) {
3573
+ void *ptr = malloc(ULONG_MAX); /* Should trigger an out of memory. */
3574
+ free(ptr);
3575
+ c->reply = createStatusObject(RLITE_STR_OK);
3576
+ } else if (!strcasecmp(c->argv[1],"assert")) {
3577
+ // TODO
3578
+ c->reply = createErrorObject("ERR Not implemented");
3579
+ } else if (!strcasecmp(c->argv[1],"reload")) {
3580
+ c->reply = createStatusObject(RLITE_STR_OK);
3581
+ } else if (!strcasecmp(c->argv[1],"loadaof")) {
3582
+ c->reply = createStatusObject(RLITE_STR_OK);
3583
+ } else if (!strcasecmp(c->argv[1],"object") && c->argc == 3) {
3584
+ char encoding[100];
3585
+ if (rl_key_get(c->context->db, UNSIGN(c->argv[2]), c->argvlen[2], NULL, NULL, NULL, NULL, NULL)) {
3586
+ getKeyEncoding(c, encoding, UNSIGN(c->argv[2]), c->argvlen[2]);
3587
+ addReplyStatusFormat(c->context,
3588
+ "Value at:0xfaceadd refcount:1 "
3589
+ "encoding:%s serializedlength:0 "
3590
+ "lru:0 lru_seconds_idle:0", encoding);
3591
+ }
3592
+ } else if (!strcasecmp(c->argv[1],"sdslen") && c->argc == 3) {
3593
+ // TODO
3594
+ c->reply = createErrorObject("ERR Not implemented");
3595
+ } else if (!strcasecmp(c->argv[1],"populate") &&
3596
+ (c->argc == 3 || c->argc == 4)) {
3597
+ c->reply = createErrorObject("ERR Not implemented");
3598
+ } else if (!strcasecmp(c->argv[1],"digest") && c->argc == 2) {
3599
+ c->reply = createErrorObject("ERR Not implemented");
3600
+ } else if (!strcasecmp(c->argv[1],"sleep") && c->argc == 3) {
3601
+ double dtime = strtod(c->argv[2], NULL);
3602
+ long long utime = dtime*1000000;
3603
+ struct timespec tv;
3604
+
3605
+ tv.tv_sec = utime / 1000000;
3606
+ tv.tv_nsec = (utime % 1000000) * 1000;
3607
+ nanosleep(&tv, NULL);
3608
+ c->reply = createStatusObject(RLITE_STR_OK);
3609
+ } else if (!strcasecmp(c->argv[1],"set-active-expire") &&
3610
+ c->argc == 3)
3611
+ {
3612
+ c->reply = createErrorObject("ERR Not implemented");
3613
+ } else if (!strcasecmp(c->argv[1],"error") && c->argc == 3) {
3614
+ c->reply = createStringObject(c->argv[2], c->argvlen[2]);
3615
+ } else {
3616
+ c->reply = createStringObject(c->argv[2], c->argvlen[2]);
3617
+ addReplyErrorFormat(c->context, "Unknown DEBUG subcommand or wrong number of arguments for '%s'",
3618
+ (char*)c->argv[1]);
3619
+ }
3620
+ }
3621
+
3622
+ static void dumpCommand(rliteClient *c) {
3623
+ unsigned char *key = UNSIGN(c->argv[1]);
3624
+ long keylen = c->argvlen[1];
3625
+ unsigned char *data;
3626
+ long datalen;
3627
+
3628
+ int retval = rl_dump(c->context->db, key, keylen, &data, &datalen);
3629
+ RLITE_SERVER_ERR(c, retval);
3630
+ if (retval == RL_NOT_FOUND) {
3631
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
3632
+ } else if (retval == RL_OK){
3633
+ c->reply = createStringObject((char *)data, datalen);
3634
+ rl_free(data);
3635
+ }
3636
+ cleanup:
3637
+ return;
3638
+ }
3639
+
3640
+ static void restoreCommand(rliteClient *c) {
3641
+ unsigned char *key = UNSIGN(c->argv[1]);
3642
+ long keylen = c->argvlen[1];
3643
+ unsigned char *payload = UNSIGN(c->argv[3]);
3644
+ long payloadlen = c->argvlen[3];
3645
+ long long expires = 0;
3646
+ if (getLongLongFromObjectOrReply(c, c->argv[2], &expires, RLITE_SYNTAXERR) != RLITE_OK) {
3647
+ return;
3648
+ }
3649
+ if (expires != 0) {
3650
+ expires += rl_mstime();
3651
+ }
3652
+
3653
+ int retval;
3654
+ if (c->argc >= 5) {
3655
+ if (c->argvlen[4] == 7 && strcasecmp(c->argv[4], "replace") == 0) {
3656
+ retval = rl_key_delete_with_value(c->context->db, key, keylen);
3657
+ RLITE_SERVER_ERR(c, retval);
3658
+ if (retval != RL_OK && retval != RL_FOUND && retval != RL_NOT_FOUND) {
3659
+ return;
3660
+ }
3661
+ } else {
3662
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
3663
+ return;
3664
+ }
3665
+ }
3666
+
3667
+ retval = rl_restore(c->context->db, key, keylen, expires, payload, payloadlen);
3668
+ RLITE_SERVER_ERR(c, retval);
3669
+ if (retval == RL_FOUND) {
3670
+ c->reply = createErrorObject("BUSYKEY Target key name already exists");
3671
+ } else if (retval == RL_INVALID_PARAMETERS){
3672
+ c->reply = createErrorObject("ERR DUMP payload version or checksum are wrong");
3673
+ } else if (retval == RL_UNEXPECTED){
3674
+ c->reply = createErrorObject("ERR unexpected");
3675
+ } else if (retval == RL_OK){
3676
+ c->reply = createStatusObject(RLITE_STR_OK);
3677
+ }
3678
+ cleanup:
3679
+ return;
3680
+ }
3681
+
3682
+ static void objectCommand(rliteClient *c) {
3683
+ if (!strcasecmp(c->argv[1],"encoding")) {
3684
+ char encoding[100];
3685
+ getKeyEncoding(c, encoding, UNSIGN(c->argv[2]), c->argvlen[2]);
3686
+ c->reply = createCStringObject(encoding);
3687
+ } else {
3688
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
3689
+ }
3690
+ }
3691
+
3692
+ static void sortCommand(rliteClient *c) {
3693
+ int retval;
3694
+ int j, desc = 0, alpha = 0;
3695
+ long limit_start = 0, limit_count = -1;
3696
+ int syntax_error = 0;
3697
+ unsigned char *storekey = NULL, *sortby = NULL;
3698
+ long storekeylen, sortbylen;
3699
+ int dontsort = 0;
3700
+ int getc = 0;
3701
+ // allocing the maximum number possible
3702
+ // this is wasteful, but no need to worry about realloc
3703
+ // and it is not that many probably anyway... hopefully
3704
+ unsigned char **getv = malloc(sizeof(unsigned char *) * c->argc);
3705
+ long *getvlen = malloc(sizeof(long) * c->argc);
3706
+ long i, objc;
3707
+ unsigned char **objv;
3708
+ long *objvlen;
3709
+
3710
+ /* The SORT command has an SQL-alike syntax, parse it */
3711
+ j = 2;
3712
+ while(j < c->argc) {
3713
+ int leftargs = c->argc-j-1;
3714
+ if (!strcasecmp(c->argv[j],"asc")) {
3715
+ desc = 0;
3716
+ } else if (!strcasecmp(c->argv[j],"desc")) {
3717
+ desc = 1;
3718
+ } else if (!strcasecmp(c->argv[j],"alpha")) {
3719
+ alpha = 1;
3720
+ } else if (!strcasecmp(c->argv[j],"limit") && leftargs >= 2) {
3721
+ if ((getLongFromObjectOrReply(c, c->argv[j+1], &limit_start, NULL)
3722
+ != RL_OK) ||
3723
+ (getLongFromObjectOrReply(c, c->argv[j+2], &limit_count, NULL)
3724
+ != RL_OK))
3725
+ {
3726
+ syntax_error++;
3727
+ break;
3728
+ }
3729
+ j+=2;
3730
+ } else if (!strcasecmp(c->argv[j],"store") && leftargs >= 1) {
3731
+ storekey = (unsigned char*)c->argv[j+1];
3732
+ storekeylen = c->argvlen[j+1];
3733
+ j++;
3734
+ } else if (!strcasecmp(c->argv[j],"by") && leftargs >= 1) {
3735
+ sortby = (unsigned char *)c->argv[j+1];
3736
+ sortbylen = c->argvlen[j+1];
3737
+ /* If the BY pattern does not contain '*', i.e. it is constant,
3738
+ * we don't need to sort nor to lookup the weight keys. */
3739
+ if (strchr(c->argv[j+1],'*') == NULL) {
3740
+ dontsort = 1;
3741
+ } else {
3742
+ /* If BY is specified with a real patter, we can't accept
3743
+ * it in cluster mode. */
3744
+ if (c->context->cluster_enabled) {
3745
+ c->reply = createErrorObject("ERR BY option of SORT denied in Cluster mode.");
3746
+ syntax_error++;
3747
+ break;
3748
+ }
3749
+ }
3750
+ j++;
3751
+ } else if (!strcasecmp(c->argv[j],"get") && leftargs >= 1) {
3752
+ if (c->context->cluster_enabled) {
3753
+ c->reply = createErrorObject("ERR GET option of SORT denied in Cluster mode.");
3754
+ syntax_error++;
3755
+ break;
3756
+ }
3757
+ getv[getc] = (unsigned char *)c->argv[j+1];
3758
+ getvlen[getc++] = c->argvlen[j+1];
3759
+ j++;
3760
+ } else {
3761
+ syntax_error++;
3762
+ break;
3763
+ }
3764
+ j++;
3765
+ }
3766
+
3767
+ /* Handle syntax errors set during options parsing. */
3768
+ if (syntax_error) {
3769
+ c->reply = createErrorObject(RLITE_SYNTAXERR);
3770
+ goto cleanup;
3771
+ }
3772
+ retval = rl_sort(c->context->db, (unsigned char *)c->argv[1], c->argvlen[1], sortby, sortbylen, dontsort, alpha, desc, limit_start, limit_count, getc, getv, getvlen, storekey, storekeylen, &objc, &objv, &objvlen);
3773
+ if (retval == RL_NAN) {
3774
+ c->reply = createErrorObject("ERR One or more scores can't be converted into double");
3775
+ goto cleanup;
3776
+ }
3777
+ RLITE_SERVER_ERR(c, retval);
3778
+ if (storekey) {
3779
+ c->reply = createLongLongObject(objc);
3780
+ } else {
3781
+ if (retval == RL_OK) {
3782
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
3783
+ c->reply->elements = objc;
3784
+ c->reply->element = malloc(sizeof(rliteReply*) * c->reply->elements);
3785
+ for (i = 0; i < objc; i++) {
3786
+ c->reply->element[i] = createStringObject((char *)objv[i], objvlen[i]);
3787
+ rl_free(objv[i]);
3788
+ }
3789
+ rl_free(objv);
3790
+ rl_free(objvlen);
3791
+ } else {
3792
+ c->reply = createReplyObject(RLITE_REPLY_ARRAY);
3793
+ c->reply->elements = 0;
3794
+ }
3795
+ }
3796
+ cleanup:
3797
+ free(getv);
3798
+ free(getvlen);
3799
+ }
3800
+
3801
+ struct rliteCommand rliteCommandTable[] = {
3802
+ {"get",getCommand,2,"rF",0,1,1,1,0,0},
3803
+ {"set",setCommand,-3,"wm",0,1,1,1,0,0},
3804
+ {"setnx",setnxCommand,3,"wmF",0,1,1,1,0,0},
3805
+ {"setex",setexCommand,4,"wm",0,1,1,1,0,0},
3806
+ {"psetex",psetexCommand,4,"wm",0,1,1,1,0,0},
3807
+ {"append",appendCommand,3,"wm",0,1,1,1,0,0},
3808
+ {"strlen",strlenCommand,2,"rF",0,1,1,1,0,0},
3809
+ {"del",delCommand,-2,"w",0,1,-1,1,0,0},
3810
+ {"exists",existsCommand,2,"rF",0,1,1,1,0,0},
3811
+ {"setbit",setbitCommand,4,"wm",0,1,1,1,0,0},
3812
+ {"getbit",getbitCommand,3,"rF",0,1,1,1,0,0},
3813
+ {"setrange",setrangeCommand,4,"wm",0,1,1,1,0,0},
3814
+ {"getrange",getrangeCommand,4,"r",0,1,1,1,0,0},
3815
+ {"substr",getrangeCommand,4,"r",0,1,1,1,0,0},
3816
+ {"incr",incrCommand,2,"wmF",0,1,1,1,0,0},
3817
+ {"decr",decrCommand,2,"wmF",0,1,1,1,0,0},
3818
+ {"mget",mgetCommand,-2,"r",0,1,-1,1,0,0},
3819
+ {"rpush",rpushCommand,-3,"wmF",0,1,1,1,0,0},
3820
+ {"lpush",lpushCommand,-3,"wmF",0,1,1,1,0,0},
3821
+ {"rpushx",rpushxCommand,3,"wmF",0,1,1,1,0,0},
3822
+ {"lpushx",lpushxCommand,3,"wmF",0,1,1,1,0,0},
3823
+ {"linsert",linsertCommand,5,"wm",0,1,1,1,0,0},
3824
+ {"rpop",rpopCommand,2,"wF",0,1,1,1,0,0},
3825
+ {"lpop",lpopCommand,2,"wF",0,1,1,1,0,0},
3826
+ // {"brpop",brpopCommand,-3,"ws",0,NULL,1,1,1,0,0},
3827
+ // {"brpoplpush",brpoplpushCommand,4,"wms",0,NULL,1,2,1,0,0},
3828
+ // {"blpop",blpopCommand,-3,"ws",0,NULL,1,-2,1,0,0},
3829
+ {"llen",llenCommand,2,"rF",0,1,1,1,0,0},
3830
+ {"lindex",lindexCommand,3,"r",0,1,1,1,0,0},
3831
+ {"lset",lsetCommand,4,"wm",0,1,1,1,0,0},
3832
+ {"lrange",lrangeCommand,4,"r",0,1,1,1,0,0},
3833
+ {"ltrim",ltrimCommand,4,"w",0,1,1,1,0,0},
3834
+ {"lrem",lremCommand,4,"w",0,1,1,1,0,0},
3835
+ {"rpoplpush",rpoplpushCommand,3,"wm",0,1,2,1,0,0},
3836
+ {"sadd",saddCommand,-3,"wmF",0,1,1,1,0,0},
3837
+ {"srem",sremCommand,-3,"wF",0,1,1,1,0,0},
3838
+ {"smove",smoveCommand,4,"wF",0,1,2,1,0,0},
3839
+ {"sismember",sismemberCommand,3,"rF",0,1,1,1,0,0},
3840
+ {"scard",scardCommand,2,"rF",0,1,1,1,0,0},
3841
+ {"spop",spopCommand,2,"wRsF",0,1,1,1,0,0},
3842
+ {"srandmember",srandmemberCommand,-2,"rR",0,1,1,1,0,0},
3843
+ {"sinter",sinterCommand,-2,"rS",0,1,-1,1,0,0},
3844
+ {"sinterstore",sinterstoreCommand,-3,"wm",0,1,-1,1,0,0},
3845
+ {"sunion",sunionCommand,-2,"rS",0,1,-1,1,0,0},
3846
+ {"sunionstore",sunionstoreCommand,-3,"wm",0,1,-1,1,0,0},
3847
+ {"sdiff",sdiffCommand,-2,"rS",0,1,-1,1,0,0},
3848
+ {"sdiffstore",sdiffstoreCommand,-3,"wm",0,1,-1,1,0,0},
3849
+ {"smembers",sinterCommand,2,"rS",0,1,1,1,0,0},
3850
+ // {"sscan",sscanCommand,-3,"rR",0,NULL,1,1,1,0,0},
3851
+ {"zadd",zaddCommand,-4,"wmF",0,1,1,1,0,0},
3852
+ {"zincrby",zincrbyCommand,4,"wmF",0,1,1,1,0,0},
3853
+ {"zrem",zremCommand,-3,"wF",0,1,1,1,0,0},
3854
+ {"zremrangebyscore",zremrangebyscoreCommand,4,"w",0,1,1,1,0,0},
3855
+ {"zremrangebyrank",zremrangebyrankCommand,4,"w",0,1,1,1,0,0},
3856
+ {"zremrangebylex",zremrangebylexCommand,4,"w",0,1,1,1,0,0},
3857
+ {"zunionstore",zunionstoreCommand,-4,"wm",0,0,0,0,0,0},
3858
+ {"zinterstore",zinterstoreCommand,-4,"wm",0,0,0,0,0,0},
3859
+ {"zrange",zrangeCommand,-4,"r",0,1,1,1,0,0},
3860
+ {"zrangebyscore",zrangebyscoreCommand,-4,"r",0,1,1,1,0,0},
3861
+ {"zrevrangebyscore",zrevrangebyscoreCommand,-4,"r",0,1,1,1,0,0},
3862
+ {"zrangebylex",zrangebylexCommand,-4,"r",0,1,1,1,0,0},
3863
+ {"zrevrangebylex",zrevrangebylexCommand,-4,"r",0,1,1,1,0,0},
3864
+ {"zcount",zcountCommand,4,"rF",0,1,1,1,0,0},
3865
+ {"zlexcount",zlexcountCommand,4,"rF",0,1,1,1,0,0},
3866
+ {"zrevrange",zrevrangeCommand,-4,"r",0,1,1,1,0,0},
3867
+ {"zcard",zcardCommand,2,"rF",0,1,1,1,0,0},
3868
+ {"zscore",zscoreCommand,3,"rF",0,1,1,1,0,0},
3869
+ {"zrank",zrankCommand,3,"rF",0,1,1,1,0,0},
3870
+ {"zrevrank",zrevrankCommand,3,"rF",0,1,1,1,0,0},
3871
+ // {"zscan",zscanCommand,-3,"rR",0,NULL,1,1,1,0,0},
3872
+ {"hset",hsetCommand,4,"wmF",0,1,1,1,0,0},
3873
+ {"hsetnx",hsetnxCommand,4,"wmF",0,1,1,1,0,0},
3874
+ {"hget",hgetCommand,3,"rF",0,1,1,1,0,0},
3875
+ {"hmset",hmsetCommand,-4,"wm",0,1,1,1,0,0},
3876
+ {"hmget",hmgetCommand,-3,"r",0,1,1,1,0,0},
3877
+ {"hincrby",hincrbyCommand,4,"wmF",0,1,1,1,0,0},
3878
+ {"hincrbyfloat",hincrbyfloatCommand,4,"wmF",0,1,1,1,0,0},
3879
+ {"hdel",hdelCommand,-3,"wF",0,1,1,1,0,0},
3880
+ {"hlen",hlenCommand,2,"rF",0,1,1,1,0,0},
3881
+ {"hkeys",hkeysCommand,2,"rS",0,1,1,1,0,0},
3882
+ {"hvals",hvalsCommand,2,"rS",0,1,1,1,0,0},
3883
+ {"hgetall",hgetallCommand,2,"r",0,1,1,1,0,0},
3884
+ {"hexists",hexistsCommand,3,"rF",0,1,1,1,0,0},
3885
+ // {"hscan",hscanCommand,-3,"rR",0,NULL,1,1,1,0,0},
3886
+ {"incrby",incrbyCommand,3,"wmF",0,1,1,1,0,0},
3887
+ {"decrby",decrbyCommand,3,"wmF",0,1,1,1,0,0},
3888
+ {"incrbyfloat",incrbyfloatCommand,3,"wmF",0,1,1,1,0,0},
3889
+ {"getset",getsetCommand,3,"wm",0,1,1,1,0,0},
3890
+ {"mset",msetCommand,-3,"wm",0,1,-1,2,0,0},
3891
+ {"msetnx",msetnxCommand,-3,"wm",0,1,-1,2,0,0},
3892
+ {"randomkey",randomkeyCommand,1,"rR",0,0,0,0,0,0},
3893
+ {"select",selectCommand,2,"rlF",0,0,0,0,0,0},
3894
+ {"move",moveCommand,3,"wF",0,1,1,1,0,0},
3895
+ {"rename",renameCommand,3,"w",0,1,2,1,0,0},
3896
+ {"renamenx",renamenxCommand,3,"wF",0,1,2,1,0,0},
3897
+ {"expire",expireCommand,3,"wF",0,1,1,1,0,0},
3898
+ {"expireat",expireatCommand,3,"wF",0,1,1,1,0,0},
3899
+ {"pexpire",pexpireCommand,3,"wF",0,1,1,1,0,0},
3900
+ {"pexpireat",pexpireatCommand,3,"wF",0,1,1,1,0,0},
3901
+ {"keys",keysCommand,2,"rS",0,0,0,0,0,0},
3902
+ // {"scan",scanCommand,-2,"rR",0,NULL,0,0,0,0,0},
3903
+ {"dbsize",dbsizeCommand,1,"rF",0,0,0,0,0,0},
3904
+ // {"auth",authCommand,2,"rsltF",0,NULL,0,0,0,0,0},
3905
+ {"ping",pingCommand,-1,"rtF",0,0,0,0,0,0},
3906
+ {"echo",echoCommand,2,"rF",0,0,0,0,0,0},
3907
+ // {"save",saveCommand,1,"ars",0,NULL,0,0,0,0,0},
3908
+ // {"bgsave",bgsaveCommand,1,"ar",0,NULL,0,0,0,0,0},
3909
+ // {"bgrewriteaof",bgrewriteaofCommand,1,"ar",0,NULL,0,0,0,0,0},
3910
+ // {"shutdown",shutdownCommand,-1,"arlt",0,NULL,0,0,0,0,0},
3911
+ // {"lastsave",lastsaveCommand,1,"rRF",0,NULL,0,0,0,0,0},
3912
+ {"type",typeCommand,2,"rF",0,1,1,1,0,0},
3913
+ {"multi",multiCommand,1,"rsF",0,0,0,0,0,0},
3914
+ {"exec",execCommand,1,"sM",0,0,0,0,0,0},
3915
+ {"discard",discardCommand,1,"rsF",0,0,0,0,0,0},
3916
+ // {"sync",syncCommand,1,"ars",0,NULL,0,0,0,0,0},
3917
+ // {"psync",syncCommand,3,"ars",0,NULL,0,0,0,0,0},
3918
+ // {"replconf",replconfCommand,-1,"arslt",0,NULL,0,0,0,0,0},
3919
+ {"flushdb",flushdbCommand,1,"w",0,0,0,0,0,0},
3920
+ {"flushall",flushallCommand,1,"w",0,0,0,0,0,0},
3921
+ {"sort",sortCommand,-2,"wm",0,1,1,1,0,0},
3922
+ // {"info",infoCommand,-1,"rlt",0,NULL,0,0,0,0,0},
3923
+ // {"monitor",monitorCommand,1,"ars",0,NULL,0,0,0,0,0},
3924
+ {"ttl",ttlCommand,2,"rF",0,1,1,1,0,0},
3925
+ {"pttl",pttlCommand,2,"rF",0,1,1,1,0,0},
3926
+ {"persist",persistCommand,2,"wF",0,1,1,1,0,0},
3927
+ // {"slaveof",slaveofCommand,3,"ast",0,NULL,0,0,0,0,0},
3928
+ // {"role",roleCommand,1,"last",0,NULL,0,0,0,0,0},
3929
+ {"debug",debugCommand,-2,"as",0,0,0,0,0,0},
3930
+ // {"config",configCommand,-2,"art",0,NULL,0,0,0,0,0},
3931
+ // {"subscribe",subscribeCommand,-2,"rpslt",0,NULL,0,0,0,0,0},
3932
+ // {"unsubscribe",unsubscribeCommand,-1,"rpslt",0,NULL,0,0,0,0,0},
3933
+ // {"psubscribe",psubscribeCommand,-2,"rpslt",0,NULL,0,0,0,0,0},
3934
+ // {"punsubscribe",punsubscribeCommand,-1,"rpslt",0,NULL,0,0,0,0,0},
3935
+ // {"publish",publishCommand,3,"pltrF",0,NULL,0,0,0,0,0},
3936
+ // {"pubsub",pubsubCommand,-2,"pltrR",0,NULL,0,0,0,0,0},
3937
+ {"watch",watchCommand,-2,"rsF",0,1,-1,1,0,0},
3938
+ {"unwatch",unwatchCommand,1,"rsF",0,0,0,0,0,0},
3939
+ // {"cluster",clusterCommand,-2,"ar",0,NULL,0,0,0,0,0},
3940
+ {"restore",restoreCommand,-4,"awm",0,1,1,1,0,0},
3941
+ // {"restore-asking",restoreCommand,-4,"awmk",0,NULL,1,1,1,0,0},
3942
+ // {"migrate",migrateCommand,-6,"aw",0,NULL,0,0,0,0,0},
3943
+ // {"asking",askingCommand,1,"r",0,NULL,0,0,0,0,0},
3944
+ // {"readonly",readonlyCommand,1,"rF",0,NULL,0,0,0,0,0},
3945
+ // {"readwrite",readwriteCommand,1,"rF",0,NULL,0,0,0,0,0},
3946
+ {"dump",dumpCommand,2,"ar",0,1,1,1,0,0},
3947
+ {"object",objectCommand,3,"r",0,2,2,2,0,0},
3948
+ // {"client",clientCommand,-2,"ars",0,NULL,0,0,0,0,0},
3949
+ // {"eval",evalCommand,-3,"s",0,evalGetKeys,0,0,0,0,0},
3950
+ // {"evalsha",evalShaCommand,-3,"s",0,evalGetKeys,0,0,0,0,0},
3951
+ // {"slowlog",slowlogCommand,-2,"r",0,NULL,0,0,0,0,0},
3952
+ // {"script",scriptCommand,-2,"ras",0,NULL,0,0,0,0,0},
3953
+ // {"time",timeCommand,1,"rRF",0,NULL,0,0,0,0,0},
3954
+ {"bitop",bitopCommand,-4,"wm",0,2,-1,1,0,0},
3955
+ {"bitcount",bitcountCommand,-2,"r",0,1,1,1,0,0},
3956
+ {"bitpos",bitposCommand,-3,"r",0,1,1,1,0,0},
3957
+ // {"wait",waitCommand,3,"rs",0,NULL,0,0,0,0,0},
3958
+ // {"command",commandCommand,0,"rlt",0,NULL,0,0,0,0,0},
3959
+ {"pfselftest",pfselftestCommand,1,"r",0,0,0,0,0,0},
3960
+ {"pfadd",pfaddCommand,-2,"wmF",0,1,1,1,0,0},
3961
+ {"pfcount",pfcountCommand,-2,"w",0,1,1,1,0,0},
3962
+ {"pfmerge",pfmergeCommand,-2,"wm",0,1,-1,1,0,0},
3963
+ {"pfdebug",pfdebugCommand,-3,"w",0,0,0,0,0,0},
3964
+ // {"latency",latencyCommand,-2,"arslt",0,NULL,0,0,0,0,0}
3965
+ };
3966
+
3967
+ static struct rliteCommand *lookupCommand(const char *name, size_t len) {
3968
+ char _name[100];
3969
+ if (len >= 100) {
3970
+ return NULL;
3971
+ }
3972
+ memcpy(_name, name, len);
3973
+ _name[len] = '\0';
3974
+ int j;
3975
+ int numcommands = sizeof(rliteCommandTable)/sizeof(struct rliteCommand);
3976
+
3977
+ for (j = 0; j < numcommands; j++) {
3978
+ struct rliteCommand *c = rliteCommandTable+j;
3979
+ if (strcasecmp(c->name, _name) == 0) {
3980
+ return c;
3981
+ }
3982
+ }
3983
+
3984
+ return NULL;
3985
+ }