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