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