]> git.saurik.com Git - redis.git/blob - redis.c
MONITOR command implemented.
[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.07"
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, *zerobulk, *nil, *zero, *one, *pong, *space,
218 *minus1, *minus2, *minus3, *minus4,
219 *wrongtypeerr, *nokeyerr, *wrongtypeerrbulk, *nokeyerrbulk,
220 *syntaxerr, *syntaxerrbulk,
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.zerobulk = createObject(REDIS_STRING,sdsnew("0\r\n\r\n"));
664 shared.nil = createObject(REDIS_STRING,sdsnew("nil\r\n"));
665 shared.zero = createObject(REDIS_STRING,sdsnew("0\r\n"));
666 shared.one = createObject(REDIS_STRING,sdsnew("1\r\n"));
667 /* no such key */
668 shared.minus1 = createObject(REDIS_STRING,sdsnew("-1\r\n"));
669 /* operation against key holding a value of the wrong type */
670 shared.minus2 = createObject(REDIS_STRING,sdsnew("-2\r\n"));
671 /* src and dest objects are the same */
672 shared.minus3 = createObject(REDIS_STRING,sdsnew("-3\r\n"));
673 /* out of range argument */
674 shared.minus4 = createObject(REDIS_STRING,sdsnew("-4\r\n"));
675 shared.pong = createObject(REDIS_STRING,sdsnew("+PONG\r\n"));
676 shared.wrongtypeerr = createObject(REDIS_STRING,sdsnew(
677 "-ERR Operation against a key holding the wrong kind of value\r\n"));
678 shared.wrongtypeerrbulk = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%d\r\n%s",-sdslen(shared.wrongtypeerr->ptr)+2,shared.wrongtypeerr->ptr));
679 shared.nokeyerr = createObject(REDIS_STRING,sdsnew(
680 "-ERR no such key\r\n"));
681 shared.nokeyerrbulk = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%d\r\n%s",-sdslen(shared.nokeyerr->ptr)+2,shared.nokeyerr->ptr));
682 shared.syntaxerr = createObject(REDIS_STRING,sdsnew(
683 "-ERR syntax error\r\n"));
684 shared.syntaxerrbulk = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%d\r\n%s",-sdslen(shared.syntaxerr->ptr)+2,shared.syntaxerr->ptr));
685 shared.space = createObject(REDIS_STRING,sdsnew(" "));
686 shared.select0 = createStringObject("select 0\r\n",10);
687 shared.select1 = createStringObject("select 1\r\n",10);
688 shared.select2 = createStringObject("select 2\r\n",10);
689 shared.select3 = createStringObject("select 3\r\n",10);
690 shared.select4 = createStringObject("select 4\r\n",10);
691 shared.select5 = createStringObject("select 5\r\n",10);
692 shared.select6 = createStringObject("select 6\r\n",10);
693 shared.select7 = createStringObject("select 7\r\n",10);
694 shared.select8 = createStringObject("select 8\r\n",10);
695 shared.select9 = createStringObject("select 9\r\n",10);
696 }
697
698 static void appendServerSaveParams(time_t seconds, int changes) {
699 server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));
700 if (server.saveparams == NULL) oom("appendServerSaveParams");
701 server.saveparams[server.saveparamslen].seconds = seconds;
702 server.saveparams[server.saveparamslen].changes = changes;
703 server.saveparamslen++;
704 }
705
706 static void ResetServerSaveParams() {
707 zfree(server.saveparams);
708 server.saveparams = NULL;
709 server.saveparamslen = 0;
710 }
711
712 static void initServerConfig() {
713 server.dbnum = REDIS_DEFAULT_DBNUM;
714 server.port = REDIS_SERVERPORT;
715 server.verbosity = REDIS_DEBUG;
716 server.maxidletime = REDIS_MAXIDLETIME;
717 server.saveparams = NULL;
718 server.logfile = NULL; /* NULL = log on standard output */
719 server.bindaddr = NULL;
720 server.glueoutputbuf = 1;
721 server.daemonize = 0;
722 server.pidfile = "/var/run/redis.pid";
723 server.dbfilename = "dump.rdb";
724 ResetServerSaveParams();
725
726 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
727 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
728 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
729 /* Replication related */
730 server.isslave = 0;
731 server.masterhost = NULL;
732 server.masterport = 6379;
733 server.master = NULL;
734 server.replstate = REDIS_REPL_NONE;
735 }
736
737 static void initServer() {
738 int j;
739
740 signal(SIGHUP, SIG_IGN);
741 signal(SIGPIPE, SIG_IGN);
742
743 server.clients = listCreate();
744 server.slaves = listCreate();
745 server.monitors = listCreate();
746 server.objfreelist = listCreate();
747 createSharedObjects();
748 server.el = aeCreateEventLoop();
749 server.dict = zmalloc(sizeof(dict*)*server.dbnum);
750 if (!server.dict || !server.clients || !server.slaves || !server.monitors || !server.el || !server.objfreelist)
751 oom("server initialization"); /* Fatal OOM */
752 server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr);
753 if (server.fd == -1) {
754 redisLog(REDIS_WARNING, "Opening TCP port: %s", server.neterr);
755 exit(1);
756 }
757 for (j = 0; j < server.dbnum; j++) {
758 server.dict[j] = dictCreate(&hashDictType,NULL);
759 if (!server.dict[j])
760 oom("dictCreate"); /* Fatal OOM */
761 }
762 server.cronloops = 0;
763 server.bgsaveinprogress = 0;
764 server.lastsave = time(NULL);
765 server.dirty = 0;
766 server.usedmemory = 0;
767 server.stat_numcommands = 0;
768 server.stat_numconnections = 0;
769 server.stat_starttime = time(NULL);
770 aeCreateTimeEvent(server.el, 1000, serverCron, NULL, NULL);
771 }
772
773 /* Empty the whole database */
774 static void emptyDb() {
775 int j;
776
777 for (j = 0; j < server.dbnum; j++)
778 dictEmpty(server.dict[j]);
779 }
780
781 /* I agree, this is a very rudimental way to load a configuration...
782 will improve later if the config gets more complex */
783 static void loadServerConfig(char *filename) {
784 FILE *fp = fopen(filename,"r");
785 char buf[REDIS_CONFIGLINE_MAX+1], *err = NULL;
786 int linenum = 0;
787 sds line = NULL;
788
789 if (!fp) {
790 redisLog(REDIS_WARNING,"Fatal error, can't open config file");
791 exit(1);
792 }
793 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL) {
794 sds *argv;
795 int argc, j;
796
797 linenum++;
798 line = sdsnew(buf);
799 line = sdstrim(line," \t\r\n");
800
801 /* Skip comments and blank lines*/
802 if (line[0] == '#' || line[0] == '\0') {
803 sdsfree(line);
804 continue;
805 }
806
807 /* Split into arguments */
808 argv = sdssplitlen(line,sdslen(line)," ",1,&argc);
809 sdstolower(argv[0]);
810
811 /* Execute config directives */
812 if (!strcmp(argv[0],"timeout") && argc == 2) {
813 server.maxidletime = atoi(argv[1]);
814 if (server.maxidletime < 1) {
815 err = "Invalid timeout value"; goto loaderr;
816 }
817 } else if (!strcmp(argv[0],"port") && argc == 2) {
818 server.port = atoi(argv[1]);
819 if (server.port < 1 || server.port > 65535) {
820 err = "Invalid port"; goto loaderr;
821 }
822 } else if (!strcmp(argv[0],"bind") && argc == 2) {
823 server.bindaddr = zstrdup(argv[1]);
824 } else if (!strcmp(argv[0],"save") && argc == 3) {
825 int seconds = atoi(argv[1]);
826 int changes = atoi(argv[2]);
827 if (seconds < 1 || changes < 0) {
828 err = "Invalid save parameters"; goto loaderr;
829 }
830 appendServerSaveParams(seconds,changes);
831 } else if (!strcmp(argv[0],"dir") && argc == 2) {
832 if (chdir(argv[1]) == -1) {
833 redisLog(REDIS_WARNING,"Can't chdir to '%s': %s",
834 argv[1], strerror(errno));
835 exit(1);
836 }
837 } else if (!strcmp(argv[0],"loglevel") && argc == 2) {
838 if (!strcmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG;
839 else if (!strcmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE;
840 else if (!strcmp(argv[1],"warning")) server.verbosity = REDIS_WARNING;
841 else {
842 err = "Invalid log level. Must be one of debug, notice, warning";
843 goto loaderr;
844 }
845 } else if (!strcmp(argv[0],"logfile") && argc == 2) {
846 FILE *fp;
847
848 server.logfile = zstrdup(argv[1]);
849 if (!strcmp(server.logfile,"stdout")) {
850 zfree(server.logfile);
851 server.logfile = NULL;
852 }
853 if (server.logfile) {
854 /* Test if we are able to open the file. The server will not
855 * be able to abort just for this problem later... */
856 fp = fopen(server.logfile,"a");
857 if (fp == NULL) {
858 err = sdscatprintf(sdsempty(),
859 "Can't open the log file: %s", strerror(errno));
860 goto loaderr;
861 }
862 fclose(fp);
863 }
864 } else if (!strcmp(argv[0],"databases") && argc == 2) {
865 server.dbnum = atoi(argv[1]);
866 if (server.dbnum < 1) {
867 err = "Invalid number of databases"; goto loaderr;
868 }
869 } else if (!strcmp(argv[0],"slaveof") && argc == 3) {
870 server.masterhost = sdsnew(argv[1]);
871 server.masterport = atoi(argv[2]);
872 server.replstate = REDIS_REPL_CONNECT;
873 } else if (!strcmp(argv[0],"glueoutputbuf") && argc == 2) {
874 sdstolower(argv[1]);
875 if (!strcmp(argv[1],"yes")) server.glueoutputbuf = 1;
876 else if (!strcmp(argv[1],"no")) server.glueoutputbuf = 0;
877 else {
878 err = "argument must be 'yes' or 'no'"; goto loaderr;
879 }
880 } else if (!strcmp(argv[0],"daemonize") && argc == 2) {
881 sdstolower(argv[1]);
882 if (!strcmp(argv[1],"yes")) server.daemonize = 1;
883 else if (!strcmp(argv[1],"no")) server.daemonize = 0;
884 else {
885 err = "argument must be 'yes' or 'no'"; goto loaderr;
886 }
887 } else if (!strcmp(argv[0],"pidfile") && argc == 2) {
888 server.pidfile = zstrdup(argv[1]);
889 } else {
890 err = "Bad directive or wrong number of arguments"; goto loaderr;
891 }
892 for (j = 0; j < argc; j++)
893 sdsfree(argv[j]);
894 zfree(argv);
895 sdsfree(line);
896 }
897 fclose(fp);
898 return;
899
900 loaderr:
901 fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n");
902 fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
903 fprintf(stderr, ">>> '%s'\n", line);
904 fprintf(stderr, "%s\n", err);
905 exit(1);
906 }
907
908 static void freeClientArgv(redisClient *c) {
909 int j;
910
911 for (j = 0; j < c->argc; j++)
912 decrRefCount(c->argv[j]);
913 c->argc = 0;
914 }
915
916 static void freeClient(redisClient *c) {
917 listNode *ln;
918
919 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
920 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
921 sdsfree(c->querybuf);
922 listRelease(c->reply);
923 freeClientArgv(c);
924 close(c->fd);
925 ln = listSearchKey(server.clients,c);
926 assert(ln != NULL);
927 listDelNode(server.clients,ln);
928 if (c->flags & REDIS_SLAVE) {
929 list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
930 ln = listSearchKey(l,c);
931 assert(ln != NULL);
932 listDelNode(l,ln);
933 }
934 if (c->flags & REDIS_MASTER) {
935 server.master = NULL;
936 server.replstate = REDIS_REPL_CONNECT;
937 }
938 zfree(c);
939 }
940
941 static void glueReplyBuffersIfNeeded(redisClient *c) {
942 int totlen = 0;
943 listNode *ln = c->reply->head, *next;
944 robj *o;
945
946 while(ln) {
947 o = ln->value;
948 totlen += sdslen(o->ptr);
949 ln = ln->next;
950 /* This optimization makes more sense if we don't have to copy
951 * too much data */
952 if (totlen > 1024) return;
953 }
954 if (totlen > 0) {
955 char buf[1024];
956 int copylen = 0;
957
958 ln = c->reply->head;
959 while(ln) {
960 next = ln->next;
961 o = ln->value;
962 memcpy(buf+copylen,o->ptr,sdslen(o->ptr));
963 copylen += sdslen(o->ptr);
964 listDelNode(c->reply,ln);
965 ln = next;
966 }
967 /* Now the output buffer is empty, add the new single element */
968 addReplySds(c,sdsnewlen(buf,totlen));
969 }
970 }
971
972 static void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
973 redisClient *c = privdata;
974 int nwritten = 0, totwritten = 0, objlen;
975 robj *o;
976 REDIS_NOTUSED(el);
977 REDIS_NOTUSED(mask);
978
979 if (server.glueoutputbuf && listLength(c->reply) > 1)
980 glueReplyBuffersIfNeeded(c);
981 while(listLength(c->reply)) {
982 o = listNodeValue(listFirst(c->reply));
983 objlen = sdslen(o->ptr);
984
985 if (objlen == 0) {
986 listDelNode(c->reply,listFirst(c->reply));
987 continue;
988 }
989
990 if (c->flags & REDIS_MASTER) {
991 nwritten = objlen - c->sentlen;
992 } else {
993 nwritten = write(fd, o->ptr+c->sentlen, objlen - c->sentlen);
994 if (nwritten <= 0) break;
995 }
996 c->sentlen += nwritten;
997 totwritten += nwritten;
998 /* If we fully sent the object on head go to the next one */
999 if (c->sentlen == objlen) {
1000 listDelNode(c->reply,listFirst(c->reply));
1001 c->sentlen = 0;
1002 }
1003 }
1004 if (nwritten == -1) {
1005 if (errno == EAGAIN) {
1006 nwritten = 0;
1007 } else {
1008 redisLog(REDIS_DEBUG,
1009 "Error writing to client: %s", strerror(errno));
1010 freeClient(c);
1011 return;
1012 }
1013 }
1014 if (totwritten > 0) c->lastinteraction = time(NULL);
1015 if (listLength(c->reply) == 0) {
1016 c->sentlen = 0;
1017 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
1018 }
1019 }
1020
1021 static struct redisCommand *lookupCommand(char *name) {
1022 int j = 0;
1023 while(cmdTable[j].name != NULL) {
1024 if (!strcmp(name,cmdTable[j].name)) return &cmdTable[j];
1025 j++;
1026 }
1027 return NULL;
1028 }
1029
1030 /* resetClient prepare the client to process the next command */
1031 static void resetClient(redisClient *c) {
1032 freeClientArgv(c);
1033 c->bulklen = -1;
1034 }
1035
1036 /* If this function gets called we already read a whole
1037 * command, argments are in the client argv/argc fields.
1038 * processCommand() execute the command or prepare the
1039 * server for a bulk read from the client.
1040 *
1041 * If 1 is returned the client is still alive and valid and
1042 * and other operations can be performed by the caller. Otherwise
1043 * if 0 is returned the client was destroied (i.e. after QUIT). */
1044 static int processCommand(redisClient *c) {
1045 struct redisCommand *cmd;
1046 long long dirty;
1047
1048 sdstolower(c->argv[0]->ptr);
1049 /* The QUIT command is handled as a special case. Normal command
1050 * procs are unable to close the client connection safely */
1051 if (!strcmp(c->argv[0]->ptr,"quit")) {
1052 freeClient(c);
1053 return 0;
1054 }
1055 cmd = lookupCommand(c->argv[0]->ptr);
1056 if (!cmd) {
1057 addReplySds(c,sdsnew("-ERR unknown command\r\n"));
1058 resetClient(c);
1059 return 1;
1060 } else if ((cmd->arity > 0 && cmd->arity != c->argc) ||
1061 (c->argc < -cmd->arity)) {
1062 addReplySds(c,sdsnew("-ERR wrong number of arguments\r\n"));
1063 resetClient(c);
1064 return 1;
1065 } else if (cmd->flags & REDIS_CMD_BULK && c->bulklen == -1) {
1066 int bulklen = atoi(c->argv[c->argc-1]->ptr);
1067
1068 decrRefCount(c->argv[c->argc-1]);
1069 if (bulklen < 0 || bulklen > 1024*1024*1024) {
1070 c->argc--;
1071 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
1072 resetClient(c);
1073 return 1;
1074 }
1075 c->argc--;
1076 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
1077 /* It is possible that the bulk read is already in the
1078 * buffer. Check this condition and handle it accordingly */
1079 if ((signed)sdslen(c->querybuf) >= c->bulklen) {
1080 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
1081 c->argc++;
1082 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
1083 } else {
1084 return 1;
1085 }
1086 }
1087 /* Exec the command */
1088 dirty = server.dirty;
1089 cmd->proc(c);
1090 if (server.dirty-dirty != 0 && listLength(server.slaves))
1091 replicationFeedSlaves(server.slaves,cmd,c->dictid,c->argv,c->argc);
1092 if (listLength(server.monitors))
1093 replicationFeedSlaves(server.monitors,cmd,c->dictid,c->argv,c->argc);
1094 server.stat_numcommands++;
1095
1096 /* Prepare the client for the next command */
1097 if (c->flags & REDIS_CLOSE) {
1098 freeClient(c);
1099 return 0;
1100 }
1101 resetClient(c);
1102 return 1;
1103 }
1104
1105 static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc) {
1106 listNode *ln = slaves->head;
1107 robj *outv[REDIS_MAX_ARGS*4]; /* enough room for args, spaces, newlines */
1108 int outc = 0, j;
1109
1110 for (j = 0; j < argc; j++) {
1111 if (j != 0) outv[outc++] = shared.space;
1112 if ((cmd->flags & REDIS_CMD_BULK) && j == argc-1) {
1113 robj *lenobj;
1114
1115 lenobj = createObject(REDIS_STRING,
1116 sdscatprintf(sdsempty(),"%d\r\n",sdslen(argv[j]->ptr)));
1117 lenobj->refcount = 0;
1118 outv[outc++] = lenobj;
1119 }
1120 outv[outc++] = argv[j];
1121 }
1122 outv[outc++] = shared.crlf;
1123
1124 while(ln) {
1125 redisClient *slave = ln->value;
1126 if (slave->slaveseldb != dictid) {
1127 robj *selectcmd;
1128
1129 switch(dictid) {
1130 case 0: selectcmd = shared.select0; break;
1131 case 1: selectcmd = shared.select1; break;
1132 case 2: selectcmd = shared.select2; break;
1133 case 3: selectcmd = shared.select3; break;
1134 case 4: selectcmd = shared.select4; break;
1135 case 5: selectcmd = shared.select5; break;
1136 case 6: selectcmd = shared.select6; break;
1137 case 7: selectcmd = shared.select7; break;
1138 case 8: selectcmd = shared.select8; break;
1139 case 9: selectcmd = shared.select9; break;
1140 default:
1141 selectcmd = createObject(REDIS_STRING,
1142 sdscatprintf(sdsempty(),"select %d\r\n",dictid));
1143 selectcmd->refcount = 0;
1144 break;
1145 }
1146 addReply(slave,selectcmd);
1147 slave->slaveseldb = dictid;
1148 }
1149 for (j = 0; j < outc; j++) addReply(slave,outv[j]);
1150 ln = ln->next;
1151 }
1152 }
1153
1154 static void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
1155 redisClient *c = (redisClient*) privdata;
1156 char buf[REDIS_QUERYBUF_LEN];
1157 int nread;
1158 REDIS_NOTUSED(el);
1159 REDIS_NOTUSED(mask);
1160
1161 nread = read(fd, buf, REDIS_QUERYBUF_LEN);
1162 if (nread == -1) {
1163 if (errno == EAGAIN) {
1164 nread = 0;
1165 } else {
1166 redisLog(REDIS_DEBUG, "Reading from client: %s",strerror(errno));
1167 freeClient(c);
1168 return;
1169 }
1170 } else if (nread == 0) {
1171 redisLog(REDIS_DEBUG, "Client closed connection");
1172 freeClient(c);
1173 return;
1174 }
1175 if (nread) {
1176 c->querybuf = sdscatlen(c->querybuf, buf, nread);
1177 c->lastinteraction = time(NULL);
1178 } else {
1179 return;
1180 }
1181
1182 again:
1183 if (c->bulklen == -1) {
1184 /* Read the first line of the query */
1185 char *p = strchr(c->querybuf,'\n');
1186 size_t querylen;
1187 if (p) {
1188 sds query, *argv;
1189 int argc, j;
1190
1191 query = c->querybuf;
1192 c->querybuf = sdsempty();
1193 querylen = 1+(p-(query));
1194 if (sdslen(query) > querylen) {
1195 /* leave data after the first line of the query in the buffer */
1196 c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
1197 }
1198 *p = '\0'; /* remove "\n" */
1199 if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
1200 sdsupdatelen(query);
1201
1202 /* Now we can split the query in arguments */
1203 if (sdslen(query) == 0) {
1204 /* Ignore empty query */
1205 sdsfree(query);
1206 return;
1207 }
1208 argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
1209 sdsfree(query);
1210 if (argv == NULL) oom("sdssplitlen");
1211 for (j = 0; j < argc && j < REDIS_MAX_ARGS; j++) {
1212 if (sdslen(argv[j])) {
1213 c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
1214 c->argc++;
1215 } else {
1216 sdsfree(argv[j]);
1217 }
1218 }
1219 zfree(argv);
1220 /* Execute the command. If the client is still valid
1221 * after processCommand() return and there is something
1222 * on the query buffer try to process the next command. */
1223 if (processCommand(c) && sdslen(c->querybuf)) goto again;
1224 return;
1225 } else if (sdslen(c->querybuf) >= 1024) {
1226 redisLog(REDIS_DEBUG, "Client protocol error");
1227 freeClient(c);
1228 return;
1229 }
1230 } else {
1231 /* Bulk read handling. Note that if we are at this point
1232 the client already sent a command terminated with a newline,
1233 we are reading the bulk data that is actually the last
1234 argument of the command. */
1235 int qbl = sdslen(c->querybuf);
1236
1237 if (c->bulklen <= qbl) {
1238 /* Copy everything but the final CRLF as final argument */
1239 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
1240 c->argc++;
1241 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
1242 processCommand(c);
1243 return;
1244 }
1245 }
1246 }
1247
1248 static int selectDb(redisClient *c, int id) {
1249 if (id < 0 || id >= server.dbnum)
1250 return REDIS_ERR;
1251 c->dict = server.dict[id];
1252 c->dictid = id;
1253 return REDIS_OK;
1254 }
1255
1256 static redisClient *createClient(int fd) {
1257 redisClient *c = zmalloc(sizeof(*c));
1258
1259 anetNonBlock(NULL,fd);
1260 anetTcpNoDelay(NULL,fd);
1261 if (!c) return NULL;
1262 selectDb(c,0);
1263 c->fd = fd;
1264 c->querybuf = sdsempty();
1265 c->argc = 0;
1266 c->bulklen = -1;
1267 c->sentlen = 0;
1268 c->flags = 0;
1269 c->lastinteraction = time(NULL);
1270 if ((c->reply = listCreate()) == NULL) oom("listCreate");
1271 listSetFreeMethod(c->reply,decrRefCount);
1272 if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
1273 readQueryFromClient, c, NULL) == AE_ERR) {
1274 freeClient(c);
1275 return NULL;
1276 }
1277 if (!listAddNodeTail(server.clients,c)) oom("listAddNodeTail");
1278 return c;
1279 }
1280
1281 static void addReply(redisClient *c, robj *obj) {
1282 if (listLength(c->reply) == 0 &&
1283 aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
1284 sendReplyToClient, c, NULL) == AE_ERR) return;
1285 if (!listAddNodeTail(c->reply,obj)) oom("listAddNodeTail");
1286 incrRefCount(obj);
1287 }
1288
1289 static void addReplySds(redisClient *c, sds s) {
1290 robj *o = createObject(REDIS_STRING,s);
1291 addReply(c,o);
1292 decrRefCount(o);
1293 }
1294
1295 static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
1296 int cport, cfd;
1297 char cip[128];
1298 REDIS_NOTUSED(el);
1299 REDIS_NOTUSED(mask);
1300 REDIS_NOTUSED(privdata);
1301
1302 cfd = anetAccept(server.neterr, fd, cip, &cport);
1303 if (cfd == AE_ERR) {
1304 redisLog(REDIS_DEBUG,"Accepting client connection: %s", server.neterr);
1305 return;
1306 }
1307 redisLog(REDIS_DEBUG,"Accepted %s:%d", cip, cport);
1308 if (createClient(cfd) == NULL) {
1309 redisLog(REDIS_WARNING,"Error allocating resoures for the client");
1310 close(cfd); /* May be already closed, just ingore errors */
1311 return;
1312 }
1313 server.stat_numconnections++;
1314 }
1315
1316 /* ======================= Redis objects implementation ===================== */
1317
1318 static robj *createObject(int type, void *ptr) {
1319 robj *o;
1320
1321 if (listLength(server.objfreelist)) {
1322 listNode *head = listFirst(server.objfreelist);
1323 o = listNodeValue(head);
1324 listDelNode(server.objfreelist,head);
1325 } else {
1326 o = zmalloc(sizeof(*o));
1327 }
1328 if (!o) oom("createObject");
1329 o->type = type;
1330 o->ptr = ptr;
1331 o->refcount = 1;
1332 return o;
1333 }
1334
1335 static robj *createStringObject(char *ptr, size_t len) {
1336 return createObject(REDIS_STRING,sdsnewlen(ptr,len));
1337 }
1338
1339 static robj *createListObject(void) {
1340 list *l = listCreate();
1341
1342 if (!l) oom("listCreate");
1343 listSetFreeMethod(l,decrRefCount);
1344 return createObject(REDIS_LIST,l);
1345 }
1346
1347 static robj *createSetObject(void) {
1348 dict *d = dictCreate(&setDictType,NULL);
1349 if (!d) oom("dictCreate");
1350 return createObject(REDIS_SET,d);
1351 }
1352
1353 #if 0
1354 static robj *createHashObject(void) {
1355 dict *d = dictCreate(&hashDictType,NULL);
1356 if (!d) oom("dictCreate");
1357 return createObject(REDIS_SET,d);
1358 }
1359 #endif
1360
1361 static void freeStringObject(robj *o) {
1362 sdsfree(o->ptr);
1363 }
1364
1365 static void freeListObject(robj *o) {
1366 listRelease((list*) o->ptr);
1367 }
1368
1369 static void freeSetObject(robj *o) {
1370 dictRelease((dict*) o->ptr);
1371 }
1372
1373 static void freeHashObject(robj *o) {
1374 dictRelease((dict*) o->ptr);
1375 }
1376
1377 static void incrRefCount(robj *o) {
1378 o->refcount++;
1379 }
1380
1381 static void decrRefCount(void *obj) {
1382 robj *o = obj;
1383 if (--(o->refcount) == 0) {
1384 switch(o->type) {
1385 case REDIS_STRING: freeStringObject(o); break;
1386 case REDIS_LIST: freeListObject(o); break;
1387 case REDIS_SET: freeSetObject(o); break;
1388 case REDIS_HASH: freeHashObject(o); break;
1389 default: assert(0 != 0); break;
1390 }
1391 if (listLength(server.objfreelist) > REDIS_OBJFREELIST_MAX ||
1392 !listAddNodeHead(server.objfreelist,o))
1393 zfree(o);
1394 }
1395 }
1396
1397 /*============================ DB saving/loading ============================ */
1398
1399 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
1400 static int saveDb(char *filename) {
1401 dictIterator *di = NULL;
1402 dictEntry *de;
1403 uint32_t len;
1404 uint8_t type;
1405 FILE *fp;
1406 char tmpfile[256];
1407 int j;
1408
1409 snprintf(tmpfile,256,"temp-%d.%ld.rdb",(int)time(NULL),(long int)random());
1410 fp = fopen(tmpfile,"w");
1411 if (!fp) {
1412 redisLog(REDIS_WARNING, "Failed saving the DB: %s", strerror(errno));
1413 return REDIS_ERR;
1414 }
1415 if (fwrite("REDIS0000",9,1,fp) == 0) goto werr;
1416 for (j = 0; j < server.dbnum; j++) {
1417 dict *d = server.dict[j];
1418 if (dictGetHashTableUsed(d) == 0) continue;
1419 di = dictGetIterator(d);
1420 if (!di) {
1421 fclose(fp);
1422 return REDIS_ERR;
1423 }
1424
1425 /* Write the SELECT DB opcode */
1426 type = REDIS_SELECTDB;
1427 len = htonl(j);
1428 if (fwrite(&type,1,1,fp) == 0) goto werr;
1429 if (fwrite(&len,4,1,fp) == 0) goto werr;
1430
1431 /* Iterate this DB writing every entry */
1432 while((de = dictNext(di)) != NULL) {
1433 robj *key = dictGetEntryKey(de);
1434 robj *o = dictGetEntryVal(de);
1435
1436 type = o->type;
1437 len = htonl(sdslen(key->ptr));
1438 if (fwrite(&type,1,1,fp) == 0) goto werr;
1439 if (fwrite(&len,4,1,fp) == 0) goto werr;
1440 if (fwrite(key->ptr,sdslen(key->ptr),1,fp) == 0) goto werr;
1441 if (type == REDIS_STRING) {
1442 /* Save a string value */
1443 sds sval = o->ptr;
1444 len = htonl(sdslen(sval));
1445 if (fwrite(&len,4,1,fp) == 0) goto werr;
1446 if (sdslen(sval) &&
1447 fwrite(sval,sdslen(sval),1,fp) == 0) goto werr;
1448 } else if (type == REDIS_LIST) {
1449 /* Save a list value */
1450 list *list = o->ptr;
1451 listNode *ln = list->head;
1452
1453 len = htonl(listLength(list));
1454 if (fwrite(&len,4,1,fp) == 0) goto werr;
1455 while(ln) {
1456 robj *eleobj = listNodeValue(ln);
1457 len = htonl(sdslen(eleobj->ptr));
1458 if (fwrite(&len,4,1,fp) == 0) goto werr;
1459 if (sdslen(eleobj->ptr) && fwrite(eleobj->ptr,sdslen(eleobj->ptr),1,fp) == 0)
1460 goto werr;
1461 ln = ln->next;
1462 }
1463 } else if (type == REDIS_SET) {
1464 /* Save a set value */
1465 dict *set = o->ptr;
1466 dictIterator *di = dictGetIterator(set);
1467 dictEntry *de;
1468
1469 if (!set) oom("dictGetIteraotr");
1470 len = htonl(dictGetHashTableUsed(set));
1471 if (fwrite(&len,4,1,fp) == 0) goto werr;
1472 while((de = dictNext(di)) != NULL) {
1473 robj *eleobj;
1474
1475 eleobj = dictGetEntryKey(de);
1476 len = htonl(sdslen(eleobj->ptr));
1477 if (fwrite(&len,4,1,fp) == 0) goto werr;
1478 if (sdslen(eleobj->ptr) && fwrite(eleobj->ptr,sdslen(eleobj->ptr),1,fp) == 0)
1479 goto werr;
1480 }
1481 dictReleaseIterator(di);
1482 } else {
1483 assert(0 != 0);
1484 }
1485 }
1486 dictReleaseIterator(di);
1487 }
1488 /* EOF opcode */
1489 type = REDIS_EOF;
1490 if (fwrite(&type,1,1,fp) == 0) goto werr;
1491 fflush(fp);
1492 fsync(fileno(fp));
1493 fclose(fp);
1494
1495 /* Use RENAME to make sure the DB file is changed atomically only
1496 * if the generate DB file is ok. */
1497 if (rename(tmpfile,filename) == -1) {
1498 redisLog(REDIS_WARNING,"Error moving temp DB file on the final destionation: %s", strerror(errno));
1499 unlink(tmpfile);
1500 return REDIS_ERR;
1501 }
1502 redisLog(REDIS_NOTICE,"DB saved on disk");
1503 server.dirty = 0;
1504 server.lastsave = time(NULL);
1505 return REDIS_OK;
1506
1507 werr:
1508 fclose(fp);
1509 unlink(tmpfile);
1510 redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
1511 if (di) dictReleaseIterator(di);
1512 return REDIS_ERR;
1513 }
1514
1515 static int saveDbBackground(char *filename) {
1516 pid_t childpid;
1517
1518 if (server.bgsaveinprogress) return REDIS_ERR;
1519 if ((childpid = fork()) == 0) {
1520 /* Child */
1521 close(server.fd);
1522 if (saveDb(filename) == REDIS_OK) {
1523 exit(0);
1524 } else {
1525 exit(1);
1526 }
1527 } else {
1528 /* Parent */
1529 redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
1530 server.bgsaveinprogress = 1;
1531 return REDIS_OK;
1532 }
1533 return REDIS_OK; /* unreached */
1534 }
1535
1536 static int loadDb(char *filename) {
1537 FILE *fp;
1538 char buf[REDIS_LOADBUF_LEN]; /* Try to use this buffer instead of */
1539 char vbuf[REDIS_LOADBUF_LEN]; /* malloc() when the element is small */
1540 char *key = NULL, *val = NULL;
1541 uint32_t klen,vlen,dbid;
1542 uint8_t type;
1543 int retval;
1544 dict *d = server.dict[0];
1545
1546 fp = fopen(filename,"r");
1547 if (!fp) return REDIS_ERR;
1548 if (fread(buf,9,1,fp) == 0) goto eoferr;
1549 if (memcmp(buf,"REDIS0000",9) != 0) {
1550 fclose(fp);
1551 redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
1552 return REDIS_ERR;
1553 }
1554 while(1) {
1555 robj *o;
1556
1557 /* Read type. */
1558 if (fread(&type,1,1,fp) == 0) goto eoferr;
1559 if (type == REDIS_EOF) break;
1560 /* Handle SELECT DB opcode as a special case */
1561 if (type == REDIS_SELECTDB) {
1562 if (fread(&dbid,4,1,fp) == 0) goto eoferr;
1563 dbid = ntohl(dbid);
1564 if (dbid >= (unsigned)server.dbnum) {
1565 redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server compiled to handle more than %d databases. Exiting\n", server.dbnum);
1566 exit(1);
1567 }
1568 d = server.dict[dbid];
1569 continue;
1570 }
1571 /* Read key */
1572 if (fread(&klen,4,1,fp) == 0) goto eoferr;
1573 klen = ntohl(klen);
1574 if (klen <= REDIS_LOADBUF_LEN) {
1575 key = buf;
1576 } else {
1577 key = zmalloc(klen);
1578 if (!key) oom("Loading DB from file");
1579 }
1580 if (fread(key,klen,1,fp) == 0) goto eoferr;
1581
1582 if (type == REDIS_STRING) {
1583 /* Read string value */
1584 if (fread(&vlen,4,1,fp) == 0) goto eoferr;
1585 vlen = ntohl(vlen);
1586 if (vlen <= REDIS_LOADBUF_LEN) {
1587 val = vbuf;
1588 } else {
1589 val = zmalloc(vlen);
1590 if (!val) oom("Loading DB from file");
1591 }
1592 if (vlen && fread(val,vlen,1,fp) == 0) goto eoferr;
1593 o = createObject(REDIS_STRING,sdsnewlen(val,vlen));
1594 } else if (type == REDIS_LIST || type == REDIS_SET) {
1595 /* Read list/set value */
1596 uint32_t listlen;
1597 if (fread(&listlen,4,1,fp) == 0) goto eoferr;
1598 listlen = ntohl(listlen);
1599 o = (type == REDIS_LIST) ? createListObject() : createSetObject();
1600 /* Load every single element of the list/set */
1601 while(listlen--) {
1602 robj *ele;
1603
1604 if (fread(&vlen,4,1,fp) == 0) goto eoferr;
1605 vlen = ntohl(vlen);
1606 if (vlen <= REDIS_LOADBUF_LEN) {
1607 val = vbuf;
1608 } else {
1609 val = zmalloc(vlen);
1610 if (!val) oom("Loading DB from file");
1611 }
1612 if (vlen && fread(val,vlen,1,fp) == 0) goto eoferr;
1613 ele = createObject(REDIS_STRING,sdsnewlen(val,vlen));
1614 if (type == REDIS_LIST) {
1615 if (!listAddNodeTail((list*)o->ptr,ele))
1616 oom("listAddNodeTail");
1617 } else {
1618 if (dictAdd((dict*)o->ptr,ele,NULL) == DICT_ERR)
1619 oom("dictAdd");
1620 }
1621 /* free the temp buffer if needed */
1622 if (val != vbuf) zfree(val);
1623 val = NULL;
1624 }
1625 } else {
1626 assert(0 != 0);
1627 }
1628 /* Add the new object in the hash table */
1629 retval = dictAdd(d,createStringObject(key,klen),o);
1630 if (retval == DICT_ERR) {
1631 redisLog(REDIS_WARNING,"Loading DB, duplicated key found! Unrecoverable error, exiting now.");
1632 exit(1);
1633 }
1634 /* Iteration cleanup */
1635 if (key != buf) zfree(key);
1636 if (val != vbuf) zfree(val);
1637 key = val = NULL;
1638 }
1639 fclose(fp);
1640 return REDIS_OK;
1641
1642 eoferr: /* unexpected end of file is handled here with a fatal exit */
1643 if (key != buf) zfree(key);
1644 if (val != vbuf) zfree(val);
1645 redisLog(REDIS_WARNING,"Short read loading DB. Unrecoverable error, exiting now.");
1646 exit(1);
1647 return REDIS_ERR; /* Just to avoid warning */
1648 }
1649
1650 /*================================== Commands =============================== */
1651
1652 static void pingCommand(redisClient *c) {
1653 addReply(c,shared.pong);
1654 }
1655
1656 static void echoCommand(redisClient *c) {
1657 addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",
1658 (int)sdslen(c->argv[1]->ptr)));
1659 addReply(c,c->argv[1]);
1660 addReply(c,shared.crlf);
1661 }
1662
1663 /*=================================== Strings =============================== */
1664
1665 static void setGenericCommand(redisClient *c, int nx) {
1666 int retval;
1667
1668 retval = dictAdd(c->dict,c->argv[1],c->argv[2]);
1669 if (retval == DICT_ERR) {
1670 if (!nx) {
1671 dictReplace(c->dict,c->argv[1],c->argv[2]);
1672 incrRefCount(c->argv[2]);
1673 } else {
1674 addReply(c,shared.zero);
1675 return;
1676 }
1677 } else {
1678 incrRefCount(c->argv[1]);
1679 incrRefCount(c->argv[2]);
1680 }
1681 server.dirty++;
1682 addReply(c, nx ? shared.one : shared.ok);
1683 }
1684
1685 static void setCommand(redisClient *c) {
1686 return setGenericCommand(c,0);
1687 }
1688
1689 static void setnxCommand(redisClient *c) {
1690 return setGenericCommand(c,1);
1691 }
1692
1693 static void getCommand(redisClient *c) {
1694 dictEntry *de;
1695
1696 de = dictFind(c->dict,c->argv[1]);
1697 if (de == NULL) {
1698 addReply(c,shared.nil);
1699 } else {
1700 robj *o = dictGetEntryVal(de);
1701
1702 if (o->type != REDIS_STRING) {
1703 addReply(c,shared.wrongtypeerrbulk);
1704 } else {
1705 addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(o->ptr)));
1706 addReply(c,o);
1707 addReply(c,shared.crlf);
1708 }
1709 }
1710 }
1711
1712 static void mgetCommand(redisClient *c) {
1713 dictEntry *de;
1714 int j;
1715
1716 addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",c->argc-1));
1717 for (j = 1; j < c->argc; j++) {
1718 de = dictFind(c->dict,c->argv[j]);
1719 if (de == NULL) {
1720 addReply(c,shared.minus1);
1721 } else {
1722 robj *o = dictGetEntryVal(de);
1723
1724 if (o->type != REDIS_STRING) {
1725 addReply(c,shared.minus1);
1726 } else {
1727 addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(o->ptr)));
1728 addReply(c,o);
1729 addReply(c,shared.crlf);
1730 }
1731 }
1732 }
1733 }
1734
1735 static void incrDecrCommand(redisClient *c, int incr) {
1736 dictEntry *de;
1737 long long value;
1738 int retval;
1739 robj *o;
1740
1741 de = dictFind(c->dict,c->argv[1]);
1742 if (de == NULL) {
1743 value = 0;
1744 } else {
1745 robj *o = dictGetEntryVal(de);
1746
1747 if (o->type != REDIS_STRING) {
1748 value = 0;
1749 } else {
1750 char *eptr;
1751
1752 value = strtoll(o->ptr, &eptr, 10);
1753 }
1754 }
1755
1756 value += incr;
1757 o = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
1758 retval = dictAdd(c->dict,c->argv[1],o);
1759 if (retval == DICT_ERR) {
1760 dictReplace(c->dict,c->argv[1],o);
1761 } else {
1762 incrRefCount(c->argv[1]);
1763 }
1764 server.dirty++;
1765 addReply(c,o);
1766 addReply(c,shared.crlf);
1767 }
1768
1769 static void incrCommand(redisClient *c) {
1770 return incrDecrCommand(c,1);
1771 }
1772
1773 static void decrCommand(redisClient *c) {
1774 return incrDecrCommand(c,-1);
1775 }
1776
1777 static void incrbyCommand(redisClient *c) {
1778 int incr = atoi(c->argv[2]->ptr);
1779 return incrDecrCommand(c,incr);
1780 }
1781
1782 static void decrbyCommand(redisClient *c) {
1783 int incr = atoi(c->argv[2]->ptr);
1784 return incrDecrCommand(c,-incr);
1785 }
1786
1787 /* ========================= Type agnostic commands ========================= */
1788
1789 static void delCommand(redisClient *c) {
1790 if (dictDelete(c->dict,c->argv[1]) == DICT_OK) {
1791 server.dirty++;
1792 addReply(c,shared.one);
1793 } else {
1794 addReply(c,shared.zero);
1795 }
1796 }
1797
1798 static void existsCommand(redisClient *c) {
1799 dictEntry *de;
1800
1801 de = dictFind(c->dict,c->argv[1]);
1802 if (de == NULL)
1803 addReply(c,shared.zero);
1804 else
1805 addReply(c,shared.one);
1806 }
1807
1808 static void selectCommand(redisClient *c) {
1809 int id = atoi(c->argv[1]->ptr);
1810
1811 if (selectDb(c,id) == REDIS_ERR) {
1812 addReplySds(c,"-ERR invalid DB index\r\n");
1813 } else {
1814 addReply(c,shared.ok);
1815 }
1816 }
1817
1818 static void randomkeyCommand(redisClient *c) {
1819 dictEntry *de;
1820
1821 de = dictGetRandomKey(c->dict);
1822 if (de == NULL) {
1823 addReply(c,shared.crlf);
1824 } else {
1825 addReply(c,dictGetEntryKey(de));
1826 addReply(c,shared.crlf);
1827 }
1828 }
1829
1830 static void keysCommand(redisClient *c) {
1831 dictIterator *di;
1832 dictEntry *de;
1833 sds pattern = c->argv[1]->ptr;
1834 int plen = sdslen(pattern);
1835 int numkeys = 0, keyslen = 0;
1836 robj *lenobj = createObject(REDIS_STRING,NULL);
1837
1838 di = dictGetIterator(c->dict);
1839 if (!di) oom("dictGetIterator");
1840 addReply(c,lenobj);
1841 decrRefCount(lenobj);
1842 while((de = dictNext(di)) != NULL) {
1843 robj *keyobj = dictGetEntryKey(de);
1844 sds key = keyobj->ptr;
1845 if ((pattern[0] == '*' && pattern[1] == '\0') ||
1846 stringmatchlen(pattern,plen,key,sdslen(key),0)) {
1847 if (numkeys != 0)
1848 addReply(c,shared.space);
1849 addReply(c,keyobj);
1850 numkeys++;
1851 keyslen += sdslen(key);
1852 }
1853 }
1854 dictReleaseIterator(di);
1855 lenobj->ptr = sdscatprintf(sdsempty(),"%lu\r\n",keyslen+(numkeys ? (numkeys-1) : 0));
1856 addReply(c,shared.crlf);
1857 }
1858
1859 static void dbsizeCommand(redisClient *c) {
1860 addReplySds(c,
1861 sdscatprintf(sdsempty(),"%lu\r\n",dictGetHashTableUsed(c->dict)));
1862 }
1863
1864 static void lastsaveCommand(redisClient *c) {
1865 addReplySds(c,
1866 sdscatprintf(sdsempty(),"%lu\r\n",server.lastsave));
1867 }
1868
1869 static void typeCommand(redisClient *c) {
1870 dictEntry *de;
1871 char *type;
1872
1873 de = dictFind(c->dict,c->argv[1]);
1874 if (de == NULL) {
1875 type = "none";
1876 } else {
1877 robj *o = dictGetEntryVal(de);
1878
1879 switch(o->type) {
1880 case REDIS_STRING: type = "string"; break;
1881 case REDIS_LIST: type = "list"; break;
1882 case REDIS_SET: type = "set"; break;
1883 default: type = "unknown"; break;
1884 }
1885 }
1886 addReplySds(c,sdsnew(type));
1887 addReply(c,shared.crlf);
1888 }
1889
1890 static void saveCommand(redisClient *c) {
1891 if (saveDb(server.dbfilename) == REDIS_OK) {
1892 addReply(c,shared.ok);
1893 } else {
1894 addReply(c,shared.err);
1895 }
1896 }
1897
1898 static void bgsaveCommand(redisClient *c) {
1899 if (server.bgsaveinprogress) {
1900 addReplySds(c,sdsnew("-ERR background save already in progress\r\n"));
1901 return;
1902 }
1903 if (saveDbBackground(server.dbfilename) == REDIS_OK) {
1904 addReply(c,shared.ok);
1905 } else {
1906 addReply(c,shared.err);
1907 }
1908 }
1909
1910 static void shutdownCommand(redisClient *c) {
1911 redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
1912 if (saveDb(server.dbfilename) == REDIS_OK) {
1913 if (server.daemonize) {
1914 unlink(server.pidfile);
1915 }
1916 redisLog(REDIS_WARNING,"Server exit now, bye bye...");
1917 exit(1);
1918 } else {
1919 redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
1920 addReplySds(c,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
1921 }
1922 }
1923
1924 static void renameGenericCommand(redisClient *c, int nx) {
1925 dictEntry *de;
1926 robj *o;
1927
1928 /* To use the same key as src and dst is probably an error */
1929 if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) {
1930 if (nx)
1931 addReply(c,shared.minus3);
1932 else
1933 addReplySds(c,sdsnew("-ERR src and dest key are the same\r\n"));
1934 return;
1935 }
1936
1937 de = dictFind(c->dict,c->argv[1]);
1938 if (de == NULL) {
1939 if (nx)
1940 addReply(c,shared.minus1);
1941 else
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.zero);
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.one : 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.minus4);
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.minus3);
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.zero);
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.zero);
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.one);
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.zero);
2068 return;
2069 } else {
2070 robj *o = dictGetEntryVal(de);
2071 if (o->type != REDIS_LIST) {
2072 addReply(c,shared.minus2);
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.nil);
2087 } else {
2088 robj *o = dictGetEntryVal(de);
2089
2090 if (o->type != REDIS_LIST) {
2091 addReply(c,shared.wrongtypeerrbulk);
2092 } else {
2093 list *list = o->ptr;
2094 listNode *ln;
2095
2096 ln = listIndex(list, index);
2097 if (ln == NULL) {
2098 addReply(c,shared.nil);
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 addReplySds(c,sdsnew("-ERR index out of range\r\n"));
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.nil);
2147 } else {
2148 robj *o = dictGetEntryVal(de);
2149
2150 if (o->type != REDIS_LIST) {
2151 addReply(c,shared.wrongtypeerrbulk);
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.nil);
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.nil);
2191 } else {
2192 robj *o = dictGetEntryVal(de);
2193
2194 if (o->type != REDIS_LIST) {
2195 addReply(c,shared.wrongtypeerrbulk);
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.zero);
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.minus1);
2289 } else {
2290 robj *o = dictGetEntryVal(de);
2291
2292 if (o->type != REDIS_LIST) {
2293 addReply(c,shared.minus2);
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.minus2);
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.one);
2344 } else {
2345 addReply(c,shared.zero);
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.zero);
2355 } else {
2356 robj *set;
2357
2358 set = dictGetEntryVal(de);
2359 if (set->type != REDIS_SET) {
2360 addReply(c,shared.minus2);
2361 return;
2362 }
2363 if (dictDelete(set->ptr,c->argv[2]) == DICT_OK) {
2364 server.dirty++;
2365 addReply(c,shared.one);
2366 } else {
2367 addReply(c,shared.zero);
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.zero);
2378 } else {
2379 robj *set;
2380
2381 set = dictGetEntryVal(de);
2382 if (set->type != REDIS_SET) {
2383 addReply(c,shared.minus2);
2384 return;
2385 }
2386 if (dictFind(set->ptr,c->argv[2]))
2387 addReply(c,shared.one);
2388 else
2389 addReply(c,shared.zero);
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.zero);
2400 return;
2401 } else {
2402 robj *o = dictGetEntryVal(de);
2403 if (o->type != REDIS_SET) {
2404 addReply(c,shared.minus2);
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,dstkey ? shared.nokeyerr : shared.nil);
2435 return;
2436 }
2437 setobj = dictGetEntryVal(de);
2438 if (setobj->type != REDIS_SET) {
2439 zfree(dv);
2440 addReply(c,dstkey ? shared.wrongtypeerr : shared.wrongtypeerrbulk);
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.nokeyerrbulk);
2625 return;
2626 }
2627 sortval = dictGetEntryVal(de);
2628 if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST) {
2629 addReply(c,shared.wrongtypeerrbulk);
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.syntaxerrbulk);
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.minus1);
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 redisLog(REDIS_NOTICE,"Slave ask for syncronization");
2923 if (flushClientOutput(c) == REDIS_ERR || saveDb(server.dbfilename) != REDIS_OK)
2924 goto closeconn;
2925
2926 fd = open(server.dbfilename, O_RDONLY);
2927 if (fd == -1 || fstat(fd,&sb) == -1) goto closeconn;
2928 len = sb.st_size;
2929
2930 snprintf(sizebuf,32,"%d\r\n",len);
2931 if (syncWrite(c->fd,sizebuf,strlen(sizebuf),5) == -1) goto closeconn;
2932 while(len) {
2933 char buf[1024];
2934 int nread;
2935
2936 if (time(NULL)-start > REDIS_MAX_SYNC_TIME) goto closeconn;
2937 nread = read(fd,buf,1024);
2938 if (nread == -1) goto closeconn;
2939 len -= nread;
2940 if (syncWrite(c->fd,buf,nread,5) == -1) goto closeconn;
2941 }
2942 if (syncWrite(c->fd,"\r\n",2,5) == -1) goto closeconn;
2943 close(fd);
2944 c->flags |= REDIS_SLAVE;
2945 c->slaveseldb = 0;
2946 if (!listAddNodeTail(server.slaves,c)) oom("listAddNodeTail");
2947 redisLog(REDIS_NOTICE,"Syncronization with slave succeeded");
2948 return;
2949
2950 closeconn:
2951 if (fd != -1) close(fd);
2952 c->flags |= REDIS_CLOSE;
2953 redisLog(REDIS_WARNING,"Syncronization with slave failed");
2954 return;
2955 }
2956
2957 static int syncWithMaster(void) {
2958 char buf[1024], tmpfile[256];
2959 int dumpsize;
2960 int fd = anetTcpConnect(NULL,server.masterhost,server.masterport);
2961 int dfd;
2962
2963 if (fd == -1) {
2964 redisLog(REDIS_WARNING,"Unable to connect to MASTER: %s",
2965 strerror(errno));
2966 return REDIS_ERR;
2967 }
2968 /* Issue the SYNC command */
2969 if (syncWrite(fd,"SYNC \r\n",7,5) == -1) {
2970 close(fd);
2971 redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
2972 strerror(errno));
2973 return REDIS_ERR;
2974 }
2975 /* Read the bulk write count */
2976 if (syncReadLine(fd,buf,1024,5) == -1) {
2977 close(fd);
2978 redisLog(REDIS_WARNING,"I/O error reading bulk count from MASTER: %s",
2979 strerror(errno));
2980 return REDIS_ERR;
2981 }
2982 dumpsize = atoi(buf);
2983 redisLog(REDIS_NOTICE,"Receiving %d bytes data dump from MASTER",dumpsize);
2984 /* Read the bulk write data on a temp file */
2985 snprintf(tmpfile,256,"temp-%d.%ld.rdb",(int)time(NULL),(long int)random());
2986 dfd = open(tmpfile,O_CREAT|O_WRONLY,0644);
2987 if (dfd == -1) {
2988 close(fd);
2989 redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
2990 return REDIS_ERR;
2991 }
2992 while(dumpsize) {
2993 int nread, nwritten;
2994
2995 nread = read(fd,buf,(dumpsize < 1024)?dumpsize:1024);
2996 if (nread == -1) {
2997 redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
2998 strerror(errno));
2999 close(fd);
3000 close(dfd);
3001 return REDIS_ERR;
3002 }
3003 nwritten = write(dfd,buf,nread);
3004 if (nwritten == -1) {
3005 redisLog(REDIS_WARNING,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
3006 close(fd);
3007 close(dfd);
3008 return REDIS_ERR;
3009 }
3010 dumpsize -= nread;
3011 }
3012 close(dfd);
3013 if (rename(tmpfile,server.dbfilename) == -1) {
3014 redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
3015 unlink(tmpfile);
3016 close(fd);
3017 return REDIS_ERR;
3018 }
3019 emptyDb();
3020 if (loadDb(server.dbfilename) != REDIS_OK) {
3021 redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
3022 close(fd);
3023 return REDIS_ERR;
3024 }
3025 server.master = createClient(fd);
3026 server.master->flags |= REDIS_MASTER;
3027 server.replstate = REDIS_REPL_CONNECTED;
3028 return REDIS_OK;
3029 }
3030
3031 static void monitorCommand(redisClient *c) {
3032 c->flags |= (REDIS_SLAVE|REDIS_MONITOR);
3033 c->slaveseldb = 0;
3034 if (!listAddNodeTail(server.monitors,c)) oom("listAddNodeTail");
3035 addReply(c,shared.ok);
3036 }
3037
3038 /* =================================== Main! ================================ */
3039
3040 static void daemonize(void) {
3041 int fd;
3042 FILE *fp;
3043
3044 if (fork() != 0) exit(0); /* parent exits */
3045 setsid(); /* create a new session */
3046
3047 /* Every output goes to /dev/null. If Redis is daemonized but
3048 * the 'logfile' is set to 'stdout' in the configuration file
3049 * it will not log at all. */
3050 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
3051 dup2(fd, STDIN_FILENO);
3052 dup2(fd, STDOUT_FILENO);
3053 dup2(fd, STDERR_FILENO);
3054 if (fd > STDERR_FILENO) close(fd);
3055 }
3056 /* Try to write the pid file */
3057 fp = fopen(server.pidfile,"w");
3058 if (fp) {
3059 fprintf(fp,"%d\n",getpid());
3060 fclose(fp);
3061 }
3062 }
3063
3064 int main(int argc, char **argv) {
3065 initServerConfig();
3066 if (argc == 2) {
3067 ResetServerSaveParams();
3068 loadServerConfig(argv[1]);
3069 } else if (argc > 2) {
3070 fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
3071 exit(1);
3072 }
3073 initServer();
3074 if (server.daemonize) daemonize();
3075 redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
3076 if (loadDb(server.dbfilename) == REDIS_OK)
3077 redisLog(REDIS_NOTICE,"DB loaded from disk");
3078 if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,
3079 acceptHandler, NULL, NULL) == AE_ERR) oom("creating file event");
3080 redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
3081 aeMain(server.el);
3082 aeDeleteEventLoop(server.el);
3083 return 0;
3084 }