hirlite 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/LICENSE +28 -0
- data/Rakefile +51 -0
- data/ext/hirlite_ext/extconf.rb +33 -0
- data/ext/hirlite_ext/hirlite_ext.c +14 -0
- data/ext/hirlite_ext/hirlite_ext.h +38 -0
- data/ext/hirlite_ext/rlite.c +351 -0
- data/lib/hirlite/rlite.rb +1 -0
- data/lib/hirlite/version.rb +3 -0
- data/lib/hirlite.rb +2 -0
- data/vendor/rlite/Makefile +6 -0
- data/vendor/rlite/deps/crc64.c +191 -0
- data/vendor/rlite/deps/crc64.h +3 -0
- data/vendor/rlite/deps/endianconv.h +73 -0
- data/vendor/rlite/deps/hyperloglog.c +1547 -0
- data/vendor/rlite/deps/hyperloglog.h +14 -0
- data/vendor/rlite/deps/lzf.h +100 -0
- data/vendor/rlite/deps/lzfP.h +159 -0
- data/vendor/rlite/deps/lzf_c.c +295 -0
- data/vendor/rlite/deps/lzf_d.c +150 -0
- data/vendor/rlite/deps/sha1.c +227 -0
- data/vendor/rlite/deps/sha1.h +19 -0
- data/vendor/rlite/deps/utilfromredis.c +397 -0
- data/vendor/rlite/deps/utilfromredis.h +11 -0
- data/vendor/rlite/src/Makefile +79 -0
- data/vendor/rlite/src/constants.h +15 -0
- data/vendor/rlite/src/dump.c +191 -0
- data/vendor/rlite/src/dump.h +3 -0
- data/vendor/rlite/src/hirlite.c +3985 -0
- data/vendor/rlite/src/hirlite.h +186 -0
- data/vendor/rlite/src/page_btree.c +1556 -0
- data/vendor/rlite/src/page_btree.h +133 -0
- data/vendor/rlite/src/page_key.c +283 -0
- data/vendor/rlite/src/page_key.h +25 -0
- data/vendor/rlite/src/page_list.c +718 -0
- data/vendor/rlite/src/page_list.h +70 -0
- data/vendor/rlite/src/page_long.c +61 -0
- data/vendor/rlite/src/page_long.h +14 -0
- data/vendor/rlite/src/page_multi_string.c +538 -0
- data/vendor/rlite/src/page_multi_string.h +18 -0
- data/vendor/rlite/src/page_skiplist.c +689 -0
- data/vendor/rlite/src/page_skiplist.h +70 -0
- data/vendor/rlite/src/page_string.c +55 -0
- data/vendor/rlite/src/page_string.h +12 -0
- data/vendor/rlite/src/pqsort.c +185 -0
- data/vendor/rlite/src/pqsort.h +40 -0
- data/vendor/rlite/src/restore.c +401 -0
- data/vendor/rlite/src/restore.h +3 -0
- data/vendor/rlite/src/rlite.c +1309 -0
- data/vendor/rlite/src/rlite.h +159 -0
- data/vendor/rlite/src/sort.c +530 -0
- data/vendor/rlite/src/sort.h +18 -0
- data/vendor/rlite/src/status.h +19 -0
- data/vendor/rlite/src/type_hash.c +607 -0
- data/vendor/rlite/src/type_hash.h +29 -0
- data/vendor/rlite/src/type_list.c +477 -0
- data/vendor/rlite/src/type_list.h +23 -0
- data/vendor/rlite/src/type_set.c +796 -0
- data/vendor/rlite/src/type_set.h +34 -0
- data/vendor/rlite/src/type_string.c +613 -0
- data/vendor/rlite/src/type_string.h +34 -0
- data/vendor/rlite/src/type_zset.c +1147 -0
- data/vendor/rlite/src/type_zset.h +50 -0
- data/vendor/rlite/src/util.c +334 -0
- data/vendor/rlite/src/util.h +71 -0
- 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
|
+
}
|