]> git.saurik.com Git - redis.git/blob - redis.c
New protocol fix for LREM
[redis.git] / redis.c
1 /*
2 * Copyright (c) 2006-2009, Salvatore Sanfilippo <antirez at gmail dot com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Redis nor the names of its contributors may be used
14 * to endorse or promote products derived from this software without
15 * specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #define REDIS_VERSION "0.08"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37 #include <signal.h>
38 #include <sys/wait.h>
39 #include <errno.h>
40 #include <assert.h>
41 #include <ctype.h>
42 #include <stdarg.h>
43 #include <inttypes.h>
44 #include <arpa/inet.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <sys/time.h>
48 #include <sys/resource.h>
49
50 #include "ae.h" /* Event driven programming library */
51 #include "sds.h" /* Dynamic safe strings */
52 #include "anet.h" /* Networking the easy way */
53 #include "dict.h" /* Hash tables */
54 #include "adlist.h" /* Linked lists */
55 #include "zmalloc.h" /* total memory usage aware version of malloc/free */
56
57 /* Error codes */
58 #define REDIS_OK 0
59 #define REDIS_ERR -1
60
61 /* Static server configuration */
62 #define REDIS_SERVERPORT 6379 /* TCP port */
63 #define REDIS_MAXIDLETIME (60*5) /* default client timeout */
64 #define REDIS_QUERYBUF_LEN 1024
65 #define REDIS_LOADBUF_LEN 1024
66 #define REDIS_MAX_ARGS 16
67 #define REDIS_DEFAULT_DBNUM 16
68 #define REDIS_CONFIGLINE_MAX 1024
69 #define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
70 #define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
71
72 /* Hash table parameters */
73 #define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
74 #define REDIS_HT_MINSLOTS 16384 /* Never resize the HT under this */
75
76 /* Command flags */
77 #define REDIS_CMD_BULK 1
78 #define REDIS_CMD_INLINE 2
79
80 /* Object types */
81 #define REDIS_STRING 0
82 #define REDIS_LIST 1
83 #define REDIS_SET 2
84 #define REDIS_HASH 3
85 #define REDIS_SELECTDB 254
86 #define REDIS_EOF 255
87
88 /* Client flags */
89 #define REDIS_CLOSE 1 /* This client connection should be closed ASAP */
90 #define REDIS_SLAVE 2 /* This client is a slave server */
91 #define REDIS_MASTER 4 /* This client is a master server */
92 #define REDIS_MONITOR 8 /* This client is a slave monitor, see MONITOR */
93
94 /* Server replication state */
95 #define REDIS_REPL_NONE 0 /* No active replication */
96 #define REDIS_REPL_CONNECT 1 /* Must connect to master */
97 #define REDIS_REPL_CONNECTED 2 /* Connected to master */
98
99 /* List related stuff */
100 #define REDIS_HEAD 0
101 #define REDIS_TAIL 1
102
103 /* Sort operations */
104 #define REDIS_SORT_GET 0
105 #define REDIS_SORT_DEL 1
106 #define REDIS_SORT_INCR 2
107 #define REDIS_SORT_DECR 3
108 #define REDIS_SORT_ASC 4
109 #define REDIS_SORT_DESC 5
110 #define REDIS_SORTKEY_MAX 1024
111
112 /* Log levels */
113 #define REDIS_DEBUG 0
114 #define REDIS_NOTICE 1
115 #define REDIS_WARNING 2
116
117 /* Anti-warning macro... */
118 #define REDIS_NOTUSED(V) ((void) V)
119
120 /*================================= Data types ============================== */
121
122 /* A redis object, that is a type able to hold a string / list / set */
123 typedef struct redisObject {
124 int type;
125 void *ptr;
126 int refcount;
127 } robj;
128
129 /* With multiplexing we need to take per-clinet state.
130 * Clients are taken in a liked list. */
131 typedef struct redisClient {
132 int fd;
133 dict *dict;
134 int dictid;
135 sds querybuf;
136 robj *argv[REDIS_MAX_ARGS];
137 int argc;
138 int bulklen; /* bulk read len. -1 if not in bulk read mode */
139 list *reply;
140 int sentlen;
141 time_t lastinteraction; /* time of the last interaction, used for timeout */
142 int flags; /* REDIS_CLOSE | REDIS_SLAVE | REDIS_MONITOR */
143 int slaveseldb; /* slave selected db, if this client is a slave */
144 } redisClient;
145
146 struct saveparam {
147 time_t seconds;
148 int changes;
149 };
150
151 /* Global server state structure */
152 struct redisServer {
153 int port;
154 int fd;
155 dict **dict;
156 long long dirty; /* changes to DB from the last save */
157 list *clients;
158 list *slaves, *monitors;
159 char neterr[ANET_ERR_LEN];
160 aeEventLoop *el;
161 int cronloops; /* number of times the cron function run */
162 list *objfreelist; /* A list of freed objects to avoid malloc() */
163 time_t lastsave; /* Unix time of last save succeeede */
164 int usedmemory; /* Used memory in megabytes */
165 /* Fields used only for stats */
166 time_t stat_starttime; /* server start time */
167 long long stat_numcommands; /* number of processed commands */
168 long long stat_numconnections; /* number of connections received */
169 /* Configuration */
170 int verbosity;
171 int glueoutputbuf;
172 int maxidletime;
173 int dbnum;
174 int daemonize;
175 char *pidfile;
176 int bgsaveinprogress;
177 struct saveparam *saveparams;
178 int saveparamslen;
179 char *logfile;
180 char *bindaddr;
181 char *dbfilename;
182 /* Replication related */
183 int isslave;
184 char *masterhost;
185 int masterport;
186 redisClient *master;
187 int replstate;
188 /* Sort parameters - qsort_r() is only available under BSD so we
189 * have to take this state global, in order to pass it to sortCompare() */
190 int sort_desc;
191 int sort_alpha;
192 int sort_bypattern;
193 };
194
195 typedef void redisCommandProc(redisClient *c);
196 struct redisCommand {
197 char *name;
198 redisCommandProc *proc;
199 int arity;
200 int flags;
201 };
202
203 typedef struct _redisSortObject {
204 robj *obj;
205 union {
206 double score;
207 robj *cmpobj;
208 } u;
209 } redisSortObject;
210
211 typedef struct _redisSortOperation {
212 int type;
213 robj *pattern;
214 } redisSortOperation;
215
216 struct sharedObjectsStruct {
217 robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *pong, *space,
218 *colon, *nullbulk, *nullmultibulk,
219 *emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr,
220 *outofrangeerr, *plus,
221 *select0, *select1, *select2, *select3, *select4,
222 *select5, *select6, *select7, *select8, *select9;
223 } shared;
224
225 /*================================ Prototypes =============================== */
226
227 static void freeStringObject(robj *o);
228 static void freeListObject(robj *o);
229 static void freeSetObject(robj *o);
230 static void decrRefCount(void *o);
231 static robj *createObject(int type, void *ptr);
232 static void freeClient(redisClient *c);
233 static int loadDb(char *filename);
234 static void addReply(redisClient *c, robj *obj);
235 static void addReplySds(redisClient *c, sds s);
236 static void incrRefCount(robj *o);
237 static int saveDbBackground(char *filename);
238 static robj *createStringObject(char *ptr, size_t len);
239 static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc);
240 static int syncWithMaster(void);
241
242 static void pingCommand(redisClient *c);
243 static void echoCommand(redisClient *c);
244 static void setCommand(redisClient *c);
245 static void setnxCommand(redisClient *c);
246 static void getCommand(redisClient *c);
247 static void delCommand(redisClient *c);
248 static void existsCommand(redisClient *c);
249 static void incrCommand(redisClient *c);
250 static void decrCommand(redisClient *c);
251 static void incrbyCommand(redisClient *c);
252 static void decrbyCommand(redisClient *c);
253 static void selectCommand(redisClient *c);
254 static void randomkeyCommand(redisClient *c);
255 static void keysCommand(redisClient *c);
256 static void dbsizeCommand(redisClient *c);
257 static void lastsaveCommand(redisClient *c);
258 static void saveCommand(redisClient *c);
259 static void bgsaveCommand(redisClient *c);
260 static void shutdownCommand(redisClient *c);
261 static void moveCommand(redisClient *c);
262 static void renameCommand(redisClient *c);
263 static void renamenxCommand(redisClient *c);
264 static void lpushCommand(redisClient *c);
265 static void rpushCommand(redisClient *c);
266 static void lpopCommand(redisClient *c);
267 static void rpopCommand(redisClient *c);
268 static void llenCommand(redisClient *c);
269 static void lindexCommand(redisClient *c);
270 static void lrangeCommand(redisClient *c);
271 static void ltrimCommand(redisClient *c);
272 static void typeCommand(redisClient *c);
273 static void lsetCommand(redisClient *c);
274 static void saddCommand(redisClient *c);
275 static void sremCommand(redisClient *c);
276 static void sismemberCommand(redisClient *c);
277 static void scardCommand(redisClient *c);
278 static void sinterCommand(redisClient *c);
279 static void sinterstoreCommand(redisClient *c);
280 static void syncCommand(redisClient *c);
281 static void flushdbCommand(redisClient *c);
282 static void flushallCommand(redisClient *c);
283 static void sortCommand(redisClient *c);
284 static void lremCommand(redisClient *c);
285 static void infoCommand(redisClient *c);
286 static void mgetCommand(redisClient *c);
287 static void monitorCommand(redisClient *c);
288
289 /*================================= Globals ================================= */
290
291 /* Global vars */
292 static struct redisServer server; /* server global state */
293 static struct redisCommand cmdTable[] = {
294 {"get",getCommand,2,REDIS_CMD_INLINE},
295 {"set",setCommand,3,REDIS_CMD_BULK},
296 {"setnx",setnxCommand,3,REDIS_CMD_BULK},
297 {"del",delCommand,2,REDIS_CMD_INLINE},
298 {"exists",existsCommand,2,REDIS_CMD_INLINE},
299 {"incr",incrCommand,2,REDIS_CMD_INLINE},
300 {"decr",decrCommand,2,REDIS_CMD_INLINE},
301 {"mget",mgetCommand,-2,REDIS_CMD_INLINE},
302 {"rpush",rpushCommand,3,REDIS_CMD_BULK},
303 {"lpush",lpushCommand,3,REDIS_CMD_BULK},
304 {"rpop",rpopCommand,2,REDIS_CMD_INLINE},
305 {"lpop",lpopCommand,2,REDIS_CMD_INLINE},
306 {"llen",llenCommand,2,REDIS_CMD_INLINE},
307 {"lindex",lindexCommand,3,REDIS_CMD_INLINE},
308 {"lset",lsetCommand,4,REDIS_CMD_BULK},
309 {"lrange",lrangeCommand,4,REDIS_CMD_INLINE},
310 {"ltrim",ltrimCommand,4,REDIS_CMD_INLINE},
311 {"lrem",lremCommand,4,REDIS_CMD_BULK},
312 {"sadd",saddCommand,3,REDIS_CMD_BULK},
313 {"srem",sremCommand,3,REDIS_CMD_BULK},
314 {"sismember",sismemberCommand,3,REDIS_CMD_BULK},
315 {"scard",scardCommand,2,REDIS_CMD_INLINE},
316 {"sinter",sinterCommand,-2,REDIS_CMD_INLINE},
317 {"sinterstore",sinterstoreCommand,-3,REDIS_CMD_INLINE},
318 {"smembers",sinterCommand,2,REDIS_CMD_INLINE},
319 {"incrby",incrbyCommand,3,REDIS_CMD_INLINE},
320 {"decrby",decrbyCommand,3,REDIS_CMD_INLINE},
321 {"randomkey",randomkeyCommand,1,REDIS_CMD_INLINE},
322 {"select",selectCommand,2,REDIS_CMD_INLINE},
323 {"move",moveCommand,3,REDIS_CMD_INLINE},
324 {"rename",renameCommand,3,REDIS_CMD_INLINE},
325 {"renamenx",renamenxCommand,3,REDIS_CMD_INLINE},
326 {"keys",keysCommand,2,REDIS_CMD_INLINE},
327 {"dbsize",dbsizeCommand,1,REDIS_CMD_INLINE},
328 {"ping",pingCommand,1,REDIS_CMD_INLINE},
329 {"echo",echoCommand,2,REDIS_CMD_BULK},
330 {"save",saveCommand,1,REDIS_CMD_INLINE},
331 {"bgsave",bgsaveCommand,1,REDIS_CMD_INLINE},
332 {"shutdown",shutdownCommand,1,REDIS_CMD_INLINE},
333 {"lastsave",lastsaveCommand,1,REDIS_CMD_INLINE},
334 {"type",typeCommand,2,REDIS_CMD_INLINE},
335 {"sync",syncCommand,1,REDIS_CMD_INLINE},
336 {"flushdb",flushdbCommand,1,REDIS_CMD_INLINE},
337 {"flushall",flushallCommand,1,REDIS_CMD_INLINE},
338 {"sort",sortCommand,-2,REDIS_CMD_INLINE},
339 {"info",infoCommand,1,REDIS_CMD_INLINE},
340 {"monitor",monitorCommand,1,REDIS_CMD_INLINE},
341 {NULL,NULL,0,0}
342 };
343
344 /*============================ Utility functions ============================ */
345
346 /* Glob-style pattern matching. */
347 int stringmatchlen(const char *pattern, int patternLen,
348 const char *string, int stringLen, int nocase)
349 {
350 while(patternLen) {
351 switch(pattern[0]) {
352 case '*':
353 while (pattern[1] == '*') {
354 pattern++;
355 patternLen--;
356 }
357 if (patternLen == 1)
358 return 1; /* match */
359 while(stringLen) {
360 if (stringmatchlen(pattern+1, patternLen-1,
361 string, stringLen, nocase))
362 return 1; /* match */
363 string++;
364 stringLen--;
365 }
366 return 0; /* no match */
367 break;
368 case '?':
369 if (stringLen == 0)
370 return 0; /* no match */
371 string++;
372 stringLen--;
373 break;
374 case '[':
375 {
376 int not, match;
377
378 pattern++;
379 patternLen--;
380 not = pattern[0] == '^';
381 if (not) {
382 pattern++;
383 patternLen--;
384 }
385 match = 0;
386 while(1) {
387 if (pattern[0] == '\\') {
388 pattern++;
389 patternLen--;
390 if (pattern[0] == string[0])
391 match = 1;
392 } else if (pattern[0] == ']') {
393 break;
394 } else if (patternLen == 0) {
395 pattern--;
396 patternLen++;
397 break;
398 } else if (pattern[1] == '-' && patternLen >= 3) {
399 int start = pattern[0];
400 int end = pattern[2];
401 int c = string[0];
402 if (start > end) {
403 int t = start;
404 start = end;
405 end = t;
406 }
407 if (nocase) {
408 start = tolower(start);
409 end = tolower(end);
410 c = tolower(c);
411 }
412 pattern += 2;
413 patternLen -= 2;
414 if (c >= start && c <= end)
415 match = 1;
416 } else {
417 if (!nocase) {
418 if (pattern[0] == string[0])
419 match = 1;
420 } else {
421 if (tolower((int)pattern[0]) == tolower((int)string[0]))
422 match = 1;
423 }
424 }
425 pattern++;
426 patternLen--;
427 }
428 if (not)
429 match = !match;
430 if (!match)
431 return 0; /* no match */
432 string++;
433 stringLen--;
434 break;
435 }
436 case '\\':
437 if (patternLen >= 2) {
438 pattern++;
439 patternLen--;
440 }
441 /* fall through */
442 default:
443 if (!nocase) {
444 if (pattern[0] != string[0])
445 return 0; /* no match */
446 } else {
447 if (tolower((int)pattern[0]) != tolower((int)string[0]))
448 return 0; /* no match */
449 }
450 string++;
451 stringLen--;
452 break;
453 }
454 pattern++;
455 patternLen--;
456 if (stringLen == 0) {
457 while(*pattern == '*') {
458 pattern++;
459 patternLen--;
460 }
461 break;
462 }
463 }
464 if (patternLen == 0 && stringLen == 0)
465 return 1;
466 return 0;
467 }
468
469 void redisLog(int level, const char *fmt, ...)
470 {
471 va_list ap;
472 FILE *fp;
473
474 fp = (server.logfile == NULL) ? stdout : fopen(server.logfile,"a");
475 if (!fp) return;
476
477 va_start(ap, fmt);
478 if (level >= server.verbosity) {
479 char *c = ".-*";
480 fprintf(fp,"%c ",c[level]);
481 vfprintf(fp, fmt, ap);
482 fprintf(fp,"\n");
483 fflush(fp);
484 }
485 va_end(ap);
486
487 if (server.logfile) fclose(fp);
488 }
489
490 /*====================== Hash table type implementation ==================== */
491
492 /* This is an hash table type that uses the SDS dynamic strings libary as
493 * keys and radis objects as values (objects can hold SDS strings,
494 * lists, sets). */
495
496 static int sdsDictKeyCompare(void *privdata, const void *key1,
497 const void *key2)
498 {
499 int l1,l2;
500 DICT_NOTUSED(privdata);
501
502 l1 = sdslen((sds)key1);
503 l2 = sdslen((sds)key2);
504 if (l1 != l2) return 0;
505 return memcmp(key1, key2, l1) == 0;
506 }
507
508 static void dictRedisObjectDestructor(void *privdata, void *val)
509 {
510 DICT_NOTUSED(privdata);
511
512 decrRefCount(val);
513 }
514
515 static int dictSdsKeyCompare(void *privdata, const void *key1,
516 const void *key2)
517 {
518 const robj *o1 = key1, *o2 = key2;
519 return sdsDictKeyCompare(privdata,o1->ptr,o2->ptr);
520 }
521
522 static unsigned int dictSdsHash(const void *key) {
523 const robj *o = key;
524 return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
525 }
526
527 static dictType setDictType = {
528 dictSdsHash, /* hash function */
529 NULL, /* key dup */
530 NULL, /* val dup */
531 dictSdsKeyCompare, /* key compare */
532 dictRedisObjectDestructor, /* key destructor */
533 NULL /* val destructor */
534 };
535
536 static dictType hashDictType = {
537 dictSdsHash, /* hash function */
538 NULL, /* key dup */
539 NULL, /* val dup */
540 dictSdsKeyCompare, /* key compare */
541 dictRedisObjectDestructor, /* key destructor */
542 dictRedisObjectDestructor /* val destructor */
543 };
544
545 /* ========================= Random utility functions ======================= */
546
547 /* Redis generally does not try to recover from out of memory conditions
548 * when allocating objects or strings, it is not clear if it will be possible
549 * to report this condition to the client since the networking layer itself
550 * is based on heap allocation for send buffers, so we simply abort.
551 * At least the code will be simpler to read... */
552 static void oom(const char *msg) {
553 fprintf(stderr, "%s: Out of memory\n",msg);
554 fflush(stderr);
555 sleep(1);
556 abort();
557 }
558
559 /* ====================== Redis server networking stuff ===================== */
560 void closeTimedoutClients(void) {
561 redisClient *c;
562 listIter *li;
563 listNode *ln;
564 time_t now = time(NULL);
565
566 li = listGetIterator(server.clients,AL_START_HEAD);
567 if (!li) return;
568 while ((ln = listNextElement(li)) != NULL) {
569 c = listNodeValue(ln);
570 if (!(c->flags & REDIS_SLAVE) && /* no timeout for slaves */
571 (now - c->lastinteraction > server.maxidletime)) {
572 redisLog(REDIS_DEBUG,"Closing idle client");
573 freeClient(c);
574 }
575 }
576 listReleaseIterator(li);
577 }
578
579 int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
580 int j, size, used, loops = server.cronloops++;
581 REDIS_NOTUSED(eventLoop);
582 REDIS_NOTUSED(id);
583 REDIS_NOTUSED(clientData);
584
585 /* Update the global state with the amount of used memory */
586 server.usedmemory = zmalloc_used_memory();
587
588 /* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
589 * we resize the hash table to save memory */
590 for (j = 0; j < server.dbnum; j++) {
591 size = dictGetHashTableSize(server.dict[j]);
592 used = dictGetHashTableUsed(server.dict[j]);
593 if (!(loops % 5) && used > 0) {
594 redisLog(REDIS_DEBUG,"DB %d: %d keys in %d slots HT.",j,used,size);
595 // dictPrintStats(server.dict);
596 }
597 if (size && used && size > REDIS_HT_MINSLOTS &&
598 (used*100/size < REDIS_HT_MINFILL)) {
599 redisLog(REDIS_NOTICE,"The hash table %d is too sparse, resize it...",j);
600 dictResize(server.dict[j]);
601 redisLog(REDIS_NOTICE,"Hash table %d resized.",j);
602 }
603 }
604
605 /* Show information about connected clients */
606 if (!(loops % 5)) {
607 redisLog(REDIS_DEBUG,"%d clients connected (%d slaves), %d bytes in use",
608 listLength(server.clients)-listLength(server.slaves),
609 listLength(server.slaves),
610 server.usedmemory);
611 }
612
613 /* Close connections of timedout clients */
614 if (!(loops % 10))
615 closeTimedoutClients();
616
617 /* Check if a background saving in progress terminated */
618 if (server.bgsaveinprogress) {
619 int statloc;
620 if (wait4(-1,&statloc,WNOHANG,NULL)) {
621 int exitcode = WEXITSTATUS(statloc);
622 if (exitcode == 0) {
623 redisLog(REDIS_NOTICE,
624 "Background saving terminated with success");
625 server.dirty = 0;
626 server.lastsave = time(NULL);
627 } else {
628 redisLog(REDIS_WARNING,
629 "Background saving error");
630 }
631 server.bgsaveinprogress = 0;
632 }
633 } else {
634 /* If there is not a background saving in progress check if
635 * we have to save now */
636 time_t now = time(NULL);
637 for (j = 0; j < server.saveparamslen; j++) {
638 struct saveparam *sp = server.saveparams+j;
639
640 if (server.dirty >= sp->changes &&
641 now-server.lastsave > sp->seconds) {
642 redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...",
643 sp->changes, sp->seconds);
644 saveDbBackground(server.dbfilename);
645 break;
646 }
647 }
648 }
649 /* Check if we should connect to a MASTER */
650 if (server.replstate == REDIS_REPL_CONNECT) {
651 redisLog(REDIS_NOTICE,"Connecting to MASTER...");
652 if (syncWithMaster() == REDIS_OK) {
653 redisLog(REDIS_NOTICE,"MASTER <-> SLAVE sync succeeded");
654 }
655 }
656 return 1000;
657 }
658
659 static void createSharedObjects(void) {
660 shared.crlf = createObject(REDIS_STRING,sdsnew("\r\n"));
661 shared.ok = createObject(REDIS_STRING,sdsnew("+OK\r\n"));
662 shared.err = createObject(REDIS_STRING,sdsnew("-ERR\r\n"));
663 shared.emptybulk = createObject(REDIS_STRING,sdsnew("$0\r\n\r\n"));
664 shared.czero = createObject(REDIS_STRING,sdsnew(":0\r\n"));
665 shared.cone = createObject(REDIS_STRING,sdsnew(":1\r\n"));
666 shared.nullbulk = createObject(REDIS_STRING,sdsnew("$-1\r\n"));
667 shared.nullmultibulk = createObject(REDIS_STRING,sdsnew("*-1\r\n"));
668 shared.emptymultibulk = createObject(REDIS_STRING,sdsnew("*0\r\n"));
669 /* no such key */
670 shared.pong = createObject(REDIS_STRING,sdsnew("+PONG\r\n"));
671 shared.wrongtypeerr = createObject(REDIS_STRING,sdsnew(
672 "-ERR Operation against a key holding the wrong kind of value\r\n"));
673 shared.nokeyerr = createObject(REDIS_STRING,sdsnew(
674 "-ERR no such key\r\n"));
675 shared.syntaxerr = createObject(REDIS_STRING,sdsnew(
676 "-ERR syntax error\r\n"));
677 shared.sameobjecterr = createObject(REDIS_STRING,sdsnew(
678 "-ERR source and destination objects are the same\r\n"));
679 shared.outofrangeerr = createObject(REDIS_STRING,sdsnew(
680 "-ERR index out of range\r\n"));
681 shared.space = createObject(REDIS_STRING,sdsnew(" "));
682 shared.colon = createObject(REDIS_STRING,sdsnew(":"));
683 shared.plus = createObject(REDIS_STRING,sdsnew("+"));
684 shared.select0 = createStringObject("select 0\r\n",10);
685 shared.select1 = createStringObject("select 1\r\n",10);
686 shared.select2 = createStringObject("select 2\r\n",10);
687 shared.select3 = createStringObject("select 3\r\n",10);
688 shared.select4 = createStringObject("select 4\r\n",10);
689 shared.select5 = createStringObject("select 5\r\n",10);
690 shared.select6 = createStringObject("select 6\r\n",10);
691 shared.select7 = createStringObject("select 7\r\n",10);
692 shared.select8 = createStringObject("select 8\r\n",10);
693 shared.select9 = createStringObject("select 9\r\n",10);
694 }
695
696 static void appendServerSaveParams(time_t seconds, int changes) {
697 server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));
698 if (server.saveparams == NULL) oom("appendServerSaveParams");
699 server.saveparams[server.saveparamslen].seconds = seconds;
700 server.saveparams[server.saveparamslen].changes = changes;
701 server.saveparamslen++;
702 }
703
704 static void ResetServerSaveParams() {
705 zfree(server.saveparams);
706 server.saveparams = NULL;
707 server.saveparamslen = 0;
708 }
709
710 static void initServerConfig() {
711 server.dbnum = REDIS_DEFAULT_DBNUM;
712 server.port = REDIS_SERVERPORT;
713 server.verbosity = REDIS_DEBUG;
714 server.maxidletime = REDIS_MAXIDLETIME;
715 server.saveparams = NULL;
716 server.logfile = NULL; /* NULL = log on standard output */
717 server.bindaddr = NULL;
718 server.glueoutputbuf = 1;
719 server.daemonize = 0;
720 server.pidfile = "/var/run/redis.pid";
721 server.dbfilename = "dump.rdb";
722 ResetServerSaveParams();
723
724 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
725 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
726 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
727 /* Replication related */
728 server.isslave = 0;
729 server.masterhost = NULL;
730 server.masterport = 6379;
731 server.master = NULL;
732 server.replstate = REDIS_REPL_NONE;
733 }
734
735 static void initServer() {
736 int j;
737
738 signal(SIGHUP, SIG_IGN);
739 signal(SIGPIPE, SIG_IGN);
740
741 server.clients = listCreate();
742 server.slaves = listCreate();
743 server.monitors = listCreate();
744 server.objfreelist = listCreate();
745 createSharedObjects();
746 server.el = aeCreateEventLoop();
747 server.dict = zmalloc(sizeof(dict*)*server.dbnum);
748 if (!server.dict || !server.clients || !server.slaves || !server.monitors || !server.el || !server.objfreelist)
749 oom("server initialization"); /* Fatal OOM */
750 server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr);
751 if (server.fd == -1) {
752 redisLog(REDIS_WARNING, "Opening TCP port: %s", server.neterr);
753 exit(1);
754 }
755 for (j = 0; j < server.dbnum; j++) {
756 server.dict[j] = dictCreate(&hashDictType,NULL);
757 if (!server.dict[j])
758 oom("dictCreate"); /* Fatal OOM */
759 }
760 server.cronloops = 0;
761 server.bgsaveinprogress = 0;
762 server.lastsave = time(NULL);
763 server.dirty = 0;
764 server.usedmemory = 0;
765 server.stat_numcommands = 0;
766 server.stat_numconnections = 0;
767 server.stat_starttime = time(NULL);
768 aeCreateTimeEvent(server.el, 1000, serverCron, NULL, NULL);
769 }
770
771 /* Empty the whole database */
772 static void emptyDb() {
773 int j;
774
775 for (j = 0; j < server.dbnum; j++)
776 dictEmpty(server.dict[j]);
777 }
778
779 /* I agree, this is a very rudimental way to load a configuration...
780 will improve later if the config gets more complex */
781 static void loadServerConfig(char *filename) {
782 FILE *fp = fopen(filename,"r");
783 char buf[REDIS_CONFIGLINE_MAX+1], *err = NULL;
784 int linenum = 0;
785 sds line = NULL;
786
787 if (!fp) {
788 redisLog(REDIS_WARNING,"Fatal error, can't open config file");
789 exit(1);
790 }
791 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL) {
792 sds *argv;
793 int argc, j;
794
795 linenum++;
796 line = sdsnew(buf);
797 line = sdstrim(line," \t\r\n");
798
799 /* Skip comments and blank lines*/
800 if (line[0] == '#' || line[0] == '\0') {
801 sdsfree(line);
802 continue;
803 }
804
805 /* Split into arguments */
806 argv = sdssplitlen(line,sdslen(line)," ",1,&argc);
807 sdstolower(argv[0]);
808
809 /* Execute config directives */
810 if (!strcmp(argv[0],"timeout") && argc == 2) {
811 server.maxidletime = atoi(argv[1]);
812 if (server.maxidletime < 1) {
813 err = "Invalid timeout value"; goto loaderr;
814 }
815 } else if (!strcmp(argv[0],"port") && argc == 2) {
816 server.port = atoi(argv[1]);
817 if (server.port < 1 || server.port > 65535) {
818 err = "Invalid port"; goto loaderr;
819 }
820 } else if (!strcmp(argv[0],"bind") && argc == 2) {
821 server.bindaddr = zstrdup(argv[1]);
822 } else if (!strcmp(argv[0],"save") && argc == 3) {
823 int seconds = atoi(argv[1]);
824 int changes = atoi(argv[2]);
825 if (seconds < 1 || changes < 0) {
826 err = "Invalid save parameters"; goto loaderr;
827 }
828 appendServerSaveParams(seconds,changes);
829 } else if (!strcmp(argv[0],"dir") && argc == 2) {
830 if (chdir(argv[1]) == -1) {
831 redisLog(REDIS_WARNING,"Can't chdir to '%s': %s",
832 argv[1], strerror(errno));
833 exit(1);
834 }
835 } else if (!strcmp(argv[0],"loglevel") && argc == 2) {
836 if (!strcmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG;
837 else if (!strcmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE;
838 else if (!strcmp(argv[1],"warning")) server.verbosity = REDIS_WARNING;
839 else {
840 err = "Invalid log level. Must be one of debug, notice, warning";
841 goto loaderr;
842 }
843 } else if (!strcmp(argv[0],"logfile") && argc == 2) {
844 FILE *fp;
845
846 server.logfile = zstrdup(argv[1]);
847 if (!strcmp(server.logfile,"stdout")) {
848 zfree(server.logfile);
849 server.logfile = NULL;
850 }
851 if (server.logfile) {
852 /* Test if we are able to open the file. The server will not
853 * be able to abort just for this problem later... */
854 fp = fopen(server.logfile,"a");
855 if (fp == NULL) {
856 err = sdscatprintf(sdsempty(),
857 "Can't open the log file: %s", strerror(errno));
858 goto loaderr;
859 }
860 fclose(fp);
861 }
862 } else if (!strcmp(argv[0],"databases") && argc == 2) {
863 server.dbnum = atoi(argv[1]);
864 if (server.dbnum < 1) {
865 err = "Invalid number of databases"; goto loaderr;
866 }
867 } else if (!strcmp(argv[0],"slaveof") && argc == 3) {
868 server.masterhost = sdsnew(argv[1]);
869 server.masterport = atoi(argv[2]);
870 server.replstate = REDIS_REPL_CONNECT;
871 } else if (!strcmp(argv[0],"glueoutputbuf") && argc == 2) {
872 sdstolower(argv[1]);
873 if (!strcmp(argv[1],"yes")) server.glueoutputbuf = 1;
874 else if (!strcmp(argv[1],"no")) server.glueoutputbuf = 0;
875 else {
876 err = "argument must be 'yes' or 'no'"; goto loaderr;
877 }
878 } else if (!strcmp(argv[0],"daemonize") && argc == 2) {
879 sdstolower(argv[1]);
880 if (!strcmp(argv[1],"yes")) server.daemonize = 1;
881 else if (!strcmp(argv[1],"no")) server.daemonize = 0;
882 else {
883 err = "argument must be 'yes' or 'no'"; goto loaderr;
884 }
885 } else if (!strcmp(argv[0],"pidfile") && argc == 2) {
886 server.pidfile = zstrdup(argv[1]);
887 } else {
888 err = "Bad directive or wrong number of arguments"; goto loaderr;
889 }
890 for (j = 0; j < argc; j++)
891 sdsfree(argv[j]);
892 zfree(argv);
893 sdsfree(line);
894 }
895 fclose(fp);
896 return;
897
898 loaderr:
899 fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n");
900 fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
901 fprintf(stderr, ">>> '%s'\n", line);
902 fprintf(stderr, "%s\n", err);
903 exit(1);
904 }
905
906 static void freeClientArgv(redisClient *c) {
907 int j;
908
909 for (j = 0; j < c->argc; j++)
910 decrRefCount(c->argv[j]);
911 c->argc = 0;
912 }
913
914 static void freeClient(redisClient *c) {
915 listNode *ln;
916
917 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
918 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
919 sdsfree(c->querybuf);
920 listRelease(c->reply);
921 freeClientArgv(c);
922 close(c->fd);
923 ln = listSearchKey(server.clients,c);
924 assert(ln != NULL);
925 listDelNode(server.clients,ln);
926 if (c->flags & REDIS_SLAVE) {
927 list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
928 ln = listSearchKey(l,c);
929 assert(ln != NULL);
930 listDelNode(l,ln);
931 }
932 if (c->flags & REDIS_MASTER) {
933 server.master = NULL;
934 server.replstate = REDIS_REPL_CONNECT;
935 }
936 zfree(c);
937 }
938
939 static void glueReplyBuffersIfNeeded(redisClient *c) {
940 int totlen = 0;
941 listNode *ln = c->reply->head, *next;
942 robj *o;
943
944 while(ln) {
945 o = ln->value;
946 totlen += sdslen(o->ptr);
947 ln = ln->next;
948 /* This optimization makes more sense if we don't have to copy
949 * too much data */
950 if (totlen > 1024) return;
951 }
952 if (totlen > 0) {
953 char buf[1024];
954 int copylen = 0;
955
956 ln = c->reply->head;
957 while(ln) {
958 next = ln->next;
959 o = ln->value;
960 memcpy(buf+copylen,o->ptr,sdslen(o->ptr));
961 copylen += sdslen(o->ptr);
962 listDelNode(c->reply,ln);
963 ln = next;
964 }
965 /* Now the output buffer is empty, add the new single element */
966 addReplySds(c,sdsnewlen(buf,totlen));
967 }
968 }
969
970 static void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
971 redisClient *c = privdata;
972 int nwritten = 0, totwritten = 0, objlen;
973 robj *o;
974 REDIS_NOTUSED(el);
975 REDIS_NOTUSED(mask);
976
977 if (server.glueoutputbuf && listLength(c->reply) > 1)
978 glueReplyBuffersIfNeeded(c);
979 while(listLength(c->reply)) {
980 o = listNodeValue(listFirst(c->reply));
981 objlen = sdslen(o->ptr);
982
983 if (objlen == 0) {
984 listDelNode(c->reply,listFirst(c->reply));
985 continue;
986 }
987
988 if (c->flags & REDIS_MASTER) {
989 nwritten = objlen - c->sentlen;
990 } else {
991 nwritten = write(fd, o->ptr+c->sentlen, objlen - c->sentlen);
992 if (nwritten <= 0) break;
993 }
994 c->sentlen += nwritten;
995 totwritten += nwritten;
996 /* If we fully sent the object on head go to the next one */
997 if (c->sentlen == objlen) {
998 listDelNode(c->reply,listFirst(c->reply));
999 c->sentlen = 0;
1000 }
1001 }
1002 if (nwritten == -1) {
1003 if (errno == EAGAIN) {
1004 nwritten = 0;
1005 } else {
1006 redisLog(REDIS_DEBUG,
1007 "Error writing to client: %s", strerror(errno));
1008 freeClient(c);
1009 return;
1010 }
1011 }
1012 if (totwritten > 0) c->lastinteraction = time(NULL);
1013 if (listLength(c->reply) == 0) {
1014 c->sentlen = 0;
1015 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
1016 }
1017 }
1018
1019 static struct redisCommand *lookupCommand(char *name) {
1020 int j = 0;
1021 while(cmdTable[j].name != NULL) {
1022 if (!strcmp(name,cmdTable[j].name)) return &cmdTable[j];
1023 j++;
1024 }
1025 return NULL;
1026 }
1027
1028 /* resetClient prepare the client to process the next command */
1029 static void resetClient(redisClient *c) {
1030 freeClientArgv(c);
1031 c->bulklen = -1;
1032 }
1033
1034 /* If this function gets called we already read a whole
1035 * command, argments are in the client argv/argc fields.
1036 * processCommand() execute the command or prepare the
1037 * server for a bulk read from the client.
1038 *
1039 * If 1 is returned the client is still alive and valid and
1040 * and other operations can be performed by the caller. Otherwise
1041 * if 0 is returned the client was destroied (i.e. after QUIT). */
1042 static int processCommand(redisClient *c) {
1043 struct redisCommand *cmd;
1044 long long dirty;
1045
1046 sdstolower(c->argv[0]->ptr);
1047 /* The QUIT command is handled as a special case. Normal command
1048 * procs are unable to close the client connection safely */
1049 if (!strcmp(c->argv[0]->ptr,"quit")) {
1050 freeClient(c);
1051 return 0;
1052 }
1053 cmd = lookupCommand(c->argv[0]->ptr);
1054 if (!cmd) {
1055 addReplySds(c,sdsnew("-ERR unknown command\r\n"));
1056 resetClient(c);
1057 return 1;
1058 } else if ((cmd->arity > 0 && cmd->arity != c->argc) ||
1059 (c->argc < -cmd->arity)) {
1060 addReplySds(c,sdsnew("-ERR wrong number of arguments\r\n"));
1061 resetClient(c);
1062 return 1;
1063 } else if (cmd->flags & REDIS_CMD_BULK && c->bulklen == -1) {
1064 int bulklen = atoi(c->argv[c->argc-1]->ptr);
1065
1066 decrRefCount(c->argv[c->argc-1]);
1067 if (bulklen < 0 || bulklen > 1024*1024*1024) {
1068 c->argc--;
1069 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
1070 resetClient(c);
1071 return 1;
1072 }
1073 c->argc--;
1074 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
1075 /* It is possible that the bulk read is already in the
1076 * buffer. Check this condition and handle it accordingly */
1077 if ((signed)sdslen(c->querybuf) >= c->bulklen) {
1078 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
1079 c->argc++;
1080 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
1081 } else {
1082 return 1;
1083 }
1084 }
1085 /* Exec the command */
1086 dirty = server.dirty;
1087 cmd->proc(c);
1088 if (server.dirty-dirty != 0 && listLength(server.slaves))
1089 replicationFeedSlaves(server.slaves,cmd,c->dictid,c->argv,c->argc);
1090 if (listLength(server.monitors))
1091 replicationFeedSlaves(server.monitors,cmd,c->dictid,c->argv,c->argc);
1092 server.stat_numcommands++;
1093
1094 /* Prepare the client for the next command */
1095 if (c->flags & REDIS_CLOSE) {
1096 freeClient(c);
1097 return 0;
1098 }
1099 resetClient(c);
1100 return 1;
1101 }
1102
1103 static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc) {
1104 listNode *ln = slaves->head;
1105 robj *outv[REDIS_MAX_ARGS*4]; /* enough room for args, spaces, newlines */
1106 int outc = 0, j;
1107
1108 for (j = 0; j < argc; j++) {
1109 if (j != 0) outv[outc++] = shared.space;
1110 if ((cmd->flags & REDIS_CMD_BULK) && j == argc-1) {
1111 robj *lenobj;
1112
1113 lenobj = createObject(REDIS_STRING,
1114 sdscatprintf(sdsempty(),"%d\r\n",sdslen(argv[j]->ptr)));
1115 lenobj->refcount = 0;
1116 outv[outc++] = lenobj;
1117 }
1118 outv[outc++] = argv[j];
1119 }
1120 outv[outc++] = shared.crlf;
1121
1122 while(ln) {
1123 redisClient *slave = ln->value;
1124 if (slave->slaveseldb != dictid) {
1125 robj *selectcmd;
1126
1127 switch(dictid) {
1128 case 0: selectcmd = shared.select0; break;
1129 case 1: selectcmd = shared.select1; break;
1130 case 2: selectcmd = shared.select2; break;
1131 case 3: selectcmd = shared.select3; break;
1132 case 4: selectcmd = shared.select4; break;
1133 case 5: selectcmd = shared.select5; break;
1134 case 6: selectcmd = shared.select6; break;
1135 case 7: selectcmd = shared.select7; break;
1136 case 8: selectcmd = shared.select8; break;
1137 case 9: selectcmd = shared.select9; break;
1138 default:
1139 selectcmd = createObject(REDIS_STRING,
1140 sdscatprintf(sdsempty(),"select %d\r\n",dictid));
1141 selectcmd->refcount = 0;
1142 break;
1143 }
1144 addReply(slave,selectcmd);
1145 slave->slaveseldb = dictid;
1146 }
1147 for (j = 0; j < outc; j++) addReply(slave,outv[j]);
1148 ln = ln->next;
1149 }
1150 }
1151
1152 static void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
1153 redisClient *c = (redisClient*) privdata;
1154 char buf[REDIS_QUERYBUF_LEN];
1155 int nread;
1156 REDIS_NOTUSED(el);
1157 REDIS_NOTUSED(mask);
1158
1159 nread = read(fd, buf, REDIS_QUERYBUF_LEN);
1160 if (nread == -1) {
1161 if (errno == EAGAIN) {
1162 nread = 0;
1163 } else {
1164 redisLog(REDIS_DEBUG, "Reading from client: %s",strerror(errno));
1165 freeClient(c);
1166 return;
1167 }
1168 } else if (nread == 0) {
1169 redisLog(REDIS_DEBUG, "Client closed connection");
1170 freeClient(c);
1171 return;
1172 }
1173 if (nread) {
1174 c->querybuf = sdscatlen(c->querybuf, buf, nread);
1175 c->lastinteraction = time(NULL);
1176 } else {
1177 return;
1178 }
1179
1180 again:
1181 if (c->bulklen == -1) {
1182 /* Read the first line of the query */
1183 char *p = strchr(c->querybuf,'\n');
1184 size_t querylen;
1185 if (p) {
1186 sds query, *argv;
1187 int argc, j;
1188
1189 query = c->querybuf;
1190 c->querybuf = sdsempty();
1191 querylen = 1+(p-(query));
1192 if (sdslen(query) > querylen) {
1193 /* leave data after the first line of the query in the buffer */
1194 c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
1195 }
1196 *p = '\0'; /* remove "\n" */
1197 if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
1198 sdsupdatelen(query);
1199
1200 /* Now we can split the query in arguments */
1201 if (sdslen(query) == 0) {
1202 /* Ignore empty query */
1203 sdsfree(query);
1204 return;
1205 }
1206 argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
1207 sdsfree(query);
1208 if (argv == NULL) oom("sdssplitlen");
1209 for (j = 0; j < argc && j < REDIS_MAX_ARGS; j++) {
1210 if (sdslen(argv[j])) {
1211 c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
1212 c->argc++;
1213 } else {
1214 sdsfree(argv[j]);
1215 }
1216 }
1217 zfree(argv);
1218 /* Execute the command. If the client is still valid
1219 * after processCommand() return and there is something
1220 * on the query buffer try to process the next command. */
1221 if (processCommand(c) && sdslen(c->querybuf)) goto again;
1222 return;
1223 } else if (sdslen(c->querybuf) >= 1024) {
1224 redisLog(REDIS_DEBUG, "Client protocol error");
1225 freeClient(c);
1226 return;
1227 }
1228 } else {
1229 /* Bulk read handling. Note that if we are at this point
1230 the client already sent a command terminated with a newline,
1231 we are reading the bulk data that is actually the last
1232 argument of the command. */
1233 int qbl = sdslen(c->querybuf);
1234
1235 if (c->bulklen <= qbl) {
1236 /* Copy everything but the final CRLF as final argument */
1237 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
1238 c->argc++;
1239 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
1240 processCommand(c);
1241 return;
1242 }
1243 }
1244 }
1245
1246 static int selectDb(redisClient *c, int id) {
1247 if (id < 0 || id >= server.dbnum)
1248 return REDIS_ERR;
1249 c->dict = server.dict[id];
1250 c->dictid = id;
1251 return REDIS_OK;
1252 }
1253
1254 static redisClient *createClient(int fd) {
1255 redisClient *c = zmalloc(sizeof(*c));
1256
1257 anetNonBlock(NULL,fd);
1258 anetTcpNoDelay(NULL,fd);
1259 if (!c) return NULL;
1260 selectDb(c,0);
1261 c->fd = fd;
1262 c->querybuf = sdsempty();
1263 c->argc = 0;
1264 c->bulklen = -1;
1265 c->sentlen = 0;
1266 c->flags = 0;
1267 c->lastinteraction = time(NULL);
1268 if ((c->reply = listCreate()) == NULL) oom("listCreate");
1269 listSetFreeMethod(c->reply,decrRefCount);
1270 if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
1271 readQueryFromClient, c, NULL) == AE_ERR) {
1272 freeClient(c);
1273 return NULL;
1274 }
1275 if (!listAddNodeTail(server.clients,c)) oom("listAddNodeTail");
1276 return c;
1277 }
1278
1279 static void addReply(redisClient *c, robj *obj) {
1280 if (listLength(c->reply) == 0 &&
1281 aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
1282 sendReplyToClient, c, NULL) == AE_ERR) return;
1283 if (!listAddNodeTail(c->reply,obj)) oom("listAddNodeTail");
1284 incrRefCount(obj);
1285 }
1286
1287 static void addReplySds(redisClient *c, sds s) {
1288 robj *o = createObject(REDIS_STRING,s);
1289 addReply(c,o);
1290 decrRefCount(o);
1291 }
1292
1293 static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
1294 int cport, cfd;
1295 char cip[128];
1296 REDIS_NOTUSED(el);
1297 REDIS_NOTUSED(mask);
1298 REDIS_NOTUSED(privdata);
1299
1300 cfd = anetAccept(server.neterr, fd, cip, &cport);
1301 if (cfd == AE_ERR) {
1302 redisLog(REDIS_DEBUG,"Accepting client connection: %s", server.neterr);
1303 return;
1304 }
1305 redisLog(REDIS_DEBUG,"Accepted %s:%d", cip, cport);
1306 if (createClient(cfd) == NULL) {
1307 redisLog(REDIS_WARNING,"Error allocating resoures for the client");
1308 close(cfd); /* May be already closed, just ingore errors */
1309 return;
1310 }
1311 server.stat_numconnections++;
1312 }
1313
1314 /* ======================= Redis objects implementation ===================== */
1315
1316 static robj *createObject(int type, void *ptr) {
1317 robj *o;
1318
1319 if (listLength(server.objfreelist)) {
1320 listNode *head = listFirst(server.objfreelist);
1321 o = listNodeValue(head);
1322 listDelNode(server.objfreelist,head);
1323 } else {
1324 o = zmalloc(sizeof(*o));
1325 }
1326 if (!o) oom("createObject");
1327 o->type = type;
1328 o->ptr = ptr;
1329 o->refcount = 1;
1330 return o;
1331 }
1332
1333 static robj *createStringObject(char *ptr, size_t len) {
1334 return createObject(REDIS_STRING,sdsnewlen(ptr,len));
1335 }
1336
1337 static robj *createListObject(void) {
1338 list *l = listCreate();
1339
1340 if (!l) oom("listCreate");
1341 listSetFreeMethod(l,decrRefCount);
1342 return createObject(REDIS_LIST,l);
1343 }
1344
1345 static robj *createSetObject(void) {
1346 dict *d = dictCreate(&setDictType,NULL);
1347 if (!d) oom("dictCreate");
1348 return createObject(REDIS_SET,d);
1349 }
1350
1351 #if 0
1352 static robj *createHashObject(void) {
1353 dict *d = dictCreate(&hashDictType,NULL);
1354 if (!d) oom("dictCreate");
1355 return createObject(REDIS_SET,d);
1356 }
1357 #endif
1358
1359 static void freeStringObject(robj *o) {
1360 sdsfree(o->ptr);
1361 }
1362
1363 static void freeListObject(robj *o) {
1364 listRelease((list*) o->ptr);
1365 }
1366
1367 static void freeSetObject(robj *o) {
1368 dictRelease((dict*) o->ptr);
1369 }
1370
1371 static void freeHashObject(robj *o) {
1372 dictRelease((dict*) o->ptr);
1373 }
1374
1375 static void incrRefCount(robj *o) {
1376 o->refcount++;
1377 }
1378
1379 static void decrRefCount(void *obj) {
1380 robj *o = obj;
1381 if (--(o->refcount) == 0) {
1382 switch(o->type) {
1383 case REDIS_STRING: freeStringObject(o); break;
1384 case REDIS_LIST: freeListObject(o); break;
1385 case REDIS_SET: freeSetObject(o); break;
1386 case REDIS_HASH: freeHashObject(o); break;
1387 default: assert(0 != 0); break;
1388 }
1389 if (listLength(server.objfreelist) > REDIS_OBJFREELIST_MAX ||
1390 !listAddNodeHead(server.objfreelist,o))
1391 zfree(o);
1392 }
1393 }
1394
1395 /*============================ DB saving/loading ============================ */
1396
1397 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
1398 static int saveDb(char *filename) {
1399 dictIterator *di = NULL;
1400 dictEntry *de;
1401 uint32_t len;
1402 uint8_t type;
1403 FILE *fp;
1404 char tmpfile[256];
1405 int j;
1406
1407 snprintf(tmpfile,256,"temp-%d.%ld.rdb",(int)time(NULL),(long int)random());
1408 fp = fopen(tmpfile,"w");
1409 if (!fp) {
1410 redisLog(REDIS_WARNING, "Failed saving the DB: %s", strerror(errno));
1411 return REDIS_ERR;
1412 }
1413 if (fwrite("REDIS0000",9,1,fp) == 0) goto werr;
1414 for (j = 0; j < server.dbnum; j++) {
1415 dict *d = server.dict[j];
1416 if (dictGetHashTableUsed(d) == 0) continue;
1417 di = dictGetIterator(d);
1418 if (!di) {
1419 fclose(fp);
1420 return REDIS_ERR;
1421 }
1422
1423 /* Write the SELECT DB opcode */
1424 type = REDIS_SELECTDB;
1425 len = htonl(j);
1426 if (fwrite(&type,1,1,fp) == 0) goto werr;
1427 if (fwrite(&len,4,1,fp) == 0) goto werr;
1428
1429 /* Iterate this DB writing every entry */
1430 while((de = dictNext(di)) != NULL) {
1431 robj *key = dictGetEntryKey(de);
1432 robj *o = dictGetEntryVal(de);
1433
1434 type = o->type;
1435 len = htonl(sdslen(key->ptr));
1436 if (fwrite(&type,1,1,fp) == 0) goto werr;
1437 if (fwrite(&len,4,1,fp) == 0) goto werr;
1438 if (fwrite(key->ptr,sdslen(key->ptr),1,fp) == 0) goto werr;
1439 if (type == REDIS_STRING) {
1440 /* Save a string value */
1441 sds sval = o->ptr;
1442 len = htonl(sdslen(sval));
1443 if (fwrite(&len,4,1,fp) == 0) goto werr;
1444 if (sdslen(sval) &&
1445 fwrite(sval,sdslen(sval),1,fp) == 0) goto werr;
1446 } else if (type == REDIS_LIST) {
1447 /* Save a list value */
1448 list *list = o->ptr;
1449 listNode *ln = list->head;
1450
1451 len = htonl(listLength(list));
1452 if (fwrite(&len,4,1,fp) == 0) goto werr;
1453 while(ln) {
1454 robj *eleobj = listNodeValue(ln);
1455 len = htonl(sdslen(eleobj->ptr));
1456 if (fwrite(&len,4,1,fp) == 0) goto werr;
1457 if (sdslen(eleobj->ptr) && fwrite(eleobj->ptr,sdslen(eleobj->ptr),1,fp) == 0)
1458 goto werr;
1459 ln = ln->next;
1460 }
1461 } else if (type == REDIS_SET) {
1462 /* Save a set value */
1463 dict *set = o->ptr;
1464 dictIterator *di = dictGetIterator(set);
1465 dictEntry *de;
1466
1467 if (!set) oom("dictGetIteraotr");
1468 len = htonl(dictGetHashTableUsed(set));
1469 if (fwrite(&len,4,1,fp) == 0) goto werr;
1470 while((de = dictNext(di)) != NULL) {
1471 robj *eleobj;
1472
1473 eleobj = dictGetEntryKey(de);
1474 len = htonl(sdslen(eleobj->ptr));
1475 if (fwrite(&len,4,1,fp) == 0) goto werr;
1476 if (sdslen(eleobj->ptr) && fwrite(eleobj->ptr,sdslen(eleobj->ptr),1,fp) == 0)
1477 goto werr;
1478 }
1479 dictReleaseIterator(di);
1480 } else {
1481 assert(0 != 0);
1482 }
1483 }
1484 dictReleaseIterator(di);
1485 }
1486 /* EOF opcode */
1487 type = REDIS_EOF;
1488 if (fwrite(&type,1,1,fp) == 0) goto werr;
1489 fflush(fp);
1490 fsync(fileno(fp));
1491 fclose(fp);
1492
1493 /* Use RENAME to make sure the DB file is changed atomically only
1494 * if the generate DB file is ok. */
1495 if (rename(tmpfile,filename) == -1) {
1496 redisLog(REDIS_WARNING,"Error moving temp DB file on the final destionation: %s", strerror(errno));
1497 unlink(tmpfile);
1498 return REDIS_ERR;
1499 }
1500 redisLog(REDIS_NOTICE,"DB saved on disk");
1501 server.dirty = 0;
1502 server.lastsave = time(NULL);
1503 return REDIS_OK;
1504
1505 werr:
1506 fclose(fp);
1507 unlink(tmpfile);
1508 redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
1509 if (di) dictReleaseIterator(di);
1510 return REDIS_ERR;
1511 }
1512
1513 static int saveDbBackground(char *filename) {
1514 pid_t childpid;
1515
1516 if (server.bgsaveinprogress) return REDIS_ERR;
1517 if ((childpid = fork()) == 0) {
1518 /* Child */
1519 close(server.fd);
1520 if (saveDb(filename) == REDIS_OK) {
1521 exit(0);
1522 } else {
1523 exit(1);
1524 }
1525 } else {
1526 /* Parent */
1527 redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
1528 server.bgsaveinprogress = 1;
1529 return REDIS_OK;
1530 }
1531 return REDIS_OK; /* unreached */
1532 }
1533
1534 static int loadType(FILE *fp) {
1535 uint8_t type;
1536 if (fread(&type,1,1,fp) == 0) return -1;
1537 return type;
1538 }
1539
1540 static int loadDb(char *filename) {
1541 FILE *fp;
1542 char buf[REDIS_LOADBUF_LEN]; /* Try to use this buffer instead of */
1543 char vbuf[REDIS_LOADBUF_LEN]; /* malloc() when the element is small */
1544 char *key = NULL, *val = NULL;
1545 uint32_t klen,vlen,dbid;
1546 int type;
1547 int retval;
1548 dict *d = server.dict[0];
1549
1550 fp = fopen(filename,"r");
1551 if (!fp) return REDIS_ERR;
1552 if (fread(buf,9,1,fp) == 0) goto eoferr;
1553 if (memcmp(buf,"REDIS0000",9) != 0) {
1554 fclose(fp);
1555 redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
1556 return REDIS_ERR;
1557 }
1558 while(1) {
1559 robj *o;
1560
1561 /* Read type. */
1562 if ((type = loadType(fp)) == -1) goto eoferr;
1563 if (type == REDIS_EOF) break;
1564 /* Handle SELECT DB opcode as a special case */
1565 if (type == REDIS_SELECTDB) {
1566 if (fread(&dbid,4,1,fp) == 0) goto eoferr;
1567 dbid = ntohl(dbid);
1568 if (dbid >= (unsigned)server.dbnum) {
1569 redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server compiled to handle more than %d databases. Exiting\n", server.dbnum);
1570 exit(1);
1571 }
1572 d = server.dict[dbid];
1573 continue;
1574 }
1575 /* Read key */
1576 if (fread(&klen,4,1,fp) == 0) goto eoferr;
1577 klen = ntohl(klen);
1578 if (klen <= REDIS_LOADBUF_LEN) {
1579 key = buf;
1580 } else {
1581 key = zmalloc(klen);
1582 if (!key) oom("Loading DB from file");
1583 }
1584 if (fread(key,klen,1,fp) == 0) goto eoferr;
1585
1586 if (type == REDIS_STRING) {
1587 /* Read string value */
1588 if (fread(&vlen,4,1,fp) == 0) goto eoferr;
1589 vlen = ntohl(vlen);
1590 if (vlen <= REDIS_LOADBUF_LEN) {
1591 val = vbuf;
1592 } else {
1593 val = zmalloc(vlen);
1594 if (!val) oom("Loading DB from file");
1595 }
1596 if (vlen && fread(val,vlen,1,fp) == 0) goto eoferr;
1597 o = createObject(REDIS_STRING,sdsnewlen(val,vlen));
1598 } else if (type == REDIS_LIST || type == REDIS_SET) {
1599 /* Read list/set value */
1600 uint32_t listlen;
1601 if (fread(&listlen,4,1,fp) == 0) goto eoferr;
1602 listlen = ntohl(listlen);
1603 o = (type == REDIS_LIST) ? createListObject() : createSetObject();
1604 /* Load every single element of the list/set */
1605 while(listlen--) {
1606 robj *ele;
1607
1608 if (fread(&vlen,4,1,fp) == 0) goto eoferr;
1609 vlen = ntohl(vlen);
1610 if (vlen <= REDIS_LOADBUF_LEN) {
1611 val = vbuf;
1612 } else {
1613 val = zmalloc(vlen);
1614 if (!val) oom("Loading DB from file");
1615 }
1616 if (vlen && fread(val,vlen,1,fp) == 0) goto eoferr;
1617 ele = createObject(REDIS_STRING,sdsnewlen(val,vlen));
1618 if (type == REDIS_LIST) {
1619 if (!listAddNodeTail((list*)o->ptr,ele))
1620 oom("listAddNodeTail");
1621 } else {
1622 if (dictAdd((dict*)o->ptr,ele,NULL) == DICT_ERR)
1623 oom("dictAdd");
1624 }
1625 /* free the temp buffer if needed */
1626 if (val != vbuf) zfree(val);
1627 val = NULL;
1628 }
1629 } else {
1630 assert(0 != 0);
1631 }
1632 /* Add the new object in the hash table */
1633 retval = dictAdd(d,createStringObject(key,klen),o);
1634 if (retval == DICT_ERR) {
1635 redisLog(REDIS_WARNING,"Loading DB, duplicated key found! Unrecoverable error, exiting now.");
1636 exit(1);
1637 }
1638 /* Iteration cleanup */
1639 if (key != buf) zfree(key);
1640 if (val != vbuf) zfree(val);
1641 key = val = NULL;
1642 }
1643 fclose(fp);
1644 return REDIS_OK;
1645
1646 eoferr: /* unexpected end of file is handled here with a fatal exit */
1647 if (key != buf) zfree(key);
1648 if (val != vbuf) zfree(val);
1649 redisLog(REDIS_WARNING,"Short read loading DB. Unrecoverable error, exiting now.");
1650 exit(1);
1651 return REDIS_ERR; /* Just to avoid warning */
1652 }
1653
1654 /*================================== Commands =============================== */
1655
1656 static void pingCommand(redisClient *c) {
1657 addReply(c,shared.pong);
1658 }
1659
1660 static void echoCommand(redisClient *c) {
1661 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",
1662 (int)sdslen(c->argv[1]->ptr)));
1663 addReply(c,c->argv[1]);
1664 addReply(c,shared.crlf);
1665 }
1666
1667 /*=================================== Strings =============================== */
1668
1669 static void setGenericCommand(redisClient *c, int nx) {
1670 int retval;
1671
1672 retval = dictAdd(c->dict,c->argv[1],c->argv[2]);
1673 if (retval == DICT_ERR) {
1674 if (!nx) {
1675 dictReplace(c->dict,c->argv[1],c->argv[2]);
1676 incrRefCount(c->argv[2]);
1677 } else {
1678 addReply(c,shared.czero);
1679 return;
1680 }
1681 } else {
1682 incrRefCount(c->argv[1]);
1683 incrRefCount(c->argv[2]);
1684 }
1685 server.dirty++;
1686 addReply(c, nx ? shared.cone : shared.ok);
1687 }
1688
1689 static void setCommand(redisClient *c) {
1690 return setGenericCommand(c,0);
1691 }
1692
1693 static void setnxCommand(redisClient *c) {
1694 return setGenericCommand(c,1);
1695 }
1696
1697 static void getCommand(redisClient *c) {
1698 dictEntry *de;
1699
1700 de = dictFind(c->dict,c->argv[1]);
1701 if (de == NULL) {
1702 addReply(c,shared.nullbulk);
1703 } else {
1704 robj *o = dictGetEntryVal(de);
1705
1706 if (o->type != REDIS_STRING) {
1707 addReply(c,shared.wrongtypeerr);
1708 } else {
1709 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(o->ptr)));
1710 addReply(c,o);
1711 addReply(c,shared.crlf);
1712 }
1713 }
1714 }
1715
1716 static void mgetCommand(redisClient *c) {
1717 dictEntry *de;
1718 int j;
1719
1720 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-1));
1721 for (j = 1; j < c->argc; j++) {
1722 de = dictFind(c->dict,c->argv[j]);
1723 if (de == NULL) {
1724 addReply(c,shared.nullbulk);
1725 } else {
1726 robj *o = dictGetEntryVal(de);
1727
1728 if (o->type != REDIS_STRING) {
1729 addReply(c,shared.nullbulk);
1730 } else {
1731 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(o->ptr)));
1732 addReply(c,o);
1733 addReply(c,shared.crlf);
1734 }
1735 }
1736 }
1737 }
1738
1739 static void incrDecrCommand(redisClient *c, int incr) {
1740 dictEntry *de;
1741 long long value;
1742 int retval;
1743 robj *o;
1744
1745 de = dictFind(c->dict,c->argv[1]);
1746 if (de == NULL) {
1747 value = 0;
1748 } else {
1749 robj *o = dictGetEntryVal(de);
1750
1751 if (o->type != REDIS_STRING) {
1752 value = 0;
1753 } else {
1754 char *eptr;
1755
1756 value = strtoll(o->ptr, &eptr, 10);
1757 }
1758 }
1759
1760 value += incr;
1761 o = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
1762 retval = dictAdd(c->dict,c->argv[1],o);
1763 if (retval == DICT_ERR) {
1764 dictReplace(c->dict,c->argv[1],o);
1765 } else {
1766 incrRefCount(c->argv[1]);
1767 }
1768 server.dirty++;
1769 addReply(c,shared.colon);
1770 addReply(c,o);
1771 addReply(c,shared.crlf);
1772 }
1773
1774 static void incrCommand(redisClient *c) {
1775 return incrDecrCommand(c,1);
1776 }
1777
1778 static void decrCommand(redisClient *c) {
1779 return incrDecrCommand(c,-1);
1780 }
1781
1782 static void incrbyCommand(redisClient *c) {
1783 int incr = atoi(c->argv[2]->ptr);
1784 return incrDecrCommand(c,incr);
1785 }
1786
1787 static void decrbyCommand(redisClient *c) {
1788 int incr = atoi(c->argv[2]->ptr);
1789 return incrDecrCommand(c,-incr);
1790 }
1791
1792 /* ========================= Type agnostic commands ========================= */
1793
1794 static void delCommand(redisClient *c) {
1795 if (dictDelete(c->dict,c->argv[1]) == DICT_OK) {
1796 server.dirty++;
1797 addReply(c,shared.cone);
1798 } else {
1799 addReply(c,shared.czero);
1800 }
1801 }
1802
1803 static void existsCommand(redisClient *c) {
1804 dictEntry *de;
1805
1806 de = dictFind(c->dict,c->argv[1]);
1807 if (de == NULL)
1808 addReply(c,shared.czero);
1809 else
1810 addReply(c,shared.cone);
1811 }
1812
1813 static void selectCommand(redisClient *c) {
1814 int id = atoi(c->argv[1]->ptr);
1815
1816 if (selectDb(c,id) == REDIS_ERR) {
1817 addReplySds(c,"-ERR invalid DB index\r\n");
1818 } else {
1819 addReply(c,shared.ok);
1820 }
1821 }
1822
1823 static void randomkeyCommand(redisClient *c) {
1824 dictEntry *de;
1825
1826 de = dictGetRandomKey(c->dict);
1827 if (de == NULL) {
1828 addReply(c,shared.crlf);
1829 } else {
1830 addReply(c,shared.plus);
1831 addReply(c,dictGetEntryKey(de));
1832 addReply(c,shared.crlf);
1833 }
1834 }
1835
1836 static void keysCommand(redisClient *c) {
1837 dictIterator *di;
1838 dictEntry *de;
1839 sds pattern = c->argv[1]->ptr;
1840 int plen = sdslen(pattern);
1841 int numkeys = 0, keyslen = 0;
1842 robj *lenobj = createObject(REDIS_STRING,NULL);
1843
1844 di = dictGetIterator(c->dict);
1845 if (!di) oom("dictGetIterator");
1846 addReply(c,lenobj);
1847 decrRefCount(lenobj);
1848 while((de = dictNext(di)) != NULL) {
1849 robj *keyobj = dictGetEntryKey(de);
1850 sds key = keyobj->ptr;
1851 if ((pattern[0] == '*' && pattern[1] == '\0') ||
1852 stringmatchlen(pattern,plen,key,sdslen(key),0)) {
1853 if (numkeys != 0)
1854 addReply(c,shared.space);
1855 addReply(c,keyobj);
1856 numkeys++;
1857 keyslen += sdslen(key);
1858 }
1859 }
1860 dictReleaseIterator(di);
1861 lenobj->ptr = sdscatprintf(sdsempty(),"$%lu\r\n",keyslen+(numkeys ? (numkeys-1) : 0));
1862 addReply(c,shared.crlf);
1863 }
1864
1865 static void dbsizeCommand(redisClient *c) {
1866 addReplySds(c,
1867 sdscatprintf(sdsempty(),":%lu\r\n",dictGetHashTableUsed(c->dict)));
1868 }
1869
1870 static void lastsaveCommand(redisClient *c) {
1871 addReplySds(c,
1872 sdscatprintf(sdsempty(),":%lu\r\n",server.lastsave));
1873 }
1874
1875 static void typeCommand(redisClient *c) {
1876 dictEntry *de;
1877 char *type;
1878
1879 de = dictFind(c->dict,c->argv[1]);
1880 if (de == NULL) {
1881 type = "+none";
1882 } else {
1883 robj *o = dictGetEntryVal(de);
1884
1885 switch(o->type) {
1886 case REDIS_STRING: type = "+string"; break;
1887 case REDIS_LIST: type = "+list"; break;
1888 case REDIS_SET: type = "+set"; break;
1889 default: type = "unknown"; break;
1890 }
1891 }
1892 addReplySds(c,sdsnew(type));
1893 addReply(c,shared.crlf);
1894 }
1895
1896 static void saveCommand(redisClient *c) {
1897 if (saveDb(server.dbfilename) == REDIS_OK) {
1898 addReply(c,shared.ok);
1899 } else {
1900 addReply(c,shared.err);
1901 }
1902 }
1903
1904 static void bgsaveCommand(redisClient *c) {
1905 if (server.bgsaveinprogress) {
1906 addReplySds(c,sdsnew("-ERR background save already in progress\r\n"));
1907 return;
1908 }
1909 if (saveDbBackground(server.dbfilename) == REDIS_OK) {
1910 addReply(c,shared.ok);
1911 } else {
1912 addReply(c,shared.err);
1913 }
1914 }
1915
1916 static void shutdownCommand(redisClient *c) {
1917 redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
1918 if (saveDb(server.dbfilename) == REDIS_OK) {
1919 if (server.daemonize) {
1920 unlink(server.pidfile);
1921 }
1922 redisLog(REDIS_WARNING,"Server exit now, bye bye...");
1923 exit(1);
1924 } else {
1925 redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
1926 addReplySds(c,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
1927 }
1928 }
1929
1930 static void renameGenericCommand(redisClient *c, int nx) {
1931 dictEntry *de;
1932 robj *o;
1933
1934 /* To use the same key as src and dst is probably an error */
1935 if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) {
1936 addReply(c,shared.sameobjecterr);
1937 return;
1938 }
1939
1940 de = dictFind(c->dict,c->argv[1]);
1941 if (de == NULL) {
1942 addReply(c,shared.nokeyerr);
1943 return;
1944 }
1945 o = dictGetEntryVal(de);
1946 incrRefCount(o);
1947 if (dictAdd(c->dict,c->argv[2],o) == DICT_ERR) {
1948 if (nx) {
1949 decrRefCount(o);
1950 addReply(c,shared.czero);
1951 return;
1952 }
1953 dictReplace(c->dict,c->argv[2],o);
1954 } else {
1955 incrRefCount(c->argv[2]);
1956 }
1957 dictDelete(c->dict,c->argv[1]);
1958 server.dirty++;
1959 addReply(c,nx ? shared.cone : shared.ok);
1960 }
1961
1962 static void renameCommand(redisClient *c) {
1963 renameGenericCommand(c,0);
1964 }
1965
1966 static void renamenxCommand(redisClient *c) {
1967 renameGenericCommand(c,1);
1968 }
1969
1970 static void moveCommand(redisClient *c) {
1971 dictEntry *de;
1972 robj *o, *key;
1973 dict *src, *dst;
1974 int srcid;
1975
1976 /* Obtain source and target DB pointers */
1977 src = c->dict;
1978 srcid = c->dictid;
1979 if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) {
1980 addReply(c,shared.outofrangeerr);
1981 return;
1982 }
1983 dst = c->dict;
1984 c->dict = src;
1985 c->dictid = srcid;
1986
1987 /* If the user is moving using as target the same
1988 * DB as the source DB it is probably an error. */
1989 if (src == dst) {
1990 addReply(c,shared.sameobjecterr);
1991 return;
1992 }
1993
1994 /* Check if the element exists and get a reference */
1995 de = dictFind(c->dict,c->argv[1]);
1996 if (!de) {
1997 addReply(c,shared.czero);
1998 return;
1999 }
2000
2001 /* Try to add the element to the target DB */
2002 key = dictGetEntryKey(de);
2003 o = dictGetEntryVal(de);
2004 if (dictAdd(dst,key,o) == DICT_ERR) {
2005 addReply(c,shared.czero);
2006 return;
2007 }
2008 incrRefCount(key);
2009 incrRefCount(o);
2010
2011 /* OK! key moved, free the entry in the source DB */
2012 dictDelete(src,c->argv[1]);
2013 server.dirty++;
2014 addReply(c,shared.cone);
2015 }
2016
2017 /* =================================== Lists ================================ */
2018 static void pushGenericCommand(redisClient *c, int where) {
2019 robj *lobj;
2020 dictEntry *de;
2021 list *list;
2022
2023 de = dictFind(c->dict,c->argv[1]);
2024 if (de == NULL) {
2025 lobj = createListObject();
2026 list = lobj->ptr;
2027 if (where == REDIS_HEAD) {
2028 if (!listAddNodeHead(list,c->argv[2])) oom("listAddNodeHead");
2029 } else {
2030 if (!listAddNodeTail(list,c->argv[2])) oom("listAddNodeTail");
2031 }
2032 dictAdd(c->dict,c->argv[1],lobj);
2033 incrRefCount(c->argv[1]);
2034 incrRefCount(c->argv[2]);
2035 } else {
2036 lobj = dictGetEntryVal(de);
2037 if (lobj->type != REDIS_LIST) {
2038 addReply(c,shared.wrongtypeerr);
2039 return;
2040 }
2041 list = lobj->ptr;
2042 if (where == REDIS_HEAD) {
2043 if (!listAddNodeHead(list,c->argv[2])) oom("listAddNodeHead");
2044 } else {
2045 if (!listAddNodeTail(list,c->argv[2])) oom("listAddNodeTail");
2046 }
2047 incrRefCount(c->argv[2]);
2048 }
2049 server.dirty++;
2050 addReply(c,shared.ok);
2051 }
2052
2053 static void lpushCommand(redisClient *c) {
2054 pushGenericCommand(c,REDIS_HEAD);
2055 }
2056
2057 static void rpushCommand(redisClient *c) {
2058 pushGenericCommand(c,REDIS_TAIL);
2059 }
2060
2061 static void llenCommand(redisClient *c) {
2062 dictEntry *de;
2063 list *l;
2064
2065 de = dictFind(c->dict,c->argv[1]);
2066 if (de == NULL) {
2067 addReply(c,shared.czero);
2068 return;
2069 } else {
2070 robj *o = dictGetEntryVal(de);
2071 if (o->type != REDIS_LIST) {
2072 addReply(c,shared.wrongtypeerr);
2073 } else {
2074 l = o->ptr;
2075 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",listLength(l)));
2076 }
2077 }
2078 }
2079
2080 static void lindexCommand(redisClient *c) {
2081 dictEntry *de;
2082 int index = atoi(c->argv[2]->ptr);
2083
2084 de = dictFind(c->dict,c->argv[1]);
2085 if (de == NULL) {
2086 addReply(c,shared.nullbulk);
2087 } else {
2088 robj *o = dictGetEntryVal(de);
2089
2090 if (o->type != REDIS_LIST) {
2091 addReply(c,shared.wrongtypeerr);
2092 } else {
2093 list *list = o->ptr;
2094 listNode *ln;
2095
2096 ln = listIndex(list, index);
2097 if (ln == NULL) {
2098 addReply(c,shared.nullbulk);
2099 } else {
2100 robj *ele = listNodeValue(ln);
2101 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele->ptr)));
2102 addReply(c,ele);
2103 addReply(c,shared.crlf);
2104 }
2105 }
2106 }
2107 }
2108
2109 static void lsetCommand(redisClient *c) {
2110 dictEntry *de;
2111 int index = atoi(c->argv[2]->ptr);
2112
2113 de = dictFind(c->dict,c->argv[1]);
2114 if (de == NULL) {
2115 addReply(c,shared.nokeyerr);
2116 } else {
2117 robj *o = dictGetEntryVal(de);
2118
2119 if (o->type != REDIS_LIST) {
2120 addReply(c,shared.wrongtypeerr);
2121 } else {
2122 list *list = o->ptr;
2123 listNode *ln;
2124
2125 ln = listIndex(list, index);
2126 if (ln == NULL) {
2127 addReply(c,shared.outofrangeerr);
2128 } else {
2129 robj *ele = listNodeValue(ln);
2130
2131 decrRefCount(ele);
2132 listNodeValue(ln) = c->argv[3];
2133 incrRefCount(c->argv[3]);
2134 addReply(c,shared.ok);
2135 server.dirty++;
2136 }
2137 }
2138 }
2139 }
2140
2141 static void popGenericCommand(redisClient *c, int where) {
2142 dictEntry *de;
2143
2144 de = dictFind(c->dict,c->argv[1]);
2145 if (de == NULL) {
2146 addReply(c,shared.nullbulk);
2147 } else {
2148 robj *o = dictGetEntryVal(de);
2149
2150 if (o->type != REDIS_LIST) {
2151 addReply(c,shared.wrongtypeerr);
2152 } else {
2153 list *list = o->ptr;
2154 listNode *ln;
2155
2156 if (where == REDIS_HEAD)
2157 ln = listFirst(list);
2158 else
2159 ln = listLast(list);
2160
2161 if (ln == NULL) {
2162 addReply(c,shared.nullbulk);
2163 } else {
2164 robj *ele = listNodeValue(ln);
2165 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele->ptr)));
2166 addReply(c,ele);
2167 addReply(c,shared.crlf);
2168 listDelNode(list,ln);
2169 server.dirty++;
2170 }
2171 }
2172 }
2173 }
2174
2175 static void lpopCommand(redisClient *c) {
2176 popGenericCommand(c,REDIS_HEAD);
2177 }
2178
2179 static void rpopCommand(redisClient *c) {
2180 popGenericCommand(c,REDIS_TAIL);
2181 }
2182
2183 static void lrangeCommand(redisClient *c) {
2184 dictEntry *de;
2185 int start = atoi(c->argv[2]->ptr);
2186 int end = atoi(c->argv[3]->ptr);
2187
2188 de = dictFind(c->dict,c->argv[1]);
2189 if (de == NULL) {
2190 addReply(c,shared.nullmultibulk);
2191 } else {
2192 robj *o = dictGetEntryVal(de);
2193
2194 if (o->type != REDIS_LIST) {
2195 addReply(c,shared.wrongtypeerr);
2196 } else {
2197 list *list = o->ptr;
2198 listNode *ln;
2199 int llen = listLength(list);
2200 int rangelen, j;
2201 robj *ele;
2202
2203 /* convert negative indexes */
2204 if (start < 0) start = llen+start;
2205 if (end < 0) end = llen+end;
2206 if (start < 0) start = 0;
2207 if (end < 0) end = 0;
2208
2209 /* indexes sanity checks */
2210 if (start > end || start >= llen) {
2211 /* Out of range start or start > end result in empty list */
2212 addReply(c,shared.emptymultibulk);
2213 return;
2214 }
2215 if (end >= llen) end = llen-1;
2216 rangelen = (end-start)+1;
2217
2218 /* Return the result in form of a multi-bulk reply */
2219 ln = listIndex(list, start);
2220 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen));
2221 for (j = 0; j < rangelen; j++) {
2222 ele = listNodeValue(ln);
2223 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele->ptr)));
2224 addReply(c,ele);
2225 addReply(c,shared.crlf);
2226 ln = ln->next;
2227 }
2228 }
2229 }
2230 }
2231
2232 static void ltrimCommand(redisClient *c) {
2233 dictEntry *de;
2234 int start = atoi(c->argv[2]->ptr);
2235 int end = atoi(c->argv[3]->ptr);
2236
2237 de = dictFind(c->dict,c->argv[1]);
2238 if (de == NULL) {
2239 addReply(c,shared.nokeyerr);
2240 } else {
2241 robj *o = dictGetEntryVal(de);
2242
2243 if (o->type != REDIS_LIST) {
2244 addReply(c,shared.wrongtypeerr);
2245 } else {
2246 list *list = o->ptr;
2247 listNode *ln;
2248 int llen = listLength(list);
2249 int j, ltrim, rtrim;
2250
2251 /* convert negative indexes */
2252 if (start < 0) start = llen+start;
2253 if (end < 0) end = llen+end;
2254 if (start < 0) start = 0;
2255 if (end < 0) end = 0;
2256
2257 /* indexes sanity checks */
2258 if (start > end || start >= llen) {
2259 /* Out of range start or start > end result in empty list */
2260 ltrim = llen;
2261 rtrim = 0;
2262 } else {
2263 if (end >= llen) end = llen-1;
2264 ltrim = start;
2265 rtrim = llen-end-1;
2266 }
2267
2268 /* Remove list elements to perform the trim */
2269 for (j = 0; j < ltrim; j++) {
2270 ln = listFirst(list);
2271 listDelNode(list,ln);
2272 }
2273 for (j = 0; j < rtrim; j++) {
2274 ln = listLast(list);
2275 listDelNode(list,ln);
2276 }
2277 addReply(c,shared.ok);
2278 server.dirty++;
2279 }
2280 }
2281 }
2282
2283 static void lremCommand(redisClient *c) {
2284 dictEntry *de;
2285
2286 de = dictFind(c->dict,c->argv[1]);
2287 if (de == NULL) {
2288 addReply(c,shared.nokeyerr);
2289 } else {
2290 robj *o = dictGetEntryVal(de);
2291
2292 if (o->type != REDIS_LIST) {
2293 addReply(c,shared.wrongtypeerr);
2294 } else {
2295 list *list = o->ptr;
2296 listNode *ln, *next;
2297 int toremove = atoi(c->argv[2]->ptr);
2298 int removed = 0;
2299 int fromtail = 0;
2300
2301 if (toremove < 0) {
2302 toremove = -toremove;
2303 fromtail = 1;
2304 }
2305 ln = fromtail ? list->tail : list->head;
2306 while (ln) {
2307 next = fromtail ? ln->prev : ln->next;
2308 robj *ele = listNodeValue(ln);
2309 if (sdscmp(ele->ptr,c->argv[3]->ptr) == 0) {
2310 listDelNode(list,ln);
2311 server.dirty++;
2312 removed++;
2313 if (toremove && removed == toremove) break;
2314 }
2315 ln = next;
2316 }
2317 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",removed));
2318 }
2319 }
2320 }
2321
2322 /* ==================================== Sets ================================ */
2323
2324 static void saddCommand(redisClient *c) {
2325 dictEntry *de;
2326 robj *set;
2327
2328 de = dictFind(c->dict,c->argv[1]);
2329 if (de == NULL) {
2330 set = createSetObject();
2331 dictAdd(c->dict,c->argv[1],set);
2332 incrRefCount(c->argv[1]);
2333 } else {
2334 set = dictGetEntryVal(de);
2335 if (set->type != REDIS_SET) {
2336 addReply(c,shared.wrongtypeerr);
2337 return;
2338 }
2339 }
2340 if (dictAdd(set->ptr,c->argv[2],NULL) == DICT_OK) {
2341 incrRefCount(c->argv[2]);
2342 server.dirty++;
2343 addReply(c,shared.cone);
2344 } else {
2345 addReply(c,shared.czero);
2346 }
2347 }
2348
2349 static void sremCommand(redisClient *c) {
2350 dictEntry *de;
2351
2352 de = dictFind(c->dict,c->argv[1]);
2353 if (de == NULL) {
2354 addReply(c,shared.czero);
2355 } else {
2356 robj *set;
2357
2358 set = dictGetEntryVal(de);
2359 if (set->type != REDIS_SET) {
2360 addReply(c,shared.wrongtypeerr);
2361 return;
2362 }
2363 if (dictDelete(set->ptr,c->argv[2]) == DICT_OK) {
2364 server.dirty++;
2365 addReply(c,shared.cone);
2366 } else {
2367 addReply(c,shared.czero);
2368 }
2369 }
2370 }
2371
2372 static void sismemberCommand(redisClient *c) {
2373 dictEntry *de;
2374
2375 de = dictFind(c->dict,c->argv[1]);
2376 if (de == NULL) {
2377 addReply(c,shared.czero);
2378 } else {
2379 robj *set;
2380
2381 set = dictGetEntryVal(de);
2382 if (set->type != REDIS_SET) {
2383 addReply(c,shared.wrongtypeerr);
2384 return;
2385 }
2386 if (dictFind(set->ptr,c->argv[2]))
2387 addReply(c,shared.cone);
2388 else
2389 addReply(c,shared.czero);
2390 }
2391 }
2392
2393 static void scardCommand(redisClient *c) {
2394 dictEntry *de;
2395 dict *s;
2396
2397 de = dictFind(c->dict,c->argv[1]);
2398 if (de == NULL) {
2399 addReply(c,shared.czero);
2400 return;
2401 } else {
2402 robj *o = dictGetEntryVal(de);
2403 if (o->type != REDIS_SET) {
2404 addReply(c,shared.wrongtypeerr);
2405 } else {
2406 s = o->ptr;
2407 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",
2408 dictGetHashTableUsed(s)));
2409 }
2410 }
2411 }
2412
2413 static int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
2414 dict **d1 = (void*) s1, **d2 = (void*) s2;
2415
2416 return dictGetHashTableUsed(*d1)-dictGetHashTableUsed(*d2);
2417 }
2418
2419 static void sinterGenericCommand(redisClient *c, robj **setskeys, int setsnum, robj *dstkey) {
2420 dict **dv = zmalloc(sizeof(dict*)*setsnum);
2421 dictIterator *di;
2422 dictEntry *de;
2423 robj *lenobj = NULL, *dstset = NULL;
2424 int j, cardinality = 0;
2425
2426 if (!dv) oom("sinterCommand");
2427 for (j = 0; j < setsnum; j++) {
2428 robj *setobj;
2429 dictEntry *de;
2430
2431 de = dictFind(c->dict,setskeys[j]);
2432 if (!de) {
2433 zfree(dv);
2434 addReply(c,shared.nokeyerr);
2435 return;
2436 }
2437 setobj = dictGetEntryVal(de);
2438 if (setobj->type != REDIS_SET) {
2439 zfree(dv);
2440 addReply(c,shared.wrongtypeerr);
2441 return;
2442 }
2443 dv[j] = setobj->ptr;
2444 }
2445 /* Sort sets from the smallest to largest, this will improve our
2446 * algorithm's performace */
2447 qsort(dv,setsnum,sizeof(dict*),qsortCompareSetsByCardinality);
2448
2449 /* The first thing we should output is the total number of elements...
2450 * since this is a multi-bulk write, but at this stage we don't know
2451 * the intersection set size, so we use a trick, append an empty object
2452 * to the output list and save the pointer to later modify it with the
2453 * right length */
2454 if (!dstkey) {
2455 lenobj = createObject(REDIS_STRING,NULL);
2456 addReply(c,lenobj);
2457 decrRefCount(lenobj);
2458 } else {
2459 /* If we have a target key where to store the resulting set
2460 * create this key with an empty set inside */
2461 dstset = createSetObject();
2462 dictDelete(c->dict,dstkey);
2463 dictAdd(c->dict,dstkey,dstset);
2464 incrRefCount(dstkey);
2465 }
2466
2467 /* Iterate all the elements of the first (smallest) set, and test
2468 * the element against all the other sets, if at least one set does
2469 * not include the element it is discarded */
2470 di = dictGetIterator(dv[0]);
2471 if (!di) oom("dictGetIterator");
2472
2473 while((de = dictNext(di)) != NULL) {
2474 robj *ele;
2475
2476 for (j = 1; j < setsnum; j++)
2477 if (dictFind(dv[j],dictGetEntryKey(de)) == NULL) break;
2478 if (j != setsnum)
2479 continue; /* at least one set does not contain the member */
2480 ele = dictGetEntryKey(de);
2481 if (!dstkey) {
2482 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(ele->ptr)));
2483 addReply(c,ele);
2484 addReply(c,shared.crlf);
2485 cardinality++;
2486 } else {
2487 dictAdd(dstset->ptr,ele,NULL);
2488 incrRefCount(ele);
2489 }
2490 }
2491 dictReleaseIterator(di);
2492
2493 if (!dstkey)
2494 lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",cardinality);
2495 else
2496 addReply(c,shared.ok);
2497 zfree(dv);
2498 }
2499
2500 static void sinterCommand(redisClient *c) {
2501 sinterGenericCommand(c,c->argv+1,c->argc-1,NULL);
2502 }
2503
2504 static void sinterstoreCommand(redisClient *c) {
2505 sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
2506 }
2507
2508 static void flushdbCommand(redisClient *c) {
2509 dictEmpty(c->dict);
2510 addReply(c,shared.ok);
2511 saveDb(server.dbfilename);
2512 }
2513
2514 static void flushallCommand(redisClient *c) {
2515 emptyDb();
2516 addReply(c,shared.ok);
2517 saveDb(server.dbfilename);
2518 }
2519
2520 redisSortOperation *createSortOperation(int type, robj *pattern) {
2521 redisSortOperation *so = zmalloc(sizeof(*so));
2522 if (!so) oom("createSortOperation");
2523 so->type = type;
2524 so->pattern = pattern;
2525 return so;
2526 }
2527
2528 /* Return the value associated to the key with a name obtained
2529 * substituting the first occurence of '*' in 'pattern' with 'subst' */
2530 robj *lookupKeyByPattern(dict *dict, robj *pattern, robj *subst) {
2531 char *p;
2532 sds spat, ssub;
2533 robj keyobj;
2534 int prefixlen, sublen, postfixlen;
2535 dictEntry *de;
2536 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
2537 struct {
2538 long len;
2539 long free;
2540 char buf[REDIS_SORTKEY_MAX+1];
2541 } keyname;
2542
2543
2544 spat = pattern->ptr;
2545 ssub = subst->ptr;
2546 if (sdslen(spat)+sdslen(ssub)-1 > REDIS_SORTKEY_MAX) return NULL;
2547 p = strchr(spat,'*');
2548 if (!p) return NULL;
2549
2550 prefixlen = p-spat;
2551 sublen = sdslen(ssub);
2552 postfixlen = sdslen(spat)-(prefixlen+1);
2553 memcpy(keyname.buf,spat,prefixlen);
2554 memcpy(keyname.buf+prefixlen,ssub,sublen);
2555 memcpy(keyname.buf+prefixlen+sublen,p+1,postfixlen);
2556 keyname.buf[prefixlen+sublen+postfixlen] = '\0';
2557 keyname.len = prefixlen+sublen+postfixlen;
2558
2559 keyobj.refcount = 1;
2560 keyobj.type = REDIS_STRING;
2561 keyobj.ptr = ((char*)&keyname)+(sizeof(long)*2);
2562
2563 de = dictFind(dict,&keyobj);
2564 // printf("lookup '%s' => %p\n", keyname.buf,de);
2565 if (!de) return NULL;
2566 return dictGetEntryVal(de);
2567 }
2568
2569 /* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
2570 * the additional parameter is not standard but a BSD-specific we have to
2571 * pass sorting parameters via the global 'server' structure */
2572 static int sortCompare(const void *s1, const void *s2) {
2573 const redisSortObject *so1 = s1, *so2 = s2;
2574 int cmp;
2575
2576 if (!server.sort_alpha) {
2577 /* Numeric sorting. Here it's trivial as we precomputed scores */
2578 if (so1->u.score > so2->u.score) {
2579 cmp = 1;
2580 } else if (so1->u.score < so2->u.score) {
2581 cmp = -1;
2582 } else {
2583 cmp = 0;
2584 }
2585 } else {
2586 /* Alphanumeric sorting */
2587 if (server.sort_bypattern) {
2588 if (!so1->u.cmpobj || !so2->u.cmpobj) {
2589 /* At least one compare object is NULL */
2590 if (so1->u.cmpobj == so2->u.cmpobj)
2591 cmp = 0;
2592 else if (so1->u.cmpobj == NULL)
2593 cmp = -1;
2594 else
2595 cmp = 1;
2596 } else {
2597 /* We have both the objects, use strcoll */
2598 cmp = strcoll(so1->u.cmpobj->ptr,so2->u.cmpobj->ptr);
2599 }
2600 } else {
2601 /* Compare elements directly */
2602 cmp = strcoll(so1->obj->ptr,so2->obj->ptr);
2603 }
2604 }
2605 return server.sort_desc ? -cmp : cmp;
2606 }
2607
2608 /* The SORT command is the most complex command in Redis. Warning: this code
2609 * is optimized for speed and a bit less for readability */
2610 static void sortCommand(redisClient *c) {
2611 dictEntry *de;
2612 list *operations;
2613 int outputlen = 0;
2614 int desc = 0, alpha = 0;
2615 int limit_start = 0, limit_count = -1, start, end;
2616 int j, dontsort = 0, vectorlen;
2617 int getop = 0; /* GET operation counter */
2618 robj *sortval, *sortby = NULL;
2619 redisSortObject *vector; /* Resulting vector to sort */
2620
2621 /* Lookup the key to sort. It must be of the right types */
2622 de = dictFind(c->dict,c->argv[1]);
2623 if (de == NULL) {
2624 addReply(c,shared.nokeyerr);
2625 return;
2626 }
2627 sortval = dictGetEntryVal(de);
2628 if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST) {
2629 addReply(c,shared.wrongtypeerr);
2630 return;
2631 }
2632
2633 /* Create a list of operations to perform for every sorted element.
2634 * Operations can be GET/DEL/INCR/DECR */
2635 operations = listCreate();
2636 listSetFreeMethod(operations,zfree);
2637 j = 2;
2638
2639 /* Now we need to protect sortval incrementing its count, in the future
2640 * SORT may have options able to overwrite/delete keys during the sorting
2641 * and the sorted key itself may get destroied */
2642 incrRefCount(sortval);
2643
2644 /* The SORT command has an SQL-alike syntax, parse it */
2645 while(j < c->argc) {
2646 int leftargs = c->argc-j-1;
2647 if (!strcasecmp(c->argv[j]->ptr,"asc")) {
2648 desc = 0;
2649 } else if (!strcasecmp(c->argv[j]->ptr,"desc")) {
2650 desc = 1;
2651 } else if (!strcasecmp(c->argv[j]->ptr,"alpha")) {
2652 alpha = 1;
2653 } else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) {
2654 limit_start = atoi(c->argv[j+1]->ptr);
2655 limit_count = atoi(c->argv[j+2]->ptr);
2656 j+=2;
2657 } else if (!strcasecmp(c->argv[j]->ptr,"by") && leftargs >= 1) {
2658 sortby = c->argv[j+1];
2659 /* If the BY pattern does not contain '*', i.e. it is constant,
2660 * we don't need to sort nor to lookup the weight keys. */
2661 if (strchr(c->argv[j+1]->ptr,'*') == NULL) dontsort = 1;
2662 j++;
2663 } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
2664 listAddNodeTail(operations,createSortOperation(
2665 REDIS_SORT_GET,c->argv[j+1]));
2666 getop++;
2667 j++;
2668 } else if (!strcasecmp(c->argv[j]->ptr,"del") && leftargs >= 1) {
2669 listAddNodeTail(operations,createSortOperation(
2670 REDIS_SORT_DEL,c->argv[j+1]));
2671 j++;
2672 } else if (!strcasecmp(c->argv[j]->ptr,"incr") && leftargs >= 1) {
2673 listAddNodeTail(operations,createSortOperation(
2674 REDIS_SORT_INCR,c->argv[j+1]));
2675 j++;
2676 } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
2677 listAddNodeTail(operations,createSortOperation(
2678 REDIS_SORT_DECR,c->argv[j+1]));
2679 j++;
2680 } else {
2681 decrRefCount(sortval);
2682 listRelease(operations);
2683 addReply(c,shared.syntaxerr);
2684 return;
2685 }
2686 j++;
2687 }
2688
2689 /* Load the sorting vector with all the objects to sort */
2690 vectorlen = (sortval->type == REDIS_LIST) ?
2691 listLength((list*)sortval->ptr) :
2692 dictGetHashTableUsed((dict*)sortval->ptr);
2693 vector = zmalloc(sizeof(redisSortObject)*vectorlen);
2694 if (!vector) oom("allocating objects vector for SORT");
2695 j = 0;
2696 if (sortval->type == REDIS_LIST) {
2697 list *list = sortval->ptr;
2698 listNode *ln = list->head;
2699 while(ln) {
2700 robj *ele = ln->value;
2701 vector[j].obj = ele;
2702 vector[j].u.score = 0;
2703 vector[j].u.cmpobj = NULL;
2704 ln = ln->next;
2705 j++;
2706 }
2707 } else {
2708 dict *set = sortval->ptr;
2709 dictIterator *di;
2710 dictEntry *setele;
2711
2712 di = dictGetIterator(set);
2713 if (!di) oom("dictGetIterator");
2714 while((setele = dictNext(di)) != NULL) {
2715 vector[j].obj = dictGetEntryKey(setele);
2716 vector[j].u.score = 0;
2717 vector[j].u.cmpobj = NULL;
2718 j++;
2719 }
2720 dictReleaseIterator(di);
2721 }
2722 assert(j == vectorlen);
2723
2724 /* Now it's time to load the right scores in the sorting vector */
2725 if (dontsort == 0) {
2726 for (j = 0; j < vectorlen; j++) {
2727 if (sortby) {
2728 robj *byval;
2729
2730 byval = lookupKeyByPattern(c->dict,sortby,vector[j].obj);
2731 if (!byval || byval->type != REDIS_STRING) continue;
2732 if (alpha) {
2733 vector[j].u.cmpobj = byval;
2734 incrRefCount(byval);
2735 } else {
2736 vector[j].u.score = strtod(byval->ptr,NULL);
2737 }
2738 } else {
2739 if (!alpha) vector[j].u.score = strtod(vector[j].obj->ptr,NULL);
2740 }
2741 }
2742 }
2743
2744 /* We are ready to sort the vector... perform a bit of sanity check
2745 * on the LIMIT option too. We'll use a partial version of quicksort. */
2746 start = (limit_start < 0) ? 0 : limit_start;
2747 end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1;
2748 if (start >= vectorlen) {
2749 start = vectorlen-1;
2750 end = vectorlen-2;
2751 }
2752 if (end >= vectorlen) end = vectorlen-1;
2753
2754 if (dontsort == 0) {
2755 server.sort_desc = desc;
2756 server.sort_alpha = alpha;
2757 server.sort_bypattern = sortby ? 1 : 0;
2758 qsort(vector,vectorlen,sizeof(redisSortObject),sortCompare);
2759 }
2760
2761 /* Send command output to the output buffer, performing the specified
2762 * GET/DEL/INCR/DECR operations if any. */
2763 outputlen = getop ? getop*(end-start+1) : end-start+1;
2764 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",outputlen));
2765 for (j = start; j <= end; j++) {
2766 listNode *ln = operations->head;
2767 if (!getop) {
2768 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",
2769 sdslen(vector[j].obj->ptr)));
2770 addReply(c,vector[j].obj);
2771 addReply(c,shared.crlf);
2772 }
2773 while(ln) {
2774 redisSortOperation *sop = ln->value;
2775 robj *val = lookupKeyByPattern(c->dict,sop->pattern,
2776 vector[j].obj);
2777
2778 if (sop->type == REDIS_SORT_GET) {
2779 if (!val || val->type != REDIS_STRING) {
2780 addReply(c,shared.nullbulk);
2781 } else {
2782 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",
2783 sdslen(val->ptr)));
2784 addReply(c,val);
2785 addReply(c,shared.crlf);
2786 }
2787 } else if (sop->type == REDIS_SORT_DEL) {
2788 /* TODO */
2789 }
2790 ln = ln->next;
2791 }
2792 }
2793
2794 /* Cleanup */
2795 decrRefCount(sortval);
2796 listRelease(operations);
2797 for (j = 0; j < vectorlen; j++) {
2798 if (sortby && alpha && vector[j].u.cmpobj)
2799 decrRefCount(vector[j].u.cmpobj);
2800 }
2801 zfree(vector);
2802 }
2803
2804 static void infoCommand(redisClient *c) {
2805 sds info;
2806 time_t uptime = time(NULL)-server.stat_starttime;
2807
2808 info = sdscatprintf(sdsempty(),
2809 "redis_version:%s\r\n"
2810 "connected_clients:%d\r\n"
2811 "connected_slaves:%d\r\n"
2812 "used_memory:%d\r\n"
2813 "changes_since_last_save:%lld\r\n"
2814 "last_save_time:%d\r\n"
2815 "total_connections_received:%lld\r\n"
2816 "total_commands_processed:%lld\r\n"
2817 "uptime_in_seconds:%d\r\n"
2818 "uptime_in_days:%d\r\n"
2819 ,REDIS_VERSION,
2820 listLength(server.clients)-listLength(server.slaves),
2821 listLength(server.slaves),
2822 server.usedmemory,
2823 server.dirty,
2824 server.lastsave,
2825 server.stat_numconnections,
2826 server.stat_numcommands,
2827 uptime,
2828 uptime/(3600*24)
2829 );
2830 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(info)));
2831 addReplySds(c,info);
2832 addReply(c,shared.crlf);
2833 }
2834
2835 /* =============================== Replication ============================= */
2836
2837 /* Send the whole output buffer syncronously to the slave. This a general operation in theory, but it is actually useful only for replication. */
2838 static int flushClientOutput(redisClient *c) {
2839 int retval;
2840 time_t start = time(NULL);
2841
2842 while(listLength(c->reply)) {
2843 if (time(NULL)-start > 5) return REDIS_ERR; /* 5 seconds timeout */
2844 retval = aeWait(c->fd,AE_WRITABLE,1000);
2845 if (retval == -1) {
2846 return REDIS_ERR;
2847 } else if (retval & AE_WRITABLE) {
2848 sendReplyToClient(NULL, c->fd, c, AE_WRITABLE);
2849 }
2850 }
2851 return REDIS_OK;
2852 }
2853
2854 static int syncWrite(int fd, void *ptr, ssize_t size, int timeout) {
2855 ssize_t nwritten, ret = size;
2856 time_t start = time(NULL);
2857
2858 timeout++;
2859 while(size) {
2860 if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
2861 nwritten = write(fd,ptr,size);
2862 if (nwritten == -1) return -1;
2863 ptr += nwritten;
2864 size -= nwritten;
2865 }
2866 if ((time(NULL)-start) > timeout) {
2867 errno = ETIMEDOUT;
2868 return -1;
2869 }
2870 }
2871 return ret;
2872 }
2873
2874 static int syncRead(int fd, void *ptr, ssize_t size, int timeout) {
2875 ssize_t nread, totread = 0;
2876 time_t start = time(NULL);
2877
2878 timeout++;
2879 while(size) {
2880 if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
2881 nread = read(fd,ptr,size);
2882 if (nread == -1) return -1;
2883 ptr += nread;
2884 size -= nread;
2885 totread += nread;
2886 }
2887 if ((time(NULL)-start) > timeout) {
2888 errno = ETIMEDOUT;
2889 return -1;
2890 }
2891 }
2892 return totread;
2893 }
2894
2895 static int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
2896 ssize_t nread = 0;
2897
2898 size--;
2899 while(size) {
2900 char c;
2901
2902 if (syncRead(fd,&c,1,timeout) == -1) return -1;
2903 if (c == '\n') {
2904 *ptr = '\0';
2905 if (nread && *(ptr-1) == '\r') *(ptr-1) = '\0';
2906 return nread;
2907 } else {
2908 *ptr++ = c;
2909 *ptr = '\0';
2910 nread++;
2911 }
2912 }
2913 return nread;
2914 }
2915
2916 static void syncCommand(redisClient *c) {
2917 struct stat sb;
2918 int fd = -1, len;
2919 time_t start = time(NULL);
2920 char sizebuf[32];
2921
2922 /* ignore SYNC if aleady slave or in monitor mode */
2923 if (c->flags & REDIS_SLAVE) return;
2924
2925 redisLog(REDIS_NOTICE,"Slave ask for syncronization");
2926 if (flushClientOutput(c) == REDIS_ERR || saveDb(server.dbfilename) != REDIS_OK)
2927 goto closeconn;
2928
2929 fd = open(server.dbfilename, O_RDONLY);
2930 if (fd == -1 || fstat(fd,&sb) == -1) goto closeconn;
2931 len = sb.st_size;
2932
2933 snprintf(sizebuf,32,"$%d\r\n",len);
2934 if (syncWrite(c->fd,sizebuf,strlen(sizebuf),5) == -1) goto closeconn;
2935 while(len) {
2936 char buf[1024];
2937 int nread;
2938
2939 if (time(NULL)-start > REDIS_MAX_SYNC_TIME) goto closeconn;
2940 nread = read(fd,buf,1024);
2941 if (nread == -1) goto closeconn;
2942 len -= nread;
2943 if (syncWrite(c->fd,buf,nread,5) == -1) goto closeconn;
2944 }
2945 if (syncWrite(c->fd,"\r\n",2,5) == -1) goto closeconn;
2946 close(fd);
2947 c->flags |= REDIS_SLAVE;
2948 c->slaveseldb = 0;
2949 if (!listAddNodeTail(server.slaves,c)) oom("listAddNodeTail");
2950 redisLog(REDIS_NOTICE,"Syncronization with slave succeeded");
2951 return;
2952
2953 closeconn:
2954 if (fd != -1) close(fd);
2955 c->flags |= REDIS_CLOSE;
2956 redisLog(REDIS_WARNING,"Syncronization with slave failed");
2957 return;
2958 }
2959
2960 static int syncWithMaster(void) {
2961 char buf[1024], tmpfile[256];
2962 int dumpsize;
2963 int fd = anetTcpConnect(NULL,server.masterhost,server.masterport);
2964 int dfd;
2965
2966 if (fd == -1) {
2967 redisLog(REDIS_WARNING,"Unable to connect to MASTER: %s",
2968 strerror(errno));
2969 return REDIS_ERR;
2970 }
2971 /* Issue the SYNC command */
2972 if (syncWrite(fd,"SYNC \r\n",7,5) == -1) {
2973 close(fd);
2974 redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
2975 strerror(errno));
2976 return REDIS_ERR;
2977 }
2978 /* Read the bulk write count */
2979 if (syncReadLine(fd,buf,1024,5) == -1) {
2980 close(fd);
2981 redisLog(REDIS_WARNING,"I/O error reading bulk count from MASTER: %s",
2982 strerror(errno));
2983 return REDIS_ERR;
2984 }
2985 dumpsize = atoi(buf+1);
2986 redisLog(REDIS_NOTICE,"Receiving %d bytes data dump from MASTER",dumpsize);
2987 /* Read the bulk write data on a temp file */
2988 snprintf(tmpfile,256,"temp-%d.%ld.rdb",(int)time(NULL),(long int)random());
2989 dfd = open(tmpfile,O_CREAT|O_WRONLY,0644);
2990 if (dfd == -1) {
2991 close(fd);
2992 redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
2993 return REDIS_ERR;
2994 }
2995 while(dumpsize) {
2996 int nread, nwritten;
2997
2998 nread = read(fd,buf,(dumpsize < 1024)?dumpsize:1024);
2999 if (nread == -1) {
3000 redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
3001 strerror(errno));
3002 close(fd);
3003 close(dfd);
3004 return REDIS_ERR;
3005 }
3006 nwritten = write(dfd,buf,nread);
3007 if (nwritten == -1) {
3008 redisLog(REDIS_WARNING,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
3009 close(fd);
3010 close(dfd);
3011 return REDIS_ERR;
3012 }
3013 dumpsize -= nread;
3014 }
3015 close(dfd);
3016 if (rename(tmpfile,server.dbfilename) == -1) {
3017 redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
3018 unlink(tmpfile);
3019 close(fd);
3020 return REDIS_ERR;
3021 }
3022 emptyDb();
3023 if (loadDb(server.dbfilename) != REDIS_OK) {
3024 redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
3025 close(fd);
3026 return REDIS_ERR;
3027 }
3028 server.master = createClient(fd);
3029 server.master->flags |= REDIS_MASTER;
3030 server.replstate = REDIS_REPL_CONNECTED;
3031 return REDIS_OK;
3032 }
3033
3034 static void monitorCommand(redisClient *c) {
3035 /* ignore MONITOR if aleady slave or in monitor mode */
3036 if (c->flags & REDIS_SLAVE) return;
3037
3038 c->flags |= (REDIS_SLAVE|REDIS_MONITOR);
3039 c->slaveseldb = 0;
3040 if (!listAddNodeTail(server.monitors,c)) oom("listAddNodeTail");
3041 addReply(c,shared.ok);
3042 }
3043
3044 /* =================================== Main! ================================ */
3045
3046 static void daemonize(void) {
3047 int fd;
3048 FILE *fp;
3049
3050 if (fork() != 0) exit(0); /* parent exits */
3051 setsid(); /* create a new session */
3052
3053 /* Every output goes to /dev/null. If Redis is daemonized but
3054 * the 'logfile' is set to 'stdout' in the configuration file
3055 * it will not log at all. */
3056 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
3057 dup2(fd, STDIN_FILENO);
3058 dup2(fd, STDOUT_FILENO);
3059 dup2(fd, STDERR_FILENO);
3060 if (fd > STDERR_FILENO) close(fd);
3061 }
3062 /* Try to write the pid file */
3063 fp = fopen(server.pidfile,"w");
3064 if (fp) {
3065 fprintf(fp,"%d\n",getpid());
3066 fclose(fp);
3067 }
3068 }
3069
3070 int main(int argc, char **argv) {
3071 initServerConfig();
3072 if (argc == 2) {
3073 ResetServerSaveParams();
3074 loadServerConfig(argv[1]);
3075 } else if (argc > 2) {
3076 fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
3077 exit(1);
3078 }
3079 initServer();
3080 if (server.daemonize) daemonize();
3081 redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
3082 if (loadDb(server.dbfilename) == REDIS_OK)
3083 redisLog(REDIS_NOTICE,"DB loaded from disk");
3084 if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,
3085 acceptHandler, NULL, NULL) == AE_ERR) oom("creating file event");
3086 redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
3087 aeMain(server.el);
3088 aeDeleteEventLoop(server.el);
3089 return 0;
3090 }