]> git.saurik.com Git - redis.git/blame - redis.c
Python lib updated
[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
16edf32d 30#define REDIS_VERSION "0.101"
23d4709d 31
32#include "fmacros.h"
ed9b544e 33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <time.h>
38#include <unistd.h>
39#include <signal.h>
40#include <sys/wait.h>
41#include <errno.h>
42#include <assert.h>
43#include <ctype.h>
44#include <stdarg.h>
45#include <inttypes.h>
46#include <arpa/inet.h>
47#include <sys/stat.h>
48#include <fcntl.h>
49#include <sys/time.h>
50#include <sys/resource.h>
f78fd11b 51#include <limits.h>
ed9b544e 52
53#include "ae.h" /* Event driven programming library */
54#include "sds.h" /* Dynamic safe strings */
55#include "anet.h" /* Networking the easy way */
56#include "dict.h" /* Hash tables */
57#include "adlist.h" /* Linked lists */
58#include "zmalloc.h" /* total memory usage aware version of malloc/free */
5f5b9840 59#include "lzf.h" /* LZF compression library */
60#include "pqsort.h" /* Partial qsort for SORT+LIMIT */
ed9b544e 61
62/* Error codes */
63#define REDIS_OK 0
64#define REDIS_ERR -1
65
66/* Static server configuration */
67#define REDIS_SERVERPORT 6379 /* TCP port */
68#define REDIS_MAXIDLETIME (60*5) /* default client timeout */
6208b3a7 69#define REDIS_IOBUF_LEN 1024
ed9b544e 70#define REDIS_LOADBUF_LEN 1024
93ea3759 71#define REDIS_STATIC_ARGS 4
ed9b544e 72#define REDIS_DEFAULT_DBNUM 16
73#define REDIS_CONFIGLINE_MAX 1024
74#define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
75#define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
94754ccc 76#define REDIS_EXPIRELOOKUPS_PER_CRON 100 /* try to expire 100 keys/second */
ed9b544e 77
78/* Hash table parameters */
79#define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
80#define REDIS_HT_MINSLOTS 16384 /* Never resize the HT under this */
81
82/* Command flags */
3fd78bcd 83#define REDIS_CMD_BULK 1 /* Bulk write command */
84#define REDIS_CMD_INLINE 2 /* Inline command */
85/* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
86 this flags will return an error when the 'maxmemory' option is set in the
87 config file and the server is using more than maxmemory bytes of memory.
88 In short this commands are denied on low memory conditions. */
89#define REDIS_CMD_DENYOOM 4
ed9b544e 90
91/* Object types */
92#define REDIS_STRING 0
93#define REDIS_LIST 1
94#define REDIS_SET 2
95#define REDIS_HASH 3
f78fd11b 96
97/* Object types only used for dumping to disk */
bb32ede5 98#define REDIS_EXPIRETIME 253
ed9b544e 99#define REDIS_SELECTDB 254
100#define REDIS_EOF 255
101
f78fd11b 102/* Defines related to the dump file format. To store 32 bits lengths for short
103 * keys requires a lot of space, so we check the most significant 2 bits of
104 * the first byte to interpreter the length:
105 *
106 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
107 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
108 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
a4d1ba9a 109 * 11|000000 this means: specially encoded object will follow. The six bits
110 * number specify the kind of object that follows.
111 * See the REDIS_RDB_ENC_* defines.
f78fd11b 112 *
10c43610 113 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
114 * values, will fit inside. */
f78fd11b 115#define REDIS_RDB_6BITLEN 0
116#define REDIS_RDB_14BITLEN 1
117#define REDIS_RDB_32BITLEN 2
17be1a4a 118#define REDIS_RDB_ENCVAL 3
f78fd11b 119#define REDIS_RDB_LENERR UINT_MAX
120
a4d1ba9a 121/* When a length of a string object stored on disk has the first two bits
122 * set, the remaining two bits specify a special encoding for the object
123 * accordingly to the following defines: */
124#define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
125#define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
126#define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
774e3047 127#define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
a4d1ba9a 128
ed9b544e 129/* Client flags */
130#define REDIS_CLOSE 1 /* This client connection should be closed ASAP */
131#define REDIS_SLAVE 2 /* This client is a slave server */
132#define REDIS_MASTER 4 /* This client is a master server */
87eca727 133#define REDIS_MONITOR 8 /* This client is a slave monitor, see MONITOR */
ed9b544e 134
40d224a9 135/* Slave replication state - slave side */
ed9b544e 136#define REDIS_REPL_NONE 0 /* No active replication */
137#define REDIS_REPL_CONNECT 1 /* Must connect to master */
138#define REDIS_REPL_CONNECTED 2 /* Connected to master */
139
40d224a9 140/* Slave replication state - from the point of view of master
141 * Note that in SEND_BULK and ONLINE state the slave receives new updates
142 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
143 * to start the next background saving in order to send updates to it. */
144#define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
145#define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
146#define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
147#define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
148
ed9b544e 149/* List related stuff */
150#define REDIS_HEAD 0
151#define REDIS_TAIL 1
152
153/* Sort operations */
154#define REDIS_SORT_GET 0
155#define REDIS_SORT_DEL 1
156#define REDIS_SORT_INCR 2
157#define REDIS_SORT_DECR 3
158#define REDIS_SORT_ASC 4
159#define REDIS_SORT_DESC 5
160#define REDIS_SORTKEY_MAX 1024
161
162/* Log levels */
163#define REDIS_DEBUG 0
164#define REDIS_NOTICE 1
165#define REDIS_WARNING 2
166
167/* Anti-warning macro... */
168#define REDIS_NOTUSED(V) ((void) V)
169
170/*================================= Data types ============================== */
171
172/* A redis object, that is a type able to hold a string / list / set */
173typedef struct redisObject {
ed9b544e 174 void *ptr;
5a6e8b1d 175 int type;
ed9b544e 176 int refcount;
177} robj;
178
3305306f 179typedef struct redisDb {
180 dict *dict;
181 dict *expires;
182 int id;
183} redisDb;
184
ed9b544e 185/* With multiplexing we need to take per-clinet state.
186 * Clients are taken in a liked list. */
187typedef struct redisClient {
188 int fd;
3305306f 189 redisDb *db;
ed9b544e 190 int dictid;
191 sds querybuf;
93ea3759 192 robj **argv;
ed9b544e 193 int argc;
40d224a9 194 int bulklen; /* bulk read len. -1 if not in bulk read mode */
ed9b544e 195 list *reply;
196 int sentlen;
197 time_t lastinteraction; /* time of the last interaction, used for timeout */
40d224a9 198 int flags; /* REDIS_CLOSE | REDIS_SLAVE | REDIS_MONITOR */
199 int slaveseldb; /* slave selected db, if this client is a slave */
200 int authenticated; /* when requirepass is non-NULL */
201 int replstate; /* replication state if this is a slave */
202 int repldbfd; /* replication DB file descriptor */
6208b3a7 203 long repldboff; /* replication DB file offset */
40d224a9 204 off_t repldbsize; /* replication DB file size */
ed9b544e 205} redisClient;
206
207struct saveparam {
208 time_t seconds;
209 int changes;
210};
211
212/* Global server state structure */
213struct redisServer {
214 int port;
215 int fd;
3305306f 216 redisDb *db;
10c43610 217 dict *sharingpool;
218 unsigned int sharingpoolsize;
ed9b544e 219 long long dirty; /* changes to DB from the last save */
220 list *clients;
87eca727 221 list *slaves, *monitors;
ed9b544e 222 char neterr[ANET_ERR_LEN];
223 aeEventLoop *el;
224 int cronloops; /* number of times the cron function run */
225 list *objfreelist; /* A list of freed objects to avoid malloc() */
226 time_t lastsave; /* Unix time of last save succeeede */
5fba9f71 227 size_t usedmemory; /* Used memory in megabytes */
ed9b544e 228 /* Fields used only for stats */
229 time_t stat_starttime; /* server start time */
230 long long stat_numcommands; /* number of processed commands */
231 long long stat_numconnections; /* number of connections received */
232 /* Configuration */
233 int verbosity;
234 int glueoutputbuf;
235 int maxidletime;
236 int dbnum;
237 int daemonize;
ed329fcf 238 char *pidfile;
ed9b544e 239 int bgsaveinprogress;
240 struct saveparam *saveparams;
241 int saveparamslen;
242 char *logfile;
243 char *bindaddr;
244 char *dbfilename;
abcb223e 245 char *requirepass;
10c43610 246 int shareobjects;
ed9b544e 247 /* Replication related */
248 int isslave;
249 char *masterhost;
250 int masterport;
40d224a9 251 redisClient *master; /* client that is master for this slave */
ed9b544e 252 int replstate;
285add55 253 unsigned int maxclients;
3fd78bcd 254 unsigned int maxmemory;
ed9b544e 255 /* Sort parameters - qsort_r() is only available under BSD so we
256 * have to take this state global, in order to pass it to sortCompare() */
257 int sort_desc;
258 int sort_alpha;
259 int sort_bypattern;
260};
261
262typedef void redisCommandProc(redisClient *c);
263struct redisCommand {
264 char *name;
265 redisCommandProc *proc;
266 int arity;
267 int flags;
268};
269
270typedef struct _redisSortObject {
271 robj *obj;
272 union {
273 double score;
274 robj *cmpobj;
275 } u;
276} redisSortObject;
277
278typedef struct _redisSortOperation {
279 int type;
280 robj *pattern;
281} redisSortOperation;
282
283struct sharedObjectsStruct {
c937aa89 284 robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *pong, *space,
7b45bfb2 285 *colon, *nullbulk, *nullmultibulk,
c937aa89 286 *emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr,
287 *outofrangeerr, *plus,
ed9b544e 288 *select0, *select1, *select2, *select3, *select4,
289 *select5, *select6, *select7, *select8, *select9;
290} shared;
291
292/*================================ Prototypes =============================== */
293
294static void freeStringObject(robj *o);
295static void freeListObject(robj *o);
296static void freeSetObject(robj *o);
297static void decrRefCount(void *o);
298static robj *createObject(int type, void *ptr);
299static void freeClient(redisClient *c);
f78fd11b 300static int rdbLoad(char *filename);
ed9b544e 301static void addReply(redisClient *c, robj *obj);
302static void addReplySds(redisClient *c, sds s);
303static void incrRefCount(robj *o);
f78fd11b 304static int rdbSaveBackground(char *filename);
ed9b544e 305static robj *createStringObject(char *ptr, size_t len);
87eca727 306static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc);
ed9b544e 307static int syncWithMaster(void);
10c43610 308static robj *tryObjectSharing(robj *o);
3305306f 309static int removeExpire(redisDb *db, robj *key);
310static int expireIfNeeded(redisDb *db, robj *key);
311static int deleteIfVolatile(redisDb *db, robj *key);
94754ccc 312static int deleteKey(redisDb *db, robj *key);
bb32ede5 313static time_t getExpire(redisDb *db, robj *key);
314static int setExpire(redisDb *db, robj *key, time_t when);
6208b3a7 315static void updateSalvesWaitingBgsave(int bgsaveerr);
3fd78bcd 316static void freeMemoryIfNeeded(void);
ed9b544e 317
abcb223e 318static void authCommand(redisClient *c);
ed9b544e 319static void pingCommand(redisClient *c);
320static void echoCommand(redisClient *c);
321static void setCommand(redisClient *c);
322static void setnxCommand(redisClient *c);
323static void getCommand(redisClient *c);
324static void delCommand(redisClient *c);
325static void existsCommand(redisClient *c);
326static void incrCommand(redisClient *c);
327static void decrCommand(redisClient *c);
328static void incrbyCommand(redisClient *c);
329static void decrbyCommand(redisClient *c);
330static void selectCommand(redisClient *c);
331static void randomkeyCommand(redisClient *c);
332static void keysCommand(redisClient *c);
333static void dbsizeCommand(redisClient *c);
334static void lastsaveCommand(redisClient *c);
335static void saveCommand(redisClient *c);
336static void bgsaveCommand(redisClient *c);
337static void shutdownCommand(redisClient *c);
338static void moveCommand(redisClient *c);
339static void renameCommand(redisClient *c);
340static void renamenxCommand(redisClient *c);
341static void lpushCommand(redisClient *c);
342static void rpushCommand(redisClient *c);
343static void lpopCommand(redisClient *c);
344static void rpopCommand(redisClient *c);
345static void llenCommand(redisClient *c);
346static void lindexCommand(redisClient *c);
347static void lrangeCommand(redisClient *c);
348static void ltrimCommand(redisClient *c);
349static void typeCommand(redisClient *c);
350static void lsetCommand(redisClient *c);
351static void saddCommand(redisClient *c);
352static void sremCommand(redisClient *c);
a4460ef4 353static void smoveCommand(redisClient *c);
ed9b544e 354static void sismemberCommand(redisClient *c);
355static void scardCommand(redisClient *c);
356static void sinterCommand(redisClient *c);
357static void sinterstoreCommand(redisClient *c);
40d224a9 358static void sunionCommand(redisClient *c);
359static void sunionstoreCommand(redisClient *c);
f4f56e1d 360static void sdiffCommand(redisClient *c);
361static void sdiffstoreCommand(redisClient *c);
ed9b544e 362static void syncCommand(redisClient *c);
363static void flushdbCommand(redisClient *c);
364static void flushallCommand(redisClient *c);
365static void sortCommand(redisClient *c);
366static void lremCommand(redisClient *c);
367static void infoCommand(redisClient *c);
70003d28 368static void mgetCommand(redisClient *c);
87eca727 369static void monitorCommand(redisClient *c);
3305306f 370static void expireCommand(redisClient *c);
a431eb74 371static void getSetCommand(redisClient *c);
fd88489a 372static void ttlCommand(redisClient *c);
321b0e13 373static void slaveofCommand(redisClient *c);
ed9b544e 374
375/*================================= Globals ================================= */
376
377/* Global vars */
378static struct redisServer server; /* server global state */
379static struct redisCommand cmdTable[] = {
380 {"get",getCommand,2,REDIS_CMD_INLINE},
3fd78bcd 381 {"set",setCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
382 {"setnx",setnxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
5109cdff 383 {"del",delCommand,-2,REDIS_CMD_INLINE},
ed9b544e 384 {"exists",existsCommand,2,REDIS_CMD_INLINE},
3fd78bcd 385 {"incr",incrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
386 {"decr",decrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
70003d28 387 {"mget",mgetCommand,-2,REDIS_CMD_INLINE},
3fd78bcd 388 {"rpush",rpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
389 {"lpush",lpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 390 {"rpop",rpopCommand,2,REDIS_CMD_INLINE},
391 {"lpop",lpopCommand,2,REDIS_CMD_INLINE},
392 {"llen",llenCommand,2,REDIS_CMD_INLINE},
393 {"lindex",lindexCommand,3,REDIS_CMD_INLINE},
3fd78bcd 394 {"lset",lsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 395 {"lrange",lrangeCommand,4,REDIS_CMD_INLINE},
396 {"ltrim",ltrimCommand,4,REDIS_CMD_INLINE},
397 {"lrem",lremCommand,4,REDIS_CMD_BULK},
3fd78bcd 398 {"sadd",saddCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 399 {"srem",sremCommand,3,REDIS_CMD_BULK},
a4460ef4 400 {"smove",smoveCommand,4,REDIS_CMD_BULK},
ed9b544e 401 {"sismember",sismemberCommand,3,REDIS_CMD_BULK},
402 {"scard",scardCommand,2,REDIS_CMD_INLINE},
3fd78bcd 403 {"sinter",sinterCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
404 {"sinterstore",sinterstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
405 {"sunion",sunionCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
406 {"sunionstore",sunionstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
407 {"sdiff",sdiffCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
408 {"sdiffstore",sdiffstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
ed9b544e 409 {"smembers",sinterCommand,2,REDIS_CMD_INLINE},
3fd78bcd 410 {"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
411 {"decrby",decrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
412 {"getset",getSetCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 413 {"randomkey",randomkeyCommand,1,REDIS_CMD_INLINE},
414 {"select",selectCommand,2,REDIS_CMD_INLINE},
415 {"move",moveCommand,3,REDIS_CMD_INLINE},
416 {"rename",renameCommand,3,REDIS_CMD_INLINE},
417 {"renamenx",renamenxCommand,3,REDIS_CMD_INLINE},
321b0e13 418 {"expire",expireCommand,3,REDIS_CMD_INLINE},
ed9b544e 419 {"keys",keysCommand,2,REDIS_CMD_INLINE},
420 {"dbsize",dbsizeCommand,1,REDIS_CMD_INLINE},
abcb223e 421 {"auth",authCommand,2,REDIS_CMD_INLINE},
ed9b544e 422 {"ping",pingCommand,1,REDIS_CMD_INLINE},
423 {"echo",echoCommand,2,REDIS_CMD_BULK},
424 {"save",saveCommand,1,REDIS_CMD_INLINE},
425 {"bgsave",bgsaveCommand,1,REDIS_CMD_INLINE},
426 {"shutdown",shutdownCommand,1,REDIS_CMD_INLINE},
427 {"lastsave",lastsaveCommand,1,REDIS_CMD_INLINE},
428 {"type",typeCommand,2,REDIS_CMD_INLINE},
429 {"sync",syncCommand,1,REDIS_CMD_INLINE},
430 {"flushdb",flushdbCommand,1,REDIS_CMD_INLINE},
431 {"flushall",flushallCommand,1,REDIS_CMD_INLINE},
3fd78bcd 432 {"sort",sortCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
ed9b544e 433 {"info",infoCommand,1,REDIS_CMD_INLINE},
87eca727 434 {"monitor",monitorCommand,1,REDIS_CMD_INLINE},
fd88489a 435 {"ttl",ttlCommand,2,REDIS_CMD_INLINE},
321b0e13 436 {"slaveof",slaveofCommand,3,REDIS_CMD_INLINE},
ed9b544e 437 {NULL,NULL,0,0}
438};
439
440/*============================ Utility functions ============================ */
441
442/* Glob-style pattern matching. */
443int stringmatchlen(const char *pattern, int patternLen,
444 const char *string, int stringLen, int nocase)
445{
446 while(patternLen) {
447 switch(pattern[0]) {
448 case '*':
449 while (pattern[1] == '*') {
450 pattern++;
451 patternLen--;
452 }
453 if (patternLen == 1)
454 return 1; /* match */
455 while(stringLen) {
456 if (stringmatchlen(pattern+1, patternLen-1,
457 string, stringLen, nocase))
458 return 1; /* match */
459 string++;
460 stringLen--;
461 }
462 return 0; /* no match */
463 break;
464 case '?':
465 if (stringLen == 0)
466 return 0; /* no match */
467 string++;
468 stringLen--;
469 break;
470 case '[':
471 {
472 int not, match;
473
474 pattern++;
475 patternLen--;
476 not = pattern[0] == '^';
477 if (not) {
478 pattern++;
479 patternLen--;
480 }
481 match = 0;
482 while(1) {
483 if (pattern[0] == '\\') {
484 pattern++;
485 patternLen--;
486 if (pattern[0] == string[0])
487 match = 1;
488 } else if (pattern[0] == ']') {
489 break;
490 } else if (patternLen == 0) {
491 pattern--;
492 patternLen++;
493 break;
494 } else if (pattern[1] == '-' && patternLen >= 3) {
495 int start = pattern[0];
496 int end = pattern[2];
497 int c = string[0];
498 if (start > end) {
499 int t = start;
500 start = end;
501 end = t;
502 }
503 if (nocase) {
504 start = tolower(start);
505 end = tolower(end);
506 c = tolower(c);
507 }
508 pattern += 2;
509 patternLen -= 2;
510 if (c >= start && c <= end)
511 match = 1;
512 } else {
513 if (!nocase) {
514 if (pattern[0] == string[0])
515 match = 1;
516 } else {
517 if (tolower((int)pattern[0]) == tolower((int)string[0]))
518 match = 1;
519 }
520 }
521 pattern++;
522 patternLen--;
523 }
524 if (not)
525 match = !match;
526 if (!match)
527 return 0; /* no match */
528 string++;
529 stringLen--;
530 break;
531 }
532 case '\\':
533 if (patternLen >= 2) {
534 pattern++;
535 patternLen--;
536 }
537 /* fall through */
538 default:
539 if (!nocase) {
540 if (pattern[0] != string[0])
541 return 0; /* no match */
542 } else {
543 if (tolower((int)pattern[0]) != tolower((int)string[0]))
544 return 0; /* no match */
545 }
546 string++;
547 stringLen--;
548 break;
549 }
550 pattern++;
551 patternLen--;
552 if (stringLen == 0) {
553 while(*pattern == '*') {
554 pattern++;
555 patternLen--;
556 }
557 break;
558 }
559 }
560 if (patternLen == 0 && stringLen == 0)
561 return 1;
562 return 0;
563}
564
565void redisLog(int level, const char *fmt, ...)
566{
567 va_list ap;
568 FILE *fp;
569
570 fp = (server.logfile == NULL) ? stdout : fopen(server.logfile,"a");
571 if (!fp) return;
572
573 va_start(ap, fmt);
574 if (level >= server.verbosity) {
575 char *c = ".-*";
1904ecc1 576 char buf[64];
577 time_t now;
578
579 now = time(NULL);
580 strftime(buf,64,"%d %b %H:%M:%S",gmtime(&now));
581 fprintf(fp,"%s %c ",buf,c[level]);
ed9b544e 582 vfprintf(fp, fmt, ap);
583 fprintf(fp,"\n");
584 fflush(fp);
585 }
586 va_end(ap);
587
588 if (server.logfile) fclose(fp);
589}
590
591/*====================== Hash table type implementation ==================== */
592
593/* This is an hash table type that uses the SDS dynamic strings libary as
594 * keys and radis objects as values (objects can hold SDS strings,
595 * lists, sets). */
596
597static int sdsDictKeyCompare(void *privdata, const void *key1,
598 const void *key2)
599{
600 int l1,l2;
601 DICT_NOTUSED(privdata);
602
603 l1 = sdslen((sds)key1);
604 l2 = sdslen((sds)key2);
605 if (l1 != l2) return 0;
606 return memcmp(key1, key2, l1) == 0;
607}
608
609static void dictRedisObjectDestructor(void *privdata, void *val)
610{
611 DICT_NOTUSED(privdata);
612
613 decrRefCount(val);
614}
615
616static int dictSdsKeyCompare(void *privdata, const void *key1,
617 const void *key2)
618{
619 const robj *o1 = key1, *o2 = key2;
620 return sdsDictKeyCompare(privdata,o1->ptr,o2->ptr);
621}
622
623static unsigned int dictSdsHash(const void *key) {
624 const robj *o = key;
625 return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
626}
627
628static dictType setDictType = {
629 dictSdsHash, /* hash function */
630 NULL, /* key dup */
631 NULL, /* val dup */
632 dictSdsKeyCompare, /* key compare */
633 dictRedisObjectDestructor, /* key destructor */
634 NULL /* val destructor */
635};
636
637static dictType hashDictType = {
638 dictSdsHash, /* hash function */
639 NULL, /* key dup */
640 NULL, /* val dup */
641 dictSdsKeyCompare, /* key compare */
642 dictRedisObjectDestructor, /* key destructor */
643 dictRedisObjectDestructor /* val destructor */
644};
645
646/* ========================= Random utility functions ======================= */
647
648/* Redis generally does not try to recover from out of memory conditions
649 * when allocating objects or strings, it is not clear if it will be possible
650 * to report this condition to the client since the networking layer itself
651 * is based on heap allocation for send buffers, so we simply abort.
652 * At least the code will be simpler to read... */
653static void oom(const char *msg) {
654 fprintf(stderr, "%s: Out of memory\n",msg);
655 fflush(stderr);
656 sleep(1);
657 abort();
658}
659
660/* ====================== Redis server networking stuff ===================== */
661void closeTimedoutClients(void) {
662 redisClient *c;
ed9b544e 663 listNode *ln;
664 time_t now = time(NULL);
665
6208b3a7 666 listRewind(server.clients);
667 while ((ln = listYield(server.clients)) != NULL) {
ed9b544e 668 c = listNodeValue(ln);
669 if (!(c->flags & REDIS_SLAVE) && /* no timeout for slaves */
c7cf2ec9 670 !(c->flags & REDIS_MASTER) && /* no timeout for masters */
ed9b544e 671 (now - c->lastinteraction > server.maxidletime)) {
672 redisLog(REDIS_DEBUG,"Closing idle client");
673 freeClient(c);
674 }
675 }
ed9b544e 676}
677
0bc03378 678/* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
679 * we resize the hash table to save memory */
680void tryResizeHashTables(void) {
681 int j;
682
683 for (j = 0; j < server.dbnum; j++) {
684 long long size, used;
685
686 size = dictSlots(server.db[j].dict);
687 used = dictSize(server.db[j].dict);
688 if (size && used && size > REDIS_HT_MINSLOTS &&
689 (used*100/size < REDIS_HT_MINFILL)) {
690 redisLog(REDIS_NOTICE,"The hash table %d is too sparse, resize it...",j);
691 dictResize(server.db[j].dict);
692 redisLog(REDIS_NOTICE,"Hash table %d resized.",j);
693 }
694 }
695}
696
ed9b544e 697int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
94754ccc 698 int j, loops = server.cronloops++;
ed9b544e 699 REDIS_NOTUSED(eventLoop);
700 REDIS_NOTUSED(id);
701 REDIS_NOTUSED(clientData);
702
703 /* Update the global state with the amount of used memory */
704 server.usedmemory = zmalloc_used_memory();
705
0bc03378 706 /* Show some info about non-empty databases */
ed9b544e 707 for (j = 0; j < server.dbnum; j++) {
dec423d9 708 long long size, used, vkeys;
94754ccc 709
3305306f 710 size = dictSlots(server.db[j].dict);
711 used = dictSize(server.db[j].dict);
94754ccc 712 vkeys = dictSize(server.db[j].expires);
ed9b544e 713 if (!(loops % 5) && used > 0) {
94754ccc 714 redisLog(REDIS_DEBUG,"DB %d: %d keys (%d volatile) in %d slots HT.",j,used,vkeys,size);
a4d1ba9a 715 /* dictPrintStats(server.dict); */
ed9b544e 716 }
ed9b544e 717 }
718
0bc03378 719 /* We don't want to resize the hash tables while a bacground saving
720 * is in progress: the saving child is created using fork() that is
721 * implemented with a copy-on-write semantic in most modern systems, so
722 * if we resize the HT while there is the saving child at work actually
723 * a lot of memory movements in the parent will cause a lot of pages
724 * copied. */
725 if (!server.bgsaveinprogress) tryResizeHashTables();
726
ed9b544e 727 /* Show information about connected clients */
728 if (!(loops % 5)) {
5fba9f71 729 redisLog(REDIS_DEBUG,"%d clients connected (%d slaves), %zu bytes in use",
ed9b544e 730 listLength(server.clients)-listLength(server.slaves),
731 listLength(server.slaves),
10c43610 732 server.usedmemory,
3305306f 733 dictSize(server.sharingpool));
ed9b544e 734 }
735
736 /* Close connections of timedout clients */
0150db36 737 if (server.maxidletime && !(loops % 10))
ed9b544e 738 closeTimedoutClients();
739
740 /* Check if a background saving in progress terminated */
741 if (server.bgsaveinprogress) {
742 int statloc;
6208b3a7 743 /* XXX: TODO handle the case of the saving child killed */
ed9b544e 744 if (wait4(-1,&statloc,WNOHANG,NULL)) {
745 int exitcode = WEXITSTATUS(statloc);
746 if (exitcode == 0) {
747 redisLog(REDIS_NOTICE,
748 "Background saving terminated with success");
749 server.dirty = 0;
750 server.lastsave = time(NULL);
751 } else {
752 redisLog(REDIS_WARNING,
753 "Background saving error");
754 }
755 server.bgsaveinprogress = 0;
6208b3a7 756 updateSalvesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR);
ed9b544e 757 }
758 } else {
759 /* If there is not a background saving in progress check if
760 * we have to save now */
761 time_t now = time(NULL);
762 for (j = 0; j < server.saveparamslen; j++) {
763 struct saveparam *sp = server.saveparams+j;
764
765 if (server.dirty >= sp->changes &&
766 now-server.lastsave > sp->seconds) {
767 redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...",
768 sp->changes, sp->seconds);
f78fd11b 769 rdbSaveBackground(server.dbfilename);
ed9b544e 770 break;
771 }
772 }
773 }
94754ccc 774
775 /* Try to expire a few timed out keys */
776 for (j = 0; j < server.dbnum; j++) {
777 redisDb *db = server.db+j;
778 int num = dictSize(db->expires);
779
780 if (num) {
781 time_t now = time(NULL);
782
783 if (num > REDIS_EXPIRELOOKUPS_PER_CRON)
784 num = REDIS_EXPIRELOOKUPS_PER_CRON;
785 while (num--) {
786 dictEntry *de;
787 time_t t;
788
789 if ((de = dictGetRandomKey(db->expires)) == NULL) break;
790 t = (time_t) dictGetEntryVal(de);
791 if (now > t) {
792 deleteKey(db,dictGetEntryKey(de));
793 }
794 }
795 }
796 }
797
ed9b544e 798 /* Check if we should connect to a MASTER */
799 if (server.replstate == REDIS_REPL_CONNECT) {
800 redisLog(REDIS_NOTICE,"Connecting to MASTER...");
801 if (syncWithMaster() == REDIS_OK) {
802 redisLog(REDIS_NOTICE,"MASTER <-> SLAVE sync succeeded");
803 }
804 }
805 return 1000;
806}
807
808static void createSharedObjects(void) {
809 shared.crlf = createObject(REDIS_STRING,sdsnew("\r\n"));
810 shared.ok = createObject(REDIS_STRING,sdsnew("+OK\r\n"));
811 shared.err = createObject(REDIS_STRING,sdsnew("-ERR\r\n"));
c937aa89 812 shared.emptybulk = createObject(REDIS_STRING,sdsnew("$0\r\n\r\n"));
813 shared.czero = createObject(REDIS_STRING,sdsnew(":0\r\n"));
814 shared.cone = createObject(REDIS_STRING,sdsnew(":1\r\n"));
815 shared.nullbulk = createObject(REDIS_STRING,sdsnew("$-1\r\n"));
816 shared.nullmultibulk = createObject(REDIS_STRING,sdsnew("*-1\r\n"));
817 shared.emptymultibulk = createObject(REDIS_STRING,sdsnew("*0\r\n"));
ed9b544e 818 /* no such key */
ed9b544e 819 shared.pong = createObject(REDIS_STRING,sdsnew("+PONG\r\n"));
820 shared.wrongtypeerr = createObject(REDIS_STRING,sdsnew(
821 "-ERR Operation against a key holding the wrong kind of value\r\n"));
ed9b544e 822 shared.nokeyerr = createObject(REDIS_STRING,sdsnew(
823 "-ERR no such key\r\n"));
ed9b544e 824 shared.syntaxerr = createObject(REDIS_STRING,sdsnew(
825 "-ERR syntax error\r\n"));
c937aa89 826 shared.sameobjecterr = createObject(REDIS_STRING,sdsnew(
827 "-ERR source and destination objects are the same\r\n"));
828 shared.outofrangeerr = createObject(REDIS_STRING,sdsnew(
829 "-ERR index out of range\r\n"));
ed9b544e 830 shared.space = createObject(REDIS_STRING,sdsnew(" "));
c937aa89 831 shared.colon = createObject(REDIS_STRING,sdsnew(":"));
832 shared.plus = createObject(REDIS_STRING,sdsnew("+"));
ed9b544e 833 shared.select0 = createStringObject("select 0\r\n",10);
834 shared.select1 = createStringObject("select 1\r\n",10);
835 shared.select2 = createStringObject("select 2\r\n",10);
836 shared.select3 = createStringObject("select 3\r\n",10);
837 shared.select4 = createStringObject("select 4\r\n",10);
838 shared.select5 = createStringObject("select 5\r\n",10);
839 shared.select6 = createStringObject("select 6\r\n",10);
840 shared.select7 = createStringObject("select 7\r\n",10);
841 shared.select8 = createStringObject("select 8\r\n",10);
842 shared.select9 = createStringObject("select 9\r\n",10);
843}
844
845static void appendServerSaveParams(time_t seconds, int changes) {
846 server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));
847 if (server.saveparams == NULL) oom("appendServerSaveParams");
848 server.saveparams[server.saveparamslen].seconds = seconds;
849 server.saveparams[server.saveparamslen].changes = changes;
850 server.saveparamslen++;
851}
852
853static void ResetServerSaveParams() {
854 zfree(server.saveparams);
855 server.saveparams = NULL;
856 server.saveparamslen = 0;
857}
858
859static void initServerConfig() {
860 server.dbnum = REDIS_DEFAULT_DBNUM;
861 server.port = REDIS_SERVERPORT;
862 server.verbosity = REDIS_DEBUG;
863 server.maxidletime = REDIS_MAXIDLETIME;
864 server.saveparams = NULL;
865 server.logfile = NULL; /* NULL = log on standard output */
866 server.bindaddr = NULL;
867 server.glueoutputbuf = 1;
868 server.daemonize = 0;
ed329fcf 869 server.pidfile = "/var/run/redis.pid";
ed9b544e 870 server.dbfilename = "dump.rdb";
abcb223e 871 server.requirepass = NULL;
10c43610 872 server.shareobjects = 0;
285add55 873 server.maxclients = 0;
3fd78bcd 874 server.maxmemory = 0;
ed9b544e 875 ResetServerSaveParams();
876
877 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
878 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
879 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
880 /* Replication related */
881 server.isslave = 0;
882 server.masterhost = NULL;
883 server.masterport = 6379;
884 server.master = NULL;
885 server.replstate = REDIS_REPL_NONE;
886}
887
888static void initServer() {
889 int j;
890
891 signal(SIGHUP, SIG_IGN);
892 signal(SIGPIPE, SIG_IGN);
893
894 server.clients = listCreate();
895 server.slaves = listCreate();
87eca727 896 server.monitors = listCreate();
ed9b544e 897 server.objfreelist = listCreate();
898 createSharedObjects();
899 server.el = aeCreateEventLoop();
3305306f 900 server.db = zmalloc(sizeof(redisDb)*server.dbnum);
10c43610 901 server.sharingpool = dictCreate(&setDictType,NULL);
902 server.sharingpoolsize = 1024;
3305306f 903 if (!server.db || !server.clients || !server.slaves || !server.monitors || !server.el || !server.objfreelist)
ed9b544e 904 oom("server initialization"); /* Fatal OOM */
905 server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr);
906 if (server.fd == -1) {
907 redisLog(REDIS_WARNING, "Opening TCP port: %s", server.neterr);
908 exit(1);
909 }
3305306f 910 for (j = 0; j < server.dbnum; j++) {
911 server.db[j].dict = dictCreate(&hashDictType,NULL);
912 server.db[j].expires = dictCreate(&setDictType,NULL);
913 server.db[j].id = j;
914 }
ed9b544e 915 server.cronloops = 0;
916 server.bgsaveinprogress = 0;
917 server.lastsave = time(NULL);
918 server.dirty = 0;
919 server.usedmemory = 0;
920 server.stat_numcommands = 0;
921 server.stat_numconnections = 0;
922 server.stat_starttime = time(NULL);
923 aeCreateTimeEvent(server.el, 1000, serverCron, NULL, NULL);
924}
925
926/* Empty the whole database */
ca37e9cd 927static long long emptyDb() {
ed9b544e 928 int j;
ca37e9cd 929 long long removed = 0;
ed9b544e 930
3305306f 931 for (j = 0; j < server.dbnum; j++) {
ca37e9cd 932 removed += dictSize(server.db[j].dict);
3305306f 933 dictEmpty(server.db[j].dict);
934 dictEmpty(server.db[j].expires);
935 }
ca37e9cd 936 return removed;
ed9b544e 937}
938
85dd2f3a 939static int yesnotoi(char *s) {
940 if (!strcasecmp(s,"yes")) return 1;
941 else if (!strcasecmp(s,"no")) return 0;
942 else return -1;
943}
944
ed9b544e 945/* I agree, this is a very rudimental way to load a configuration...
946 will improve later if the config gets more complex */
947static void loadServerConfig(char *filename) {
948 FILE *fp = fopen(filename,"r");
949 char buf[REDIS_CONFIGLINE_MAX+1], *err = NULL;
950 int linenum = 0;
951 sds line = NULL;
952
953 if (!fp) {
954 redisLog(REDIS_WARNING,"Fatal error, can't open config file");
955 exit(1);
956 }
957 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL) {
958 sds *argv;
959 int argc, j;
960
961 linenum++;
962 line = sdsnew(buf);
963 line = sdstrim(line," \t\r\n");
964
965 /* Skip comments and blank lines*/
966 if (line[0] == '#' || line[0] == '\0') {
967 sdsfree(line);
968 continue;
969 }
970
971 /* Split into arguments */
972 argv = sdssplitlen(line,sdslen(line)," ",1,&argc);
973 sdstolower(argv[0]);
974
975 /* Execute config directives */
bb0b03a3 976 if (!strcasecmp(argv[0],"timeout") && argc == 2) {
ed9b544e 977 server.maxidletime = atoi(argv[1]);
0150db36 978 if (server.maxidletime < 0) {
ed9b544e 979 err = "Invalid timeout value"; goto loaderr;
980 }
bb0b03a3 981 } else if (!strcasecmp(argv[0],"port") && argc == 2) {
ed9b544e 982 server.port = atoi(argv[1]);
983 if (server.port < 1 || server.port > 65535) {
984 err = "Invalid port"; goto loaderr;
985 }
bb0b03a3 986 } else if (!strcasecmp(argv[0],"bind") && argc == 2) {
ed9b544e 987 server.bindaddr = zstrdup(argv[1]);
bb0b03a3 988 } else if (!strcasecmp(argv[0],"save") && argc == 3) {
ed9b544e 989 int seconds = atoi(argv[1]);
990 int changes = atoi(argv[2]);
991 if (seconds < 1 || changes < 0) {
992 err = "Invalid save parameters"; goto loaderr;
993 }
994 appendServerSaveParams(seconds,changes);
bb0b03a3 995 } else if (!strcasecmp(argv[0],"dir") && argc == 2) {
ed9b544e 996 if (chdir(argv[1]) == -1) {
997 redisLog(REDIS_WARNING,"Can't chdir to '%s': %s",
998 argv[1], strerror(errno));
999 exit(1);
1000 }
bb0b03a3 1001 } else if (!strcasecmp(argv[0],"loglevel") && argc == 2) {
1002 if (!strcasecmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG;
1003 else if (!strcasecmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE;
1004 else if (!strcasecmp(argv[1],"warning")) server.verbosity = REDIS_WARNING;
ed9b544e 1005 else {
1006 err = "Invalid log level. Must be one of debug, notice, warning";
1007 goto loaderr;
1008 }
bb0b03a3 1009 } else if (!strcasecmp(argv[0],"logfile") && argc == 2) {
ed9b544e 1010 FILE *fp;
1011
1012 server.logfile = zstrdup(argv[1]);
bb0b03a3 1013 if (!strcasecmp(server.logfile,"stdout")) {
ed9b544e 1014 zfree(server.logfile);
1015 server.logfile = NULL;
1016 }
1017 if (server.logfile) {
1018 /* Test if we are able to open the file. The server will not
1019 * be able to abort just for this problem later... */
1020 fp = fopen(server.logfile,"a");
1021 if (fp == NULL) {
1022 err = sdscatprintf(sdsempty(),
1023 "Can't open the log file: %s", strerror(errno));
1024 goto loaderr;
1025 }
1026 fclose(fp);
1027 }
bb0b03a3 1028 } else if (!strcasecmp(argv[0],"databases") && argc == 2) {
ed9b544e 1029 server.dbnum = atoi(argv[1]);
1030 if (server.dbnum < 1) {
1031 err = "Invalid number of databases"; goto loaderr;
1032 }
285add55 1033 } else if (!strcasecmp(argv[0],"maxclients") && argc == 2) {
1034 server.maxclients = atoi(argv[1]);
3fd78bcd 1035 } else if (!strcasecmp(argv[0],"maxmemory") && argc == 2) {
1036 server.maxmemory = atoi(argv[1]);
bb0b03a3 1037 } else if (!strcasecmp(argv[0],"slaveof") && argc == 3) {
ed9b544e 1038 server.masterhost = sdsnew(argv[1]);
1039 server.masterport = atoi(argv[2]);
1040 server.replstate = REDIS_REPL_CONNECT;
bb0b03a3 1041 } else if (!strcasecmp(argv[0],"glueoutputbuf") && argc == 2) {
85dd2f3a 1042 if ((server.glueoutputbuf = yesnotoi(argv[1])) == -1) {
ed9b544e 1043 err = "argument must be 'yes' or 'no'"; goto loaderr;
1044 }
bb0b03a3 1045 } else if (!strcasecmp(argv[0],"shareobjects") && argc == 2) {
85dd2f3a 1046 if ((server.shareobjects = yesnotoi(argv[1])) == -1) {
10c43610 1047 err = "argument must be 'yes' or 'no'"; goto loaderr;
1048 }
e52c65b9 1049 } else if (!strcasecmp(argv[0],"shareobjectspoolsize") && argc == 2) {
1050 server.sharingpoolsize = atoi(argv[1]);
1051 if (server.sharingpoolsize < 1) {
1052 err = "invalid object sharing pool size"; goto loaderr;
1053 }
bb0b03a3 1054 } else if (!strcasecmp(argv[0],"daemonize") && argc == 2) {
85dd2f3a 1055 if ((server.daemonize = yesnotoi(argv[1])) == -1) {
ed9b544e 1056 err = "argument must be 'yes' or 'no'"; goto loaderr;
1057 }
bb0b03a3 1058 } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
abcb223e 1059 server.requirepass = zstrdup(argv[1]);
bb0b03a3 1060 } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
ed329fcf 1061 server.pidfile = zstrdup(argv[1]);
bb0b03a3 1062 } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) {
b8b553c8 1063 server.dbfilename = zstrdup(argv[1]);
ed9b544e 1064 } else {
1065 err = "Bad directive or wrong number of arguments"; goto loaderr;
1066 }
1067 for (j = 0; j < argc; j++)
1068 sdsfree(argv[j]);
1069 zfree(argv);
1070 sdsfree(line);
1071 }
1072 fclose(fp);
1073 return;
1074
1075loaderr:
1076 fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n");
1077 fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
1078 fprintf(stderr, ">>> '%s'\n", line);
1079 fprintf(stderr, "%s\n", err);
1080 exit(1);
1081}
1082
1083static void freeClientArgv(redisClient *c) {
1084 int j;
1085
1086 for (j = 0; j < c->argc; j++)
1087 decrRefCount(c->argv[j]);
1088 c->argc = 0;
1089}
1090
1091static void freeClient(redisClient *c) {
1092 listNode *ln;
1093
1094 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
1095 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
1096 sdsfree(c->querybuf);
1097 listRelease(c->reply);
1098 freeClientArgv(c);
1099 close(c->fd);
1100 ln = listSearchKey(server.clients,c);
1101 assert(ln != NULL);
1102 listDelNode(server.clients,ln);
1103 if (c->flags & REDIS_SLAVE) {
6208b3a7 1104 if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1)
1105 close(c->repldbfd);
87eca727 1106 list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
1107 ln = listSearchKey(l,c);
ed9b544e 1108 assert(ln != NULL);
87eca727 1109 listDelNode(l,ln);
ed9b544e 1110 }
1111 if (c->flags & REDIS_MASTER) {
1112 server.master = NULL;
1113 server.replstate = REDIS_REPL_CONNECT;
1114 }
93ea3759 1115 zfree(c->argv);
ed9b544e 1116 zfree(c);
1117}
1118
1119static void glueReplyBuffersIfNeeded(redisClient *c) {
1120 int totlen = 0;
6208b3a7 1121 listNode *ln;
ed9b544e 1122 robj *o;
1123
6208b3a7 1124 listRewind(c->reply);
1125 while((ln = listYield(c->reply))) {
ed9b544e 1126 o = ln->value;
1127 totlen += sdslen(o->ptr);
ed9b544e 1128 /* This optimization makes more sense if we don't have to copy
1129 * too much data */
1130 if (totlen > 1024) return;
1131 }
1132 if (totlen > 0) {
1133 char buf[1024];
1134 int copylen = 0;
1135
6208b3a7 1136 listRewind(c->reply);
1137 while((ln = listYield(c->reply))) {
ed9b544e 1138 o = ln->value;
1139 memcpy(buf+copylen,o->ptr,sdslen(o->ptr));
1140 copylen += sdslen(o->ptr);
1141 listDelNode(c->reply,ln);
ed9b544e 1142 }
1143 /* Now the output buffer is empty, add the new single element */
6fdc78ac 1144 o = createObject(REDIS_STRING,sdsnewlen(buf,totlen));
1145 if (!listAddNodeTail(c->reply,o)) oom("listAddNodeTail");
ed9b544e 1146 }
1147}
1148
1149static void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
1150 redisClient *c = privdata;
1151 int nwritten = 0, totwritten = 0, objlen;
1152 robj *o;
1153 REDIS_NOTUSED(el);
1154 REDIS_NOTUSED(mask);
1155
1156 if (server.glueoutputbuf && listLength(c->reply) > 1)
1157 glueReplyBuffersIfNeeded(c);
1158 while(listLength(c->reply)) {
1159 o = listNodeValue(listFirst(c->reply));
1160 objlen = sdslen(o->ptr);
1161
1162 if (objlen == 0) {
1163 listDelNode(c->reply,listFirst(c->reply));
1164 continue;
1165 }
1166
1167 if (c->flags & REDIS_MASTER) {
1168 nwritten = objlen - c->sentlen;
1169 } else {
a4d1ba9a 1170 nwritten = write(fd, ((char*)o->ptr)+c->sentlen, objlen - c->sentlen);
ed9b544e 1171 if (nwritten <= 0) break;
1172 }
1173 c->sentlen += nwritten;
1174 totwritten += nwritten;
1175 /* If we fully sent the object on head go to the next one */
1176 if (c->sentlen == objlen) {
1177 listDelNode(c->reply,listFirst(c->reply));
1178 c->sentlen = 0;
1179 }
1180 }
1181 if (nwritten == -1) {
1182 if (errno == EAGAIN) {
1183 nwritten = 0;
1184 } else {
1185 redisLog(REDIS_DEBUG,
1186 "Error writing to client: %s", strerror(errno));
1187 freeClient(c);
1188 return;
1189 }
1190 }
1191 if (totwritten > 0) c->lastinteraction = time(NULL);
1192 if (listLength(c->reply) == 0) {
1193 c->sentlen = 0;
1194 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
1195 }
1196}
1197
1198static struct redisCommand *lookupCommand(char *name) {
1199 int j = 0;
1200 while(cmdTable[j].name != NULL) {
bb0b03a3 1201 if (!strcasecmp(name,cmdTable[j].name)) return &cmdTable[j];
ed9b544e 1202 j++;
1203 }
1204 return NULL;
1205}
1206
1207/* resetClient prepare the client to process the next command */
1208static void resetClient(redisClient *c) {
1209 freeClientArgv(c);
1210 c->bulklen = -1;
1211}
1212
1213/* If this function gets called we already read a whole
1214 * command, argments are in the client argv/argc fields.
1215 * processCommand() execute the command or prepare the
1216 * server for a bulk read from the client.
1217 *
1218 * If 1 is returned the client is still alive and valid and
1219 * and other operations can be performed by the caller. Otherwise
1220 * if 0 is returned the client was destroied (i.e. after QUIT). */
1221static int processCommand(redisClient *c) {
1222 struct redisCommand *cmd;
1223 long long dirty;
1224
3fd78bcd 1225 /* Free some memory if needed (maxmemory setting) */
1226 if (server.maxmemory) freeMemoryIfNeeded();
1227
ed9b544e 1228 /* The QUIT command is handled as a special case. Normal command
1229 * procs are unable to close the client connection safely */
bb0b03a3 1230 if (!strcasecmp(c->argv[0]->ptr,"quit")) {
ed9b544e 1231 freeClient(c);
1232 return 0;
1233 }
1234 cmd = lookupCommand(c->argv[0]->ptr);
1235 if (!cmd) {
1236 addReplySds(c,sdsnew("-ERR unknown command\r\n"));
1237 resetClient(c);
1238 return 1;
1239 } else if ((cmd->arity > 0 && cmd->arity != c->argc) ||
1240 (c->argc < -cmd->arity)) {
1241 addReplySds(c,sdsnew("-ERR wrong number of arguments\r\n"));
1242 resetClient(c);
1243 return 1;
3fd78bcd 1244 } else if (server.maxmemory && cmd->flags & REDIS_CMD_DENYOOM && zmalloc_used_memory() > server.maxmemory) {
1245 addReplySds(c,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
1246 resetClient(c);
1247 return 1;
ed9b544e 1248 } else if (cmd->flags & REDIS_CMD_BULK && c->bulklen == -1) {
1249 int bulklen = atoi(c->argv[c->argc-1]->ptr);
1250
1251 decrRefCount(c->argv[c->argc-1]);
1252 if (bulklen < 0 || bulklen > 1024*1024*1024) {
1253 c->argc--;
1254 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
1255 resetClient(c);
1256 return 1;
1257 }
1258 c->argc--;
1259 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
1260 /* It is possible that the bulk read is already in the
1261 * buffer. Check this condition and handle it accordingly */
1262 if ((signed)sdslen(c->querybuf) >= c->bulklen) {
1263 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
1264 c->argc++;
1265 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
1266 } else {
1267 return 1;
1268 }
1269 }
10c43610 1270 /* Let's try to share objects on the command arguments vector */
1271 if (server.shareobjects) {
1272 int j;
1273 for(j = 1; j < c->argc; j++)
1274 c->argv[j] = tryObjectSharing(c->argv[j]);
1275 }
e63943a4 1276 /* Check if the user is authenticated */
1277 if (server.requirepass && !c->authenticated && cmd->proc != authCommand) {
1278 addReplySds(c,sdsnew("-ERR operation not permitted\r\n"));
1279 resetClient(c);
1280 return 1;
1281 }
1282
ed9b544e 1283 /* Exec the command */
1284 dirty = server.dirty;
1285 cmd->proc(c);
1286 if (server.dirty-dirty != 0 && listLength(server.slaves))
3305306f 1287 replicationFeedSlaves(server.slaves,cmd,c->db->id,c->argv,c->argc);
87eca727 1288 if (listLength(server.monitors))
3305306f 1289 replicationFeedSlaves(server.monitors,cmd,c->db->id,c->argv,c->argc);
ed9b544e 1290 server.stat_numcommands++;
1291
1292 /* Prepare the client for the next command */
1293 if (c->flags & REDIS_CLOSE) {
1294 freeClient(c);
1295 return 0;
1296 }
1297 resetClient(c);
1298 return 1;
1299}
1300
87eca727 1301static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc) {
6208b3a7 1302 listNode *ln;
ed9b544e 1303 int outc = 0, j;
93ea3759 1304 robj **outv;
1305 /* (args*2)+1 is enough room for args, spaces, newlines */
1306 robj *static_outv[REDIS_STATIC_ARGS*2+1];
1307
1308 if (argc <= REDIS_STATIC_ARGS) {
1309 outv = static_outv;
1310 } else {
1311 outv = zmalloc(sizeof(robj*)*(argc*2+1));
1312 if (!outv) oom("replicationFeedSlaves");
1313 }
ed9b544e 1314
1315 for (j = 0; j < argc; j++) {
1316 if (j != 0) outv[outc++] = shared.space;
1317 if ((cmd->flags & REDIS_CMD_BULK) && j == argc-1) {
1318 robj *lenobj;
1319
1320 lenobj = createObject(REDIS_STRING,
1321 sdscatprintf(sdsempty(),"%d\r\n",sdslen(argv[j]->ptr)));
1322 lenobj->refcount = 0;
1323 outv[outc++] = lenobj;
1324 }
1325 outv[outc++] = argv[j];
1326 }
1327 outv[outc++] = shared.crlf;
1328
40d224a9 1329 /* Increment all the refcounts at start and decrement at end in order to
1330 * be sure to free objects if there is no slave in a replication state
1331 * able to be feed with commands */
1332 for (j = 0; j < outc; j++) incrRefCount(outv[j]);
6208b3a7 1333 listRewind(slaves);
1334 while((ln = listYield(slaves))) {
ed9b544e 1335 redisClient *slave = ln->value;
40d224a9 1336
1337 /* Don't feed slaves that are still waiting for BGSAVE to start */
6208b3a7 1338 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) continue;
40d224a9 1339
1340 /* Feed all the other slaves, MONITORs and so on */
ed9b544e 1341 if (slave->slaveseldb != dictid) {
1342 robj *selectcmd;
1343
1344 switch(dictid) {
1345 case 0: selectcmd = shared.select0; break;
1346 case 1: selectcmd = shared.select1; break;
1347 case 2: selectcmd = shared.select2; break;
1348 case 3: selectcmd = shared.select3; break;
1349 case 4: selectcmd = shared.select4; break;
1350 case 5: selectcmd = shared.select5; break;
1351 case 6: selectcmd = shared.select6; break;
1352 case 7: selectcmd = shared.select7; break;
1353 case 8: selectcmd = shared.select8; break;
1354 case 9: selectcmd = shared.select9; break;
1355 default:
1356 selectcmd = createObject(REDIS_STRING,
1357 sdscatprintf(sdsempty(),"select %d\r\n",dictid));
1358 selectcmd->refcount = 0;
1359 break;
1360 }
1361 addReply(slave,selectcmd);
1362 slave->slaveseldb = dictid;
1363 }
1364 for (j = 0; j < outc; j++) addReply(slave,outv[j]);
ed9b544e 1365 }
40d224a9 1366 for (j = 0; j < outc; j++) decrRefCount(outv[j]);
93ea3759 1367 if (outv != static_outv) zfree(outv);
ed9b544e 1368}
1369
1370static void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
1371 redisClient *c = (redisClient*) privdata;
6208b3a7 1372 char buf[REDIS_IOBUF_LEN];
ed9b544e 1373 int nread;
1374 REDIS_NOTUSED(el);
1375 REDIS_NOTUSED(mask);
1376
6208b3a7 1377 nread = read(fd, buf, REDIS_IOBUF_LEN);
ed9b544e 1378 if (nread == -1) {
1379 if (errno == EAGAIN) {
1380 nread = 0;
1381 } else {
1382 redisLog(REDIS_DEBUG, "Reading from client: %s",strerror(errno));
1383 freeClient(c);
1384 return;
1385 }
1386 } else if (nread == 0) {
1387 redisLog(REDIS_DEBUG, "Client closed connection");
1388 freeClient(c);
1389 return;
1390 }
1391 if (nread) {
1392 c->querybuf = sdscatlen(c->querybuf, buf, nread);
1393 c->lastinteraction = time(NULL);
1394 } else {
1395 return;
1396 }
1397
1398again:
1399 if (c->bulklen == -1) {
1400 /* Read the first line of the query */
1401 char *p = strchr(c->querybuf,'\n');
1402 size_t querylen;
1403 if (p) {
1404 sds query, *argv;
1405 int argc, j;
1406
1407 query = c->querybuf;
1408 c->querybuf = sdsempty();
1409 querylen = 1+(p-(query));
1410 if (sdslen(query) > querylen) {
1411 /* leave data after the first line of the query in the buffer */
1412 c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
1413 }
1414 *p = '\0'; /* remove "\n" */
1415 if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
1416 sdsupdatelen(query);
1417
1418 /* Now we can split the query in arguments */
1419 if (sdslen(query) == 0) {
1420 /* Ignore empty query */
1421 sdsfree(query);
1422 return;
1423 }
1424 argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
ed9b544e 1425 if (argv == NULL) oom("sdssplitlen");
93ea3759 1426 sdsfree(query);
1427
1428 if (c->argv) zfree(c->argv);
1429 c->argv = zmalloc(sizeof(robj*)*argc);
1430 if (c->argv == NULL) oom("allocating arguments list for client");
1431
1432 for (j = 0; j < argc; j++) {
ed9b544e 1433 if (sdslen(argv[j])) {
1434 c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
1435 c->argc++;
1436 } else {
1437 sdsfree(argv[j]);
1438 }
1439 }
1440 zfree(argv);
1441 /* Execute the command. If the client is still valid
1442 * after processCommand() return and there is something
1443 * on the query buffer try to process the next command. */
1444 if (processCommand(c) && sdslen(c->querybuf)) goto again;
1445 return;
a1f6fa5e 1446 } else if (sdslen(c->querybuf) >= 1024*32) {
ed9b544e 1447 redisLog(REDIS_DEBUG, "Client protocol error");
1448 freeClient(c);
1449 return;
1450 }
1451 } else {
1452 /* Bulk read handling. Note that if we are at this point
1453 the client already sent a command terminated with a newline,
1454 we are reading the bulk data that is actually the last
1455 argument of the command. */
1456 int qbl = sdslen(c->querybuf);
1457
1458 if (c->bulklen <= qbl) {
1459 /* Copy everything but the final CRLF as final argument */
1460 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
1461 c->argc++;
1462 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
1463 processCommand(c);
1464 return;
1465 }
1466 }
1467}
1468
1469static int selectDb(redisClient *c, int id) {
1470 if (id < 0 || id >= server.dbnum)
1471 return REDIS_ERR;
3305306f 1472 c->db = &server.db[id];
ed9b544e 1473 return REDIS_OK;
1474}
1475
40d224a9 1476static void *dupClientReplyValue(void *o) {
1477 incrRefCount((robj*)o);
1478 return 0;
1479}
1480
ed9b544e 1481static redisClient *createClient(int fd) {
1482 redisClient *c = zmalloc(sizeof(*c));
1483
1484 anetNonBlock(NULL,fd);
1485 anetTcpNoDelay(NULL,fd);
1486 if (!c) return NULL;
1487 selectDb(c,0);
1488 c->fd = fd;
1489 c->querybuf = sdsempty();
1490 c->argc = 0;
93ea3759 1491 c->argv = NULL;
ed9b544e 1492 c->bulklen = -1;
1493 c->sentlen = 0;
1494 c->flags = 0;
1495 c->lastinteraction = time(NULL);
abcb223e 1496 c->authenticated = 0;
40d224a9 1497 c->replstate = REDIS_REPL_NONE;
ed9b544e 1498 if ((c->reply = listCreate()) == NULL) oom("listCreate");
1499 listSetFreeMethod(c->reply,decrRefCount);
40d224a9 1500 listSetDupMethod(c->reply,dupClientReplyValue);
ed9b544e 1501 if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
1502 readQueryFromClient, c, NULL) == AE_ERR) {
1503 freeClient(c);
1504 return NULL;
1505 }
1506 if (!listAddNodeTail(server.clients,c)) oom("listAddNodeTail");
1507 return c;
1508}
1509
1510static void addReply(redisClient *c, robj *obj) {
1511 if (listLength(c->reply) == 0 &&
6208b3a7 1512 (c->replstate == REDIS_REPL_NONE ||
1513 c->replstate == REDIS_REPL_ONLINE) &&
ed9b544e 1514 aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
1515 sendReplyToClient, c, NULL) == AE_ERR) return;
1516 if (!listAddNodeTail(c->reply,obj)) oom("listAddNodeTail");
1517 incrRefCount(obj);
1518}
1519
1520static void addReplySds(redisClient *c, sds s) {
1521 robj *o = createObject(REDIS_STRING,s);
1522 addReply(c,o);
1523 decrRefCount(o);
1524}
1525
1526static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
1527 int cport, cfd;
1528 char cip[128];
285add55 1529 redisClient *c;
ed9b544e 1530 REDIS_NOTUSED(el);
1531 REDIS_NOTUSED(mask);
1532 REDIS_NOTUSED(privdata);
1533
1534 cfd = anetAccept(server.neterr, fd, cip, &cport);
1535 if (cfd == AE_ERR) {
1536 redisLog(REDIS_DEBUG,"Accepting client connection: %s", server.neterr);
1537 return;
1538 }
1539 redisLog(REDIS_DEBUG,"Accepted %s:%d", cip, cport);
285add55 1540 if ((c = createClient(cfd)) == NULL) {
ed9b544e 1541 redisLog(REDIS_WARNING,"Error allocating resoures for the client");
1542 close(cfd); /* May be already closed, just ingore errors */
1543 return;
1544 }
285add55 1545 /* If maxclient directive is set and this is one client more... close the
1546 * connection. Note that we create the client instead to check before
1547 * for this condition, since now the socket is already set in nonblocking
1548 * mode and we can send an error for free using the Kernel I/O */
1549 if (server.maxclients && listLength(server.clients) > server.maxclients) {
1550 char *err = "-ERR max number of clients reached\r\n";
1551
1552 /* That's a best effort error message, don't check write errors */
d7fc9edb 1553 (void) write(c->fd,err,strlen(err));
285add55 1554 freeClient(c);
1555 return;
1556 }
ed9b544e 1557 server.stat_numconnections++;
1558}
1559
1560/* ======================= Redis objects implementation ===================== */
1561
1562static robj *createObject(int type, void *ptr) {
1563 robj *o;
1564
1565 if (listLength(server.objfreelist)) {
1566 listNode *head = listFirst(server.objfreelist);
1567 o = listNodeValue(head);
1568 listDelNode(server.objfreelist,head);
1569 } else {
1570 o = zmalloc(sizeof(*o));
1571 }
1572 if (!o) oom("createObject");
1573 o->type = type;
1574 o->ptr = ptr;
1575 o->refcount = 1;
1576 return o;
1577}
1578
1579static robj *createStringObject(char *ptr, size_t len) {
1580 return createObject(REDIS_STRING,sdsnewlen(ptr,len));
1581}
1582
1583static robj *createListObject(void) {
1584 list *l = listCreate();
1585
1586 if (!l) oom("listCreate");
1587 listSetFreeMethod(l,decrRefCount);
1588 return createObject(REDIS_LIST,l);
1589}
1590
1591static robj *createSetObject(void) {
1592 dict *d = dictCreate(&setDictType,NULL);
1593 if (!d) oom("dictCreate");
1594 return createObject(REDIS_SET,d);
1595}
1596
ed9b544e 1597static void freeStringObject(robj *o) {
1598 sdsfree(o->ptr);
1599}
1600
1601static void freeListObject(robj *o) {
1602 listRelease((list*) o->ptr);
1603}
1604
1605static void freeSetObject(robj *o) {
1606 dictRelease((dict*) o->ptr);
1607}
1608
1609static void freeHashObject(robj *o) {
1610 dictRelease((dict*) o->ptr);
1611}
1612
1613static void incrRefCount(robj *o) {
1614 o->refcount++;
94754ccc 1615#ifdef DEBUG_REFCOUNT
1616 if (o->type == REDIS_STRING)
1617 printf("Increment '%s'(%p), now is: %d\n",o->ptr,o,o->refcount);
1618#endif
ed9b544e 1619}
1620
1621static void decrRefCount(void *obj) {
1622 robj *o = obj;
94754ccc 1623
1624#ifdef DEBUG_REFCOUNT
1625 if (o->type == REDIS_STRING)
1626 printf("Decrement '%s'(%p), now is: %d\n",o->ptr,o,o->refcount-1);
1627#endif
ed9b544e 1628 if (--(o->refcount) == 0) {
1629 switch(o->type) {
1630 case REDIS_STRING: freeStringObject(o); break;
1631 case REDIS_LIST: freeListObject(o); break;
1632 case REDIS_SET: freeSetObject(o); break;
1633 case REDIS_HASH: freeHashObject(o); break;
1634 default: assert(0 != 0); break;
1635 }
1636 if (listLength(server.objfreelist) > REDIS_OBJFREELIST_MAX ||
1637 !listAddNodeHead(server.objfreelist,o))
1638 zfree(o);
1639 }
1640}
1641
10c43610 1642/* Try to share an object against the shared objects pool */
1643static robj *tryObjectSharing(robj *o) {
1644 struct dictEntry *de;
1645 unsigned long c;
1646
3305306f 1647 if (o == NULL || server.shareobjects == 0) return o;
10c43610 1648
1649 assert(o->type == REDIS_STRING);
1650 de = dictFind(server.sharingpool,o);
1651 if (de) {
1652 robj *shared = dictGetEntryKey(de);
1653
1654 c = ((unsigned long) dictGetEntryVal(de))+1;
1655 dictGetEntryVal(de) = (void*) c;
1656 incrRefCount(shared);
1657 decrRefCount(o);
1658 return shared;
1659 } else {
1660 /* Here we are using a stream algorihtm: Every time an object is
1661 * shared we increment its count, everytime there is a miss we
1662 * recrement the counter of a random object. If this object reaches
1663 * zero we remove the object and put the current object instead. */
3305306f 1664 if (dictSize(server.sharingpool) >=
10c43610 1665 server.sharingpoolsize) {
1666 de = dictGetRandomKey(server.sharingpool);
1667 assert(de != NULL);
1668 c = ((unsigned long) dictGetEntryVal(de))-1;
1669 dictGetEntryVal(de) = (void*) c;
1670 if (c == 0) {
1671 dictDelete(server.sharingpool,de->key);
1672 }
1673 } else {
1674 c = 0; /* If the pool is empty we want to add this object */
1675 }
1676 if (c == 0) {
1677 int retval;
1678
1679 retval = dictAdd(server.sharingpool,o,(void*)1);
1680 assert(retval == DICT_OK);
1681 incrRefCount(o);
1682 }
1683 return o;
1684 }
1685}
1686
3305306f 1687static robj *lookupKey(redisDb *db, robj *key) {
1688 dictEntry *de = dictFind(db->dict,key);
1689 return de ? dictGetEntryVal(de) : NULL;
1690}
1691
1692static robj *lookupKeyRead(redisDb *db, robj *key) {
1693 expireIfNeeded(db,key);
1694 return lookupKey(db,key);
1695}
1696
1697static robj *lookupKeyWrite(redisDb *db, robj *key) {
1698 deleteIfVolatile(db,key);
1699 return lookupKey(db,key);
1700}
1701
1702static int deleteKey(redisDb *db, robj *key) {
94754ccc 1703 int retval;
1704
1705 /* We need to protect key from destruction: after the first dictDelete()
1706 * it may happen that 'key' is no longer valid if we don't increment
1707 * it's count. This may happen when we get the object reference directly
1708 * from the hash table with dictRandomKey() or dict iterators */
1709 incrRefCount(key);
3305306f 1710 if (dictSize(db->expires)) dictDelete(db->expires,key);
94754ccc 1711 retval = dictDelete(db->dict,key);
1712 decrRefCount(key);
1713
1714 return retval == DICT_OK;
3305306f 1715}
1716
ed9b544e 1717/*============================ DB saving/loading ============================ */
1718
f78fd11b 1719static int rdbSaveType(FILE *fp, unsigned char type) {
1720 if (fwrite(&type,1,1,fp) == 0) return -1;
1721 return 0;
1722}
1723
bb32ede5 1724static int rdbSaveTime(FILE *fp, time_t t) {
1725 int32_t t32 = (int32_t) t;
1726 if (fwrite(&t32,4,1,fp) == 0) return -1;
1727 return 0;
1728}
1729
e3566d4b 1730/* check rdbLoadLen() comments for more info */
f78fd11b 1731static int rdbSaveLen(FILE *fp, uint32_t len) {
1732 unsigned char buf[2];
1733
1734 if (len < (1<<6)) {
1735 /* Save a 6 bit len */
10c43610 1736 buf[0] = (len&0xFF)|(REDIS_RDB_6BITLEN<<6);
f78fd11b 1737 if (fwrite(buf,1,1,fp) == 0) return -1;
1738 } else if (len < (1<<14)) {
1739 /* Save a 14 bit len */
10c43610 1740 buf[0] = ((len>>8)&0xFF)|(REDIS_RDB_14BITLEN<<6);
f78fd11b 1741 buf[1] = len&0xFF;
17be1a4a 1742 if (fwrite(buf,2,1,fp) == 0) return -1;
f78fd11b 1743 } else {
1744 /* Save a 32 bit len */
10c43610 1745 buf[0] = (REDIS_RDB_32BITLEN<<6);
f78fd11b 1746 if (fwrite(buf,1,1,fp) == 0) return -1;
1747 len = htonl(len);
1748 if (fwrite(&len,4,1,fp) == 0) return -1;
1749 }
1750 return 0;
1751}
1752
e3566d4b 1753/* String objects in the form "2391" "-100" without any space and with a
1754 * range of values that can fit in an 8, 16 or 32 bit signed value can be
1755 * encoded as integers to save space */
1756int rdbTryIntegerEncoding(sds s, unsigned char *enc) {
1757 long long value;
1758 char *endptr, buf[32];
1759
1760 /* Check if it's possible to encode this value as a number */
1761 value = strtoll(s, &endptr, 10);
1762 if (endptr[0] != '\0') return 0;
1763 snprintf(buf,32,"%lld",value);
1764
1765 /* If the number converted back into a string is not identical
1766 * then it's not possible to encode the string as integer */
1767 if (strlen(buf) != sdslen(s) || memcmp(buf,s,sdslen(s))) return 0;
1768
1769 /* Finally check if it fits in our ranges */
1770 if (value >= -(1<<7) && value <= (1<<7)-1) {
1771 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT8;
1772 enc[1] = value&0xFF;
1773 return 2;
1774 } else if (value >= -(1<<15) && value <= (1<<15)-1) {
1775 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT16;
1776 enc[1] = value&0xFF;
1777 enc[2] = (value>>8)&0xFF;
1778 return 3;
1779 } else if (value >= -((long long)1<<31) && value <= ((long long)1<<31)-1) {
1780 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT32;
1781 enc[1] = value&0xFF;
1782 enc[2] = (value>>8)&0xFF;
1783 enc[3] = (value>>16)&0xFF;
1784 enc[4] = (value>>24)&0xFF;
1785 return 5;
1786 } else {
1787 return 0;
1788 }
1789}
1790
774e3047 1791static int rdbSaveLzfStringObject(FILE *fp, robj *obj) {
1792 unsigned int comprlen, outlen;
1793 unsigned char byte;
1794 void *out;
1795
1796 /* We require at least four bytes compression for this to be worth it */
1797 outlen = sdslen(obj->ptr)-4;
1798 if (outlen <= 0) return 0;
3a2694c4 1799 if ((out = zmalloc(outlen+1)) == NULL) return 0;
774e3047 1800 comprlen = lzf_compress(obj->ptr, sdslen(obj->ptr), out, outlen);
1801 if (comprlen == 0) {
88e85998 1802 zfree(out);
774e3047 1803 return 0;
1804 }
1805 /* Data compressed! Let's save it on disk */
1806 byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF;
1807 if (fwrite(&byte,1,1,fp) == 0) goto writeerr;
1808 if (rdbSaveLen(fp,comprlen) == -1) goto writeerr;
1809 if (rdbSaveLen(fp,sdslen(obj->ptr)) == -1) goto writeerr;
1810 if (fwrite(out,comprlen,1,fp) == 0) goto writeerr;
88e85998 1811 zfree(out);
774e3047 1812 return comprlen;
1813
1814writeerr:
88e85998 1815 zfree(out);
774e3047 1816 return -1;
1817}
1818
e3566d4b 1819/* Save a string objet as [len][data] on disk. If the object is a string
1820 * representation of an integer value we try to safe it in a special form */
10c43610 1821static int rdbSaveStringObject(FILE *fp, robj *obj) {
1822 size_t len = sdslen(obj->ptr);
e3566d4b 1823 int enclen;
10c43610 1824
774e3047 1825 /* Try integer encoding */
e3566d4b 1826 if (len <= 11) {
1827 unsigned char buf[5];
1828 if ((enclen = rdbTryIntegerEncoding(obj->ptr,buf)) > 0) {
1829 if (fwrite(buf,enclen,1,fp) == 0) return -1;
1830 return 0;
1831 }
1832 }
774e3047 1833
1834 /* Try LZF compression - under 20 bytes it's unable to compress even
88e85998 1835 * aaaaaaaaaaaaaaaaaa so skip it */
3a2694c4 1836 if (1 && len > 20) {
774e3047 1837 int retval;
1838
1839 retval = rdbSaveLzfStringObject(fp,obj);
1840 if (retval == -1) return -1;
1841 if (retval > 0) return 0;
1842 /* retval == 0 means data can't be compressed, save the old way */
1843 }
1844
1845 /* Store verbatim */
10c43610 1846 if (rdbSaveLen(fp,len) == -1) return -1;
1847 if (len && fwrite(obj->ptr,len,1,fp) == 0) return -1;
1848 return 0;
1849}
1850
ed9b544e 1851/* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
f78fd11b 1852static int rdbSave(char *filename) {
ed9b544e 1853 dictIterator *di = NULL;
1854 dictEntry *de;
ed9b544e 1855 FILE *fp;
1856 char tmpfile[256];
1857 int j;
bb32ede5 1858 time_t now = time(NULL);
ed9b544e 1859
1860 snprintf(tmpfile,256,"temp-%d.%ld.rdb",(int)time(NULL),(long int)random());
1861 fp = fopen(tmpfile,"w");
1862 if (!fp) {
1863 redisLog(REDIS_WARNING, "Failed saving the DB: %s", strerror(errno));
1864 return REDIS_ERR;
1865 }
f78fd11b 1866 if (fwrite("REDIS0001",9,1,fp) == 0) goto werr;
ed9b544e 1867 for (j = 0; j < server.dbnum; j++) {
bb32ede5 1868 redisDb *db = server.db+j;
1869 dict *d = db->dict;
3305306f 1870 if (dictSize(d) == 0) continue;
ed9b544e 1871 di = dictGetIterator(d);
1872 if (!di) {
1873 fclose(fp);
1874 return REDIS_ERR;
1875 }
1876
1877 /* Write the SELECT DB opcode */
f78fd11b 1878 if (rdbSaveType(fp,REDIS_SELECTDB) == -1) goto werr;
1879 if (rdbSaveLen(fp,j) == -1) goto werr;
ed9b544e 1880
1881 /* Iterate this DB writing every entry */
1882 while((de = dictNext(di)) != NULL) {
1883 robj *key = dictGetEntryKey(de);
1884 robj *o = dictGetEntryVal(de);
bb32ede5 1885 time_t expiretime = getExpire(db,key);
1886
1887 /* Save the expire time */
1888 if (expiretime != -1) {
1889 /* If this key is already expired skip it */
1890 if (expiretime < now) continue;
1891 if (rdbSaveType(fp,REDIS_EXPIRETIME) == -1) goto werr;
1892 if (rdbSaveTime(fp,expiretime) == -1) goto werr;
1893 }
1894 /* Save the key and associated value */
f78fd11b 1895 if (rdbSaveType(fp,o->type) == -1) goto werr;
10c43610 1896 if (rdbSaveStringObject(fp,key) == -1) goto werr;
f78fd11b 1897 if (o->type == REDIS_STRING) {
ed9b544e 1898 /* Save a string value */
10c43610 1899 if (rdbSaveStringObject(fp,o) == -1) goto werr;
f78fd11b 1900 } else if (o->type == REDIS_LIST) {
ed9b544e 1901 /* Save a list value */
1902 list *list = o->ptr;
6208b3a7 1903 listNode *ln;
ed9b544e 1904
6208b3a7 1905 listRewind(list);
f78fd11b 1906 if (rdbSaveLen(fp,listLength(list)) == -1) goto werr;
6208b3a7 1907 while((ln = listYield(list))) {
ed9b544e 1908 robj *eleobj = listNodeValue(ln);
f78fd11b 1909
10c43610 1910 if (rdbSaveStringObject(fp,eleobj) == -1) goto werr;
ed9b544e 1911 }
f78fd11b 1912 } else if (o->type == REDIS_SET) {
ed9b544e 1913 /* Save a set value */
1914 dict *set = o->ptr;
1915 dictIterator *di = dictGetIterator(set);
1916 dictEntry *de;
1917
1918 if (!set) oom("dictGetIteraotr");
3305306f 1919 if (rdbSaveLen(fp,dictSize(set)) == -1) goto werr;
ed9b544e 1920 while((de = dictNext(di)) != NULL) {
10c43610 1921 robj *eleobj = dictGetEntryKey(de);
ed9b544e 1922
10c43610 1923 if (rdbSaveStringObject(fp,eleobj) == -1) goto werr;
ed9b544e 1924 }
1925 dictReleaseIterator(di);
1926 } else {
1927 assert(0 != 0);
1928 }
1929 }
1930 dictReleaseIterator(di);
1931 }
1932 /* EOF opcode */
f78fd11b 1933 if (rdbSaveType(fp,REDIS_EOF) == -1) goto werr;
1934
1935 /* Make sure data will not remain on the OS's output buffers */
ed9b544e 1936 fflush(fp);
1937 fsync(fileno(fp));
1938 fclose(fp);
1939
1940 /* Use RENAME to make sure the DB file is changed atomically only
1941 * if the generate DB file is ok. */
1942 if (rename(tmpfile,filename) == -1) {
1943 redisLog(REDIS_WARNING,"Error moving temp DB file on the final destionation: %s", strerror(errno));
1944 unlink(tmpfile);
1945 return REDIS_ERR;
1946 }
1947 redisLog(REDIS_NOTICE,"DB saved on disk");
1948 server.dirty = 0;
1949 server.lastsave = time(NULL);
1950 return REDIS_OK;
1951
1952werr:
1953 fclose(fp);
1954 unlink(tmpfile);
1955 redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
1956 if (di) dictReleaseIterator(di);
1957 return REDIS_ERR;
1958}
1959
f78fd11b 1960static int rdbSaveBackground(char *filename) {
ed9b544e 1961 pid_t childpid;
1962
1963 if (server.bgsaveinprogress) return REDIS_ERR;
1964 if ((childpid = fork()) == 0) {
1965 /* Child */
1966 close(server.fd);
f78fd11b 1967 if (rdbSave(filename) == REDIS_OK) {
ed9b544e 1968 exit(0);
1969 } else {
1970 exit(1);
1971 }
1972 } else {
1973 /* Parent */
5a7c647e 1974 if (childpid == -1) {
1975 redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
1976 strerror(errno));
1977 return REDIS_ERR;
1978 }
ed9b544e 1979 redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
1980 server.bgsaveinprogress = 1;
1981 return REDIS_OK;
1982 }
1983 return REDIS_OK; /* unreached */
1984}
1985
f78fd11b 1986static int rdbLoadType(FILE *fp) {
1987 unsigned char type;
7b45bfb2 1988 if (fread(&type,1,1,fp) == 0) return -1;
1989 return type;
1990}
1991
bb32ede5 1992static time_t rdbLoadTime(FILE *fp) {
1993 int32_t t32;
1994 if (fread(&t32,4,1,fp) == 0) return -1;
1995 return (time_t) t32;
1996}
1997
e3566d4b 1998/* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
1999 * of this file for a description of how this are stored on disk.
2000 *
2001 * isencoded is set to 1 if the readed length is not actually a length but
2002 * an "encoding type", check the above comments for more info */
2003static uint32_t rdbLoadLen(FILE *fp, int rdbver, int *isencoded) {
f78fd11b 2004 unsigned char buf[2];
2005 uint32_t len;
2006
e3566d4b 2007 if (isencoded) *isencoded = 0;
f78fd11b 2008 if (rdbver == 0) {
2009 if (fread(&len,4,1,fp) == 0) return REDIS_RDB_LENERR;
2010 return ntohl(len);
2011 } else {
17be1a4a 2012 int type;
2013
f78fd11b 2014 if (fread(buf,1,1,fp) == 0) return REDIS_RDB_LENERR;
17be1a4a 2015 type = (buf[0]&0xC0)>>6;
2016 if (type == REDIS_RDB_6BITLEN) {
f78fd11b 2017 /* Read a 6 bit len */
e3566d4b 2018 return buf[0]&0x3F;
2019 } else if (type == REDIS_RDB_ENCVAL) {
2020 /* Read a 6 bit len encoding type */
2021 if (isencoded) *isencoded = 1;
2022 return buf[0]&0x3F;
17be1a4a 2023 } else if (type == REDIS_RDB_14BITLEN) {
f78fd11b 2024 /* Read a 14 bit len */
2025 if (fread(buf+1,1,1,fp) == 0) return REDIS_RDB_LENERR;
2026 return ((buf[0]&0x3F)<<8)|buf[1];
2027 } else {
2028 /* Read a 32 bit len */
2029 if (fread(&len,4,1,fp) == 0) return REDIS_RDB_LENERR;
2030 return ntohl(len);
2031 }
2032 }
f78fd11b 2033}
2034
e3566d4b 2035static robj *rdbLoadIntegerObject(FILE *fp, int enctype) {
2036 unsigned char enc[4];
2037 long long val;
2038
2039 if (enctype == REDIS_RDB_ENC_INT8) {
2040 if (fread(enc,1,1,fp) == 0) return NULL;
2041 val = (signed char)enc[0];
2042 } else if (enctype == REDIS_RDB_ENC_INT16) {
2043 uint16_t v;
2044 if (fread(enc,2,1,fp) == 0) return NULL;
2045 v = enc[0]|(enc[1]<<8);
2046 val = (int16_t)v;
2047 } else if (enctype == REDIS_RDB_ENC_INT32) {
2048 uint32_t v;
2049 if (fread(enc,4,1,fp) == 0) return NULL;
2050 v = enc[0]|(enc[1]<<8)|(enc[2]<<16)|(enc[3]<<24);
2051 val = (int32_t)v;
2052 } else {
2053 val = 0; /* anti-warning */
2054 assert(0!=0);
2055 }
2056 return createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",val));
2057}
2058
88e85998 2059static robj *rdbLoadLzfStringObject(FILE*fp, int rdbver) {
2060 unsigned int len, clen;
2061 unsigned char *c = NULL;
2062 sds val = NULL;
2063
2064 if ((clen = rdbLoadLen(fp,rdbver,NULL)) == REDIS_RDB_LENERR) return NULL;
2065 if ((len = rdbLoadLen(fp,rdbver,NULL)) == REDIS_RDB_LENERR) return NULL;
2066 if ((c = zmalloc(clen)) == NULL) goto err;
2067 if ((val = sdsnewlen(NULL,len)) == NULL) goto err;
2068 if (fread(c,clen,1,fp) == 0) goto err;
2069 if (lzf_decompress(c,clen,val,len) == 0) goto err;
5109cdff 2070 zfree(c);
88e85998 2071 return createObject(REDIS_STRING,val);
2072err:
2073 zfree(c);
2074 sdsfree(val);
2075 return NULL;
2076}
2077
e3566d4b 2078static robj *rdbLoadStringObject(FILE*fp, int rdbver) {
2079 int isencoded;
2080 uint32_t len;
f78fd11b 2081 sds val;
2082
e3566d4b 2083 len = rdbLoadLen(fp,rdbver,&isencoded);
2084 if (isencoded) {
2085 switch(len) {
2086 case REDIS_RDB_ENC_INT8:
2087 case REDIS_RDB_ENC_INT16:
2088 case REDIS_RDB_ENC_INT32:
3305306f 2089 return tryObjectSharing(rdbLoadIntegerObject(fp,len));
88e85998 2090 case REDIS_RDB_ENC_LZF:
2091 return tryObjectSharing(rdbLoadLzfStringObject(fp,rdbver));
e3566d4b 2092 default:
2093 assert(0!=0);
2094 }
2095 }
2096
f78fd11b 2097 if (len == REDIS_RDB_LENERR) return NULL;
2098 val = sdsnewlen(NULL,len);
2099 if (len && fread(val,len,1,fp) == 0) {
2100 sdsfree(val);
2101 return NULL;
2102 }
10c43610 2103 return tryObjectSharing(createObject(REDIS_STRING,val));
f78fd11b 2104}
2105
2106static int rdbLoad(char *filename) {
ed9b544e 2107 FILE *fp;
f78fd11b 2108 robj *keyobj = NULL;
2109 uint32_t dbid;
bb32ede5 2110 int type, retval, rdbver;
3305306f 2111 dict *d = server.db[0].dict;
bb32ede5 2112 redisDb *db = server.db+0;
f78fd11b 2113 char buf[1024];
bb32ede5 2114 time_t expiretime = -1, now = time(NULL);
2115
ed9b544e 2116 fp = fopen(filename,"r");
2117 if (!fp) return REDIS_ERR;
2118 if (fread(buf,9,1,fp) == 0) goto eoferr;
f78fd11b 2119 buf[9] = '\0';
2120 if (memcmp(buf,"REDIS",5) != 0) {
ed9b544e 2121 fclose(fp);
2122 redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
2123 return REDIS_ERR;
2124 }
f78fd11b 2125 rdbver = atoi(buf+5);
2126 if (rdbver > 1) {
2127 fclose(fp);
2128 redisLog(REDIS_WARNING,"Can't handle RDB format version %d",rdbver);
2129 return REDIS_ERR;
2130 }
ed9b544e 2131 while(1) {
2132 robj *o;
2133
2134 /* Read type. */
f78fd11b 2135 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
bb32ede5 2136 if (type == REDIS_EXPIRETIME) {
2137 if ((expiretime = rdbLoadTime(fp)) == -1) goto eoferr;
2138 /* We read the time so we need to read the object type again */
2139 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
2140 }
ed9b544e 2141 if (type == REDIS_EOF) break;
2142 /* Handle SELECT DB opcode as a special case */
2143 if (type == REDIS_SELECTDB) {
e3566d4b 2144 if ((dbid = rdbLoadLen(fp,rdbver,NULL)) == REDIS_RDB_LENERR)
2145 goto eoferr;
ed9b544e 2146 if (dbid >= (unsigned)server.dbnum) {
f78fd11b 2147 redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum);
ed9b544e 2148 exit(1);
2149 }
bb32ede5 2150 db = server.db+dbid;
2151 d = db->dict;
ed9b544e 2152 continue;
2153 }
2154 /* Read key */
f78fd11b 2155 if ((keyobj = rdbLoadStringObject(fp,rdbver)) == NULL) goto eoferr;
ed9b544e 2156
2157 if (type == REDIS_STRING) {
2158 /* Read string value */
f78fd11b 2159 if ((o = rdbLoadStringObject(fp,rdbver)) == NULL) goto eoferr;
ed9b544e 2160 } else if (type == REDIS_LIST || type == REDIS_SET) {
2161 /* Read list/set value */
2162 uint32_t listlen;
f78fd11b 2163
e3566d4b 2164 if ((listlen = rdbLoadLen(fp,rdbver,NULL)) == REDIS_RDB_LENERR)
f78fd11b 2165 goto eoferr;
ed9b544e 2166 o = (type == REDIS_LIST) ? createListObject() : createSetObject();
2167 /* Load every single element of the list/set */
2168 while(listlen--) {
2169 robj *ele;
2170
f78fd11b 2171 if ((ele = rdbLoadStringObject(fp,rdbver)) == NULL) goto eoferr;
ed9b544e 2172 if (type == REDIS_LIST) {
2173 if (!listAddNodeTail((list*)o->ptr,ele))
2174 oom("listAddNodeTail");
2175 } else {
2176 if (dictAdd((dict*)o->ptr,ele,NULL) == DICT_ERR)
2177 oom("dictAdd");
2178 }
ed9b544e 2179 }
2180 } else {
2181 assert(0 != 0);
2182 }
2183 /* Add the new object in the hash table */
f78fd11b 2184 retval = dictAdd(d,keyobj,o);
ed9b544e 2185 if (retval == DICT_ERR) {
f78fd11b 2186 redisLog(REDIS_WARNING,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj->ptr);
ed9b544e 2187 exit(1);
2188 }
bb32ede5 2189 /* Set the expire time if needed */
2190 if (expiretime != -1) {
2191 setExpire(db,keyobj,expiretime);
2192 /* Delete this key if already expired */
2193 if (expiretime < now) deleteKey(db,keyobj);
2194 expiretime = -1;
2195 }
f78fd11b 2196 keyobj = o = NULL;
ed9b544e 2197 }
2198 fclose(fp);
2199 return REDIS_OK;
2200
2201eoferr: /* unexpected end of file is handled here with a fatal exit */
e3566d4b 2202 if (keyobj) decrRefCount(keyobj);
2203 redisLog(REDIS_WARNING,"Short read or OOM loading DB. Unrecoverable error, exiting now.");
ed9b544e 2204 exit(1);
2205 return REDIS_ERR; /* Just to avoid warning */
2206}
2207
2208/*================================== Commands =============================== */
2209
abcb223e 2210static void authCommand(redisClient *c) {
2e77c2ee 2211 if (!server.requirepass || !strcmp(c->argv[1]->ptr, server.requirepass)) {
abcb223e
BH
2212 c->authenticated = 1;
2213 addReply(c,shared.ok);
2214 } else {
2215 c->authenticated = 0;
2216 addReply(c,shared.err);
2217 }
2218}
2219
ed9b544e 2220static void pingCommand(redisClient *c) {
2221 addReply(c,shared.pong);
2222}
2223
2224static void echoCommand(redisClient *c) {
c937aa89 2225 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",
ed9b544e 2226 (int)sdslen(c->argv[1]->ptr)));
2227 addReply(c,c->argv[1]);
2228 addReply(c,shared.crlf);
2229}
2230
2231/*=================================== Strings =============================== */
2232
2233static void setGenericCommand(redisClient *c, int nx) {
2234 int retval;
2235
3305306f 2236 retval = dictAdd(c->db->dict,c->argv[1],c->argv[2]);
ed9b544e 2237 if (retval == DICT_ERR) {
2238 if (!nx) {
3305306f 2239 dictReplace(c->db->dict,c->argv[1],c->argv[2]);
ed9b544e 2240 incrRefCount(c->argv[2]);
2241 } else {
c937aa89 2242 addReply(c,shared.czero);
ed9b544e 2243 return;
2244 }
2245 } else {
2246 incrRefCount(c->argv[1]);
2247 incrRefCount(c->argv[2]);
2248 }
2249 server.dirty++;
3305306f 2250 removeExpire(c->db,c->argv[1]);
c937aa89 2251 addReply(c, nx ? shared.cone : shared.ok);
ed9b544e 2252}
2253
2254static void setCommand(redisClient *c) {
a4d1ba9a 2255 setGenericCommand(c,0);
ed9b544e 2256}
2257
2258static void setnxCommand(redisClient *c) {
a4d1ba9a 2259 setGenericCommand(c,1);
ed9b544e 2260}
2261
2262static void getCommand(redisClient *c) {
3305306f 2263 robj *o = lookupKeyRead(c->db,c->argv[1]);
2264
2265 if (o == NULL) {
c937aa89 2266 addReply(c,shared.nullbulk);
ed9b544e 2267 } else {
ed9b544e 2268 if (o->type != REDIS_STRING) {
c937aa89 2269 addReply(c,shared.wrongtypeerr);
ed9b544e 2270 } else {
c937aa89 2271 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(o->ptr)));
ed9b544e 2272 addReply(c,o);
2273 addReply(c,shared.crlf);
2274 }
2275 }
2276}
2277
a431eb74 2278static void getSetCommand(redisClient *c) {
2279 getCommand(c);
2280 if (dictAdd(c->db->dict,c->argv[1],c->argv[2]) == DICT_ERR) {
2281 dictReplace(c->db->dict,c->argv[1],c->argv[2]);
2282 } else {
2283 incrRefCount(c->argv[1]);
2284 }
2285 incrRefCount(c->argv[2]);
2286 server.dirty++;
2287 removeExpire(c->db,c->argv[1]);
2288}
2289
70003d28 2290static void mgetCommand(redisClient *c) {
70003d28 2291 int j;
2292
c937aa89 2293 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-1));
70003d28 2294 for (j = 1; j < c->argc; j++) {
3305306f 2295 robj *o = lookupKeyRead(c->db,c->argv[j]);
2296 if (o == NULL) {
c937aa89 2297 addReply(c,shared.nullbulk);
70003d28 2298 } else {
70003d28 2299 if (o->type != REDIS_STRING) {
c937aa89 2300 addReply(c,shared.nullbulk);
70003d28 2301 } else {
c937aa89 2302 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(o->ptr)));
70003d28 2303 addReply(c,o);
2304 addReply(c,shared.crlf);
2305 }
2306 }
2307 }
2308}
2309
d68ed120 2310static void incrDecrCommand(redisClient *c, long long incr) {
ed9b544e 2311 long long value;
2312 int retval;
2313 robj *o;
2314
3305306f 2315 o = lookupKeyWrite(c->db,c->argv[1]);
2316 if (o == NULL) {
ed9b544e 2317 value = 0;
2318 } else {
ed9b544e 2319 if (o->type != REDIS_STRING) {
2320 value = 0;
2321 } else {
2322 char *eptr;
2323
2324 value = strtoll(o->ptr, &eptr, 10);
2325 }
2326 }
2327
2328 value += incr;
2329 o = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
3305306f 2330 retval = dictAdd(c->db->dict,c->argv[1],o);
ed9b544e 2331 if (retval == DICT_ERR) {
3305306f 2332 dictReplace(c->db->dict,c->argv[1],o);
2333 removeExpire(c->db,c->argv[1]);
ed9b544e 2334 } else {
2335 incrRefCount(c->argv[1]);
2336 }
2337 server.dirty++;
c937aa89 2338 addReply(c,shared.colon);
ed9b544e 2339 addReply(c,o);
2340 addReply(c,shared.crlf);
2341}
2342
2343static void incrCommand(redisClient *c) {
a4d1ba9a 2344 incrDecrCommand(c,1);
ed9b544e 2345}
2346
2347static void decrCommand(redisClient *c) {
a4d1ba9a 2348 incrDecrCommand(c,-1);
ed9b544e 2349}
2350
2351static void incrbyCommand(redisClient *c) {
d68ed120 2352 long long incr = strtoll(c->argv[2]->ptr, NULL, 10);
a4d1ba9a 2353 incrDecrCommand(c,incr);
ed9b544e 2354}
2355
2356static void decrbyCommand(redisClient *c) {
d68ed120 2357 long long incr = strtoll(c->argv[2]->ptr, NULL, 10);
a4d1ba9a 2358 incrDecrCommand(c,-incr);
ed9b544e 2359}
2360
2361/* ========================= Type agnostic commands ========================= */
2362
2363static void delCommand(redisClient *c) {
5109cdff 2364 int deleted = 0, j;
2365
2366 for (j = 1; j < c->argc; j++) {
2367 if (deleteKey(c->db,c->argv[j])) {
2368 server.dirty++;
2369 deleted++;
2370 }
2371 }
2372 switch(deleted) {
2373 case 0:
c937aa89 2374 addReply(c,shared.czero);
5109cdff 2375 break;
2376 case 1:
2377 addReply(c,shared.cone);
2378 break;
2379 default:
2380 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",deleted));
2381 break;
ed9b544e 2382 }
2383}
2384
2385static void existsCommand(redisClient *c) {
3305306f 2386 addReply(c,lookupKeyRead(c->db,c->argv[1]) ? shared.cone : shared.czero);
ed9b544e 2387}
2388
2389static void selectCommand(redisClient *c) {
2390 int id = atoi(c->argv[1]->ptr);
2391
2392 if (selectDb(c,id) == REDIS_ERR) {
774e3047 2393 addReplySds(c,sdsnew("-ERR invalid DB index\r\n"));
ed9b544e 2394 } else {
2395 addReply(c,shared.ok);
2396 }
2397}
2398
2399static void randomkeyCommand(redisClient *c) {
2400 dictEntry *de;
3305306f 2401
2402 while(1) {
2403 de = dictGetRandomKey(c->db->dict);
ce7bef07 2404 if (!de || expireIfNeeded(c->db,dictGetEntryKey(de)) == 0) break;
3305306f 2405 }
ed9b544e 2406 if (de == NULL) {
ce7bef07 2407 addReply(c,shared.plus);
ed9b544e 2408 addReply(c,shared.crlf);
2409 } else {
c937aa89 2410 addReply(c,shared.plus);
ed9b544e 2411 addReply(c,dictGetEntryKey(de));
2412 addReply(c,shared.crlf);
2413 }
2414}
2415
2416static void keysCommand(redisClient *c) {
2417 dictIterator *di;
2418 dictEntry *de;
2419 sds pattern = c->argv[1]->ptr;
2420 int plen = sdslen(pattern);
2421 int numkeys = 0, keyslen = 0;
2422 robj *lenobj = createObject(REDIS_STRING,NULL);
2423
3305306f 2424 di = dictGetIterator(c->db->dict);
ed9b544e 2425 if (!di) oom("dictGetIterator");
2426 addReply(c,lenobj);
2427 decrRefCount(lenobj);
2428 while((de = dictNext(di)) != NULL) {
2429 robj *keyobj = dictGetEntryKey(de);
3305306f 2430
ed9b544e 2431 sds key = keyobj->ptr;
2432 if ((pattern[0] == '*' && pattern[1] == '\0') ||
2433 stringmatchlen(pattern,plen,key,sdslen(key),0)) {
3305306f 2434 if (expireIfNeeded(c->db,keyobj) == 0) {
2435 if (numkeys != 0)
2436 addReply(c,shared.space);
2437 addReply(c,keyobj);
2438 numkeys++;
2439 keyslen += sdslen(key);
2440 }
ed9b544e 2441 }
2442 }
2443 dictReleaseIterator(di);
c937aa89 2444 lenobj->ptr = sdscatprintf(sdsempty(),"$%lu\r\n",keyslen+(numkeys ? (numkeys-1) : 0));
ed9b544e 2445 addReply(c,shared.crlf);
2446}
2447
2448static void dbsizeCommand(redisClient *c) {
2449 addReplySds(c,
3305306f 2450 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c->db->dict)));
ed9b544e 2451}
2452
2453static void lastsaveCommand(redisClient *c) {
2454 addReplySds(c,
c937aa89 2455 sdscatprintf(sdsempty(),":%lu\r\n",server.lastsave));
ed9b544e 2456}
2457
2458static void typeCommand(redisClient *c) {
3305306f 2459 robj *o;
ed9b544e 2460 char *type;
3305306f 2461
2462 o = lookupKeyRead(c->db,c->argv[1]);
2463 if (o == NULL) {
c937aa89 2464 type = "+none";
ed9b544e 2465 } else {
ed9b544e 2466 switch(o->type) {
c937aa89 2467 case REDIS_STRING: type = "+string"; break;
2468 case REDIS_LIST: type = "+list"; break;
2469 case REDIS_SET: type = "+set"; break;
ed9b544e 2470 default: type = "unknown"; break;
2471 }
2472 }
2473 addReplySds(c,sdsnew(type));
2474 addReply(c,shared.crlf);
2475}
2476
2477static void saveCommand(redisClient *c) {
05557f6d 2478 if (server.bgsaveinprogress) {
2479 addReplySds(c,sdsnew("-ERR background save in progress\r\n"));
2480 return;
2481 }
f78fd11b 2482 if (rdbSave(server.dbfilename) == REDIS_OK) {
ed9b544e 2483 addReply(c,shared.ok);
2484 } else {
2485 addReply(c,shared.err);
2486 }
2487}
2488
2489static void bgsaveCommand(redisClient *c) {
2490 if (server.bgsaveinprogress) {
2491 addReplySds(c,sdsnew("-ERR background save already in progress\r\n"));
2492 return;
2493 }
f78fd11b 2494 if (rdbSaveBackground(server.dbfilename) == REDIS_OK) {
ed9b544e 2495 addReply(c,shared.ok);
2496 } else {
2497 addReply(c,shared.err);
2498 }
2499}
2500
2501static void shutdownCommand(redisClient *c) {
2502 redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
6208b3a7 2503 /* XXX: TODO kill the child if there is a bgsave in progress */
f78fd11b 2504 if (rdbSave(server.dbfilename) == REDIS_OK) {
ed329fcf 2505 if (server.daemonize) {
b284af55 2506 unlink(server.pidfile);
ed329fcf 2507 }
b284af55 2508 redisLog(REDIS_WARNING,"%zu bytes used at exit",zmalloc_used_memory());
ed9b544e 2509 redisLog(REDIS_WARNING,"Server exit now, bye bye...");
2510 exit(1);
2511 } else {
2512 redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
2513 addReplySds(c,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
2514 }
2515}
2516
2517static void renameGenericCommand(redisClient *c, int nx) {
ed9b544e 2518 robj *o;
2519
2520 /* To use the same key as src and dst is probably an error */
2521 if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) {
c937aa89 2522 addReply(c,shared.sameobjecterr);
ed9b544e 2523 return;
2524 }
2525
3305306f 2526 o = lookupKeyWrite(c->db,c->argv[1]);
2527 if (o == NULL) {
c937aa89 2528 addReply(c,shared.nokeyerr);
ed9b544e 2529 return;
2530 }
ed9b544e 2531 incrRefCount(o);
3305306f 2532 deleteIfVolatile(c->db,c->argv[2]);
2533 if (dictAdd(c->db->dict,c->argv[2],o) == DICT_ERR) {
ed9b544e 2534 if (nx) {
2535 decrRefCount(o);
c937aa89 2536 addReply(c,shared.czero);
ed9b544e 2537 return;
2538 }
3305306f 2539 dictReplace(c->db->dict,c->argv[2],o);
ed9b544e 2540 } else {
2541 incrRefCount(c->argv[2]);
2542 }
3305306f 2543 deleteKey(c->db,c->argv[1]);
ed9b544e 2544 server.dirty++;
c937aa89 2545 addReply(c,nx ? shared.cone : shared.ok);
ed9b544e 2546}
2547
2548static void renameCommand(redisClient *c) {
2549 renameGenericCommand(c,0);
2550}
2551
2552static void renamenxCommand(redisClient *c) {
2553 renameGenericCommand(c,1);
2554}
2555
2556static void moveCommand(redisClient *c) {
3305306f 2557 robj *o;
2558 redisDb *src, *dst;
ed9b544e 2559 int srcid;
2560
2561 /* Obtain source and target DB pointers */
3305306f 2562 src = c->db;
2563 srcid = c->db->id;
ed9b544e 2564 if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) {
c937aa89 2565 addReply(c,shared.outofrangeerr);
ed9b544e 2566 return;
2567 }
3305306f 2568 dst = c->db;
2569 selectDb(c,srcid); /* Back to the source DB */
ed9b544e 2570
2571 /* If the user is moving using as target the same
2572 * DB as the source DB it is probably an error. */
2573 if (src == dst) {
c937aa89 2574 addReply(c,shared.sameobjecterr);
ed9b544e 2575 return;
2576 }
2577
2578 /* Check if the element exists and get a reference */
3305306f 2579 o = lookupKeyWrite(c->db,c->argv[1]);
2580 if (!o) {
c937aa89 2581 addReply(c,shared.czero);
ed9b544e 2582 return;
2583 }
2584
2585 /* Try to add the element to the target DB */
3305306f 2586 deleteIfVolatile(dst,c->argv[1]);
2587 if (dictAdd(dst->dict,c->argv[1],o) == DICT_ERR) {
c937aa89 2588 addReply(c,shared.czero);
ed9b544e 2589 return;
2590 }
3305306f 2591 incrRefCount(c->argv[1]);
ed9b544e 2592 incrRefCount(o);
2593
2594 /* OK! key moved, free the entry in the source DB */
3305306f 2595 deleteKey(src,c->argv[1]);
ed9b544e 2596 server.dirty++;
c937aa89 2597 addReply(c,shared.cone);
ed9b544e 2598}
2599
2600/* =================================== Lists ================================ */
2601static void pushGenericCommand(redisClient *c, int where) {
2602 robj *lobj;
ed9b544e 2603 list *list;
3305306f 2604
2605 lobj = lookupKeyWrite(c->db,c->argv[1]);
2606 if (lobj == NULL) {
ed9b544e 2607 lobj = createListObject();
2608 list = lobj->ptr;
2609 if (where == REDIS_HEAD) {
2610 if (!listAddNodeHead(list,c->argv[2])) oom("listAddNodeHead");
2611 } else {
2612 if (!listAddNodeTail(list,c->argv[2])) oom("listAddNodeTail");
2613 }
3305306f 2614 dictAdd(c->db->dict,c->argv[1],lobj);
ed9b544e 2615 incrRefCount(c->argv[1]);
2616 incrRefCount(c->argv[2]);
2617 } else {
ed9b544e 2618 if (lobj->type != REDIS_LIST) {
2619 addReply(c,shared.wrongtypeerr);
2620 return;
2621 }
2622 list = lobj->ptr;
2623 if (where == REDIS_HEAD) {
2624 if (!listAddNodeHead(list,c->argv[2])) oom("listAddNodeHead");
2625 } else {
2626 if (!listAddNodeTail(list,c->argv[2])) oom("listAddNodeTail");
2627 }
2628 incrRefCount(c->argv[2]);
2629 }
2630 server.dirty++;
2631 addReply(c,shared.ok);
2632}
2633
2634static void lpushCommand(redisClient *c) {
2635 pushGenericCommand(c,REDIS_HEAD);
2636}
2637
2638static void rpushCommand(redisClient *c) {
2639 pushGenericCommand(c,REDIS_TAIL);
2640}
2641
2642static void llenCommand(redisClient *c) {
3305306f 2643 robj *o;
ed9b544e 2644 list *l;
2645
3305306f 2646 o = lookupKeyRead(c->db,c->argv[1]);
2647 if (o == NULL) {
c937aa89 2648 addReply(c,shared.czero);
ed9b544e 2649 return;
2650 } else {
ed9b544e 2651 if (o->type != REDIS_LIST) {
c937aa89 2652 addReply(c,shared.wrongtypeerr);
ed9b544e 2653 } else {
2654 l = o->ptr;
c937aa89 2655 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",listLength(l)));
ed9b544e 2656 }
2657 }
2658}
2659
2660static void lindexCommand(redisClient *c) {
3305306f 2661 robj *o;
ed9b544e 2662 int index = atoi(c->argv[2]->ptr);
2663
3305306f 2664 o = lookupKeyRead(c->db,c->argv[1]);
2665 if (o == NULL) {
c937aa89 2666 addReply(c,shared.nullbulk);
ed9b544e 2667 } else {
ed9b544e 2668 if (o->type != REDIS_LIST) {
c937aa89 2669 addReply(c,shared.wrongtypeerr);
ed9b544e 2670 } else {
2671 list *list = o->ptr;
2672 listNode *ln;
2673
2674 ln = listIndex(list, index);
2675 if (ln == NULL) {
c937aa89 2676 addReply(c,shared.nullbulk);
ed9b544e 2677 } else {
2678 robj *ele = listNodeValue(ln);
c937aa89 2679 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele->ptr)));
ed9b544e 2680 addReply(c,ele);
2681 addReply(c,shared.crlf);
2682 }
2683 }
2684 }
2685}
2686
2687static void lsetCommand(redisClient *c) {
3305306f 2688 robj *o;
ed9b544e 2689 int index = atoi(c->argv[2]->ptr);
2690
3305306f 2691 o = lookupKeyWrite(c->db,c->argv[1]);
2692 if (o == NULL) {
ed9b544e 2693 addReply(c,shared.nokeyerr);
2694 } else {
ed9b544e 2695 if (o->type != REDIS_LIST) {
2696 addReply(c,shared.wrongtypeerr);
2697 } else {
2698 list *list = o->ptr;
2699 listNode *ln;
2700
2701 ln = listIndex(list, index);
2702 if (ln == NULL) {
c937aa89 2703 addReply(c,shared.outofrangeerr);
ed9b544e 2704 } else {
2705 robj *ele = listNodeValue(ln);
2706
2707 decrRefCount(ele);
2708 listNodeValue(ln) = c->argv[3];
2709 incrRefCount(c->argv[3]);
2710 addReply(c,shared.ok);
2711 server.dirty++;
2712 }
2713 }
2714 }
2715}
2716
2717static void popGenericCommand(redisClient *c, int where) {
3305306f 2718 robj *o;
2719
2720 o = lookupKeyWrite(c->db,c->argv[1]);
2721 if (o == NULL) {
c937aa89 2722 addReply(c,shared.nullbulk);
ed9b544e 2723 } else {
ed9b544e 2724 if (o->type != REDIS_LIST) {
c937aa89 2725 addReply(c,shared.wrongtypeerr);
ed9b544e 2726 } else {
2727 list *list = o->ptr;
2728 listNode *ln;
2729
2730 if (where == REDIS_HEAD)
2731 ln = listFirst(list);
2732 else
2733 ln = listLast(list);
2734
2735 if (ln == NULL) {
c937aa89 2736 addReply(c,shared.nullbulk);
ed9b544e 2737 } else {
2738 robj *ele = listNodeValue(ln);
c937aa89 2739 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele->ptr)));
ed9b544e 2740 addReply(c,ele);
2741 addReply(c,shared.crlf);
2742 listDelNode(list,ln);
2743 server.dirty++;
2744 }
2745 }
2746 }
2747}
2748
2749static void lpopCommand(redisClient *c) {
2750 popGenericCommand(c,REDIS_HEAD);
2751}
2752
2753static void rpopCommand(redisClient *c) {
2754 popGenericCommand(c,REDIS_TAIL);
2755}
2756
2757static void lrangeCommand(redisClient *c) {
3305306f 2758 robj *o;
ed9b544e 2759 int start = atoi(c->argv[2]->ptr);
2760 int end = atoi(c->argv[3]->ptr);
3305306f 2761
2762 o = lookupKeyRead(c->db,c->argv[1]);
2763 if (o == NULL) {
c937aa89 2764 addReply(c,shared.nullmultibulk);
ed9b544e 2765 } else {
ed9b544e 2766 if (o->type != REDIS_LIST) {
c937aa89 2767 addReply(c,shared.wrongtypeerr);
ed9b544e 2768 } else {
2769 list *list = o->ptr;
2770 listNode *ln;
2771 int llen = listLength(list);
2772 int rangelen, j;
2773 robj *ele;
2774
2775 /* convert negative indexes */
2776 if (start < 0) start = llen+start;
2777 if (end < 0) end = llen+end;
2778 if (start < 0) start = 0;
2779 if (end < 0) end = 0;
2780
2781 /* indexes sanity checks */
2782 if (start > end || start >= llen) {
2783 /* Out of range start or start > end result in empty list */
c937aa89 2784 addReply(c,shared.emptymultibulk);
ed9b544e 2785 return;
2786 }
2787 if (end >= llen) end = llen-1;
2788 rangelen = (end-start)+1;
2789
2790 /* Return the result in form of a multi-bulk reply */
2791 ln = listIndex(list, start);
c937aa89 2792 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen));
ed9b544e 2793 for (j = 0; j < rangelen; j++) {
2794 ele = listNodeValue(ln);
c937aa89 2795 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele->ptr)));
ed9b544e 2796 addReply(c,ele);
2797 addReply(c,shared.crlf);
2798 ln = ln->next;
2799 }
2800 }
2801 }
2802}
2803
2804static void ltrimCommand(redisClient *c) {
3305306f 2805 robj *o;
ed9b544e 2806 int start = atoi(c->argv[2]->ptr);
2807 int end = atoi(c->argv[3]->ptr);
2808
3305306f 2809 o = lookupKeyWrite(c->db,c->argv[1]);
2810 if (o == NULL) {
ed9b544e 2811 addReply(c,shared.nokeyerr);
2812 } else {
ed9b544e 2813 if (o->type != REDIS_LIST) {
2814 addReply(c,shared.wrongtypeerr);
2815 } else {
2816 list *list = o->ptr;
2817 listNode *ln;
2818 int llen = listLength(list);
2819 int j, ltrim, rtrim;
2820
2821 /* convert negative indexes */
2822 if (start < 0) start = llen+start;
2823 if (end < 0) end = llen+end;
2824 if (start < 0) start = 0;
2825 if (end < 0) end = 0;
2826
2827 /* indexes sanity checks */
2828 if (start > end || start >= llen) {
2829 /* Out of range start or start > end result in empty list */
2830 ltrim = llen;
2831 rtrim = 0;
2832 } else {
2833 if (end >= llen) end = llen-1;
2834 ltrim = start;
2835 rtrim = llen-end-1;
2836 }
2837
2838 /* Remove list elements to perform the trim */
2839 for (j = 0; j < ltrim; j++) {
2840 ln = listFirst(list);
2841 listDelNode(list,ln);
2842 }
2843 for (j = 0; j < rtrim; j++) {
2844 ln = listLast(list);
2845 listDelNode(list,ln);
2846 }
2847 addReply(c,shared.ok);
2848 server.dirty++;
2849 }
2850 }
2851}
2852
2853static void lremCommand(redisClient *c) {
3305306f 2854 robj *o;
ed9b544e 2855
3305306f 2856 o = lookupKeyWrite(c->db,c->argv[1]);
2857 if (o == NULL) {
7b45bfb2 2858 addReply(c,shared.nokeyerr);
ed9b544e 2859 } else {
ed9b544e 2860 if (o->type != REDIS_LIST) {
c937aa89 2861 addReply(c,shared.wrongtypeerr);
ed9b544e 2862 } else {
2863 list *list = o->ptr;
2864 listNode *ln, *next;
2865 int toremove = atoi(c->argv[2]->ptr);
2866 int removed = 0;
2867 int fromtail = 0;
2868
2869 if (toremove < 0) {
2870 toremove = -toremove;
2871 fromtail = 1;
2872 }
2873 ln = fromtail ? list->tail : list->head;
2874 while (ln) {
ed9b544e 2875 robj *ele = listNodeValue(ln);
a4d1ba9a 2876
2877 next = fromtail ? ln->prev : ln->next;
ed9b544e 2878 if (sdscmp(ele->ptr,c->argv[3]->ptr) == 0) {
2879 listDelNode(list,ln);
2880 server.dirty++;
2881 removed++;
2882 if (toremove && removed == toremove) break;
2883 }
2884 ln = next;
2885 }
c937aa89 2886 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",removed));
ed9b544e 2887 }
2888 }
2889}
2890
2891/* ==================================== Sets ================================ */
2892
2893static void saddCommand(redisClient *c) {
ed9b544e 2894 robj *set;
2895
3305306f 2896 set = lookupKeyWrite(c->db,c->argv[1]);
2897 if (set == NULL) {
ed9b544e 2898 set = createSetObject();
3305306f 2899 dictAdd(c->db->dict,c->argv[1],set);
ed9b544e 2900 incrRefCount(c->argv[1]);
2901 } else {
ed9b544e 2902 if (set->type != REDIS_SET) {
c937aa89 2903 addReply(c,shared.wrongtypeerr);
ed9b544e 2904 return;
2905 }
2906 }
2907 if (dictAdd(set->ptr,c->argv[2],NULL) == DICT_OK) {
2908 incrRefCount(c->argv[2]);
2909 server.dirty++;
c937aa89 2910 addReply(c,shared.cone);
ed9b544e 2911 } else {
c937aa89 2912 addReply(c,shared.czero);
ed9b544e 2913 }
2914}
2915
2916static void sremCommand(redisClient *c) {
3305306f 2917 robj *set;
ed9b544e 2918
3305306f 2919 set = lookupKeyWrite(c->db,c->argv[1]);
2920 if (set == NULL) {
c937aa89 2921 addReply(c,shared.czero);
ed9b544e 2922 } else {
ed9b544e 2923 if (set->type != REDIS_SET) {
c937aa89 2924 addReply(c,shared.wrongtypeerr);
ed9b544e 2925 return;
2926 }
2927 if (dictDelete(set->ptr,c->argv[2]) == DICT_OK) {
2928 server.dirty++;
c937aa89 2929 addReply(c,shared.cone);
ed9b544e 2930 } else {
c937aa89 2931 addReply(c,shared.czero);
ed9b544e 2932 }
2933 }
2934}
2935
a4460ef4 2936static void smoveCommand(redisClient *c) {
2937 robj *srcset, *dstset;
2938
2939 srcset = lookupKeyWrite(c->db,c->argv[1]);
2940 dstset = lookupKeyWrite(c->db,c->argv[2]);
2941
2942 /* If the source key does not exist return 0, if it's of the wrong type
2943 * raise an error */
2944 if (srcset == NULL || srcset->type != REDIS_SET) {
2945 addReply(c, srcset ? shared.wrongtypeerr : shared.czero);
2946 return;
2947 }
2948 /* Error if the destination key is not a set as well */
2949 if (dstset && dstset->type != REDIS_SET) {
2950 addReply(c,shared.wrongtypeerr);
2951 return;
2952 }
2953 /* Remove the element from the source set */
2954 if (dictDelete(srcset->ptr,c->argv[3]) == DICT_ERR) {
2955 /* Key not found in the src set! return zero */
2956 addReply(c,shared.czero);
2957 return;
2958 }
2959 server.dirty++;
2960 /* Add the element to the destination set */
2961 if (!dstset) {
2962 dstset = createSetObject();
2963 dictAdd(c->db->dict,c->argv[2],dstset);
2964 incrRefCount(c->argv[2]);
2965 }
2966 if (dictAdd(dstset->ptr,c->argv[3],NULL) == DICT_OK)
2967 incrRefCount(c->argv[3]);
2968 addReply(c,shared.cone);
2969}
2970
ed9b544e 2971static void sismemberCommand(redisClient *c) {
3305306f 2972 robj *set;
ed9b544e 2973
3305306f 2974 set = lookupKeyRead(c->db,c->argv[1]);
2975 if (set == NULL) {
c937aa89 2976 addReply(c,shared.czero);
ed9b544e 2977 } else {
ed9b544e 2978 if (set->type != REDIS_SET) {
c937aa89 2979 addReply(c,shared.wrongtypeerr);
ed9b544e 2980 return;
2981 }
2982 if (dictFind(set->ptr,c->argv[2]))
c937aa89 2983 addReply(c,shared.cone);
ed9b544e 2984 else
c937aa89 2985 addReply(c,shared.czero);
ed9b544e 2986 }
2987}
2988
2989static void scardCommand(redisClient *c) {
3305306f 2990 robj *o;
ed9b544e 2991 dict *s;
2992
3305306f 2993 o = lookupKeyRead(c->db,c->argv[1]);
2994 if (o == NULL) {
c937aa89 2995 addReply(c,shared.czero);
ed9b544e 2996 return;
2997 } else {
ed9b544e 2998 if (o->type != REDIS_SET) {
c937aa89 2999 addReply(c,shared.wrongtypeerr);
ed9b544e 3000 } else {
3001 s = o->ptr;
c937aa89 3002 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",
3305306f 3003 dictSize(s)));
ed9b544e 3004 }
3005 }
3006}
3007
3008static int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
3009 dict **d1 = (void*) s1, **d2 = (void*) s2;
3010
3305306f 3011 return dictSize(*d1)-dictSize(*d2);
ed9b544e 3012}
3013
3014static void sinterGenericCommand(redisClient *c, robj **setskeys, int setsnum, robj *dstkey) {
3015 dict **dv = zmalloc(sizeof(dict*)*setsnum);
3016 dictIterator *di;
3017 dictEntry *de;
3018 robj *lenobj = NULL, *dstset = NULL;
3019 int j, cardinality = 0;
3020
3ba37089 3021 if (!dv) oom("sinterGenericCommand");
ed9b544e 3022 for (j = 0; j < setsnum; j++) {
3023 robj *setobj;
3305306f 3024
3025 setobj = dstkey ?
3026 lookupKeyWrite(c->db,setskeys[j]) :
3027 lookupKeyRead(c->db,setskeys[j]);
3028 if (!setobj) {
ed9b544e 3029 zfree(dv);
5faa6025 3030 if (dstkey) {
3031 deleteKey(c->db,dstkey);
3032 addReply(c,shared.ok);
3033 } else {
3034 addReply(c,shared.nullmultibulk);
3035 }
ed9b544e 3036 return;
3037 }
ed9b544e 3038 if (setobj->type != REDIS_SET) {
3039 zfree(dv);
c937aa89 3040 addReply(c,shared.wrongtypeerr);
ed9b544e 3041 return;
3042 }
3043 dv[j] = setobj->ptr;
3044 }
3045 /* Sort sets from the smallest to largest, this will improve our
3046 * algorithm's performace */
3047 qsort(dv,setsnum,sizeof(dict*),qsortCompareSetsByCardinality);
3048
3049 /* The first thing we should output is the total number of elements...
3050 * since this is a multi-bulk write, but at this stage we don't know
3051 * the intersection set size, so we use a trick, append an empty object
3052 * to the output list and save the pointer to later modify it with the
3053 * right length */
3054 if (!dstkey) {
3055 lenobj = createObject(REDIS_STRING,NULL);
3056 addReply(c,lenobj);
3057 decrRefCount(lenobj);
3058 } else {
3059 /* If we have a target key where to store the resulting set
3060 * create this key with an empty set inside */
3061 dstset = createSetObject();
ed9b544e 3062 }
3063
3064 /* Iterate all the elements of the first (smallest) set, and test
3065 * the element against all the other sets, if at least one set does
3066 * not include the element it is discarded */
3067 di = dictGetIterator(dv[0]);
3068 if (!di) oom("dictGetIterator");
3069
3070 while((de = dictNext(di)) != NULL) {
3071 robj *ele;
3072
3073 for (j = 1; j < setsnum; j++)
3074 if (dictFind(dv[j],dictGetEntryKey(de)) == NULL) break;
3075 if (j != setsnum)
3076 continue; /* at least one set does not contain the member */
3077 ele = dictGetEntryKey(de);
3078 if (!dstkey) {
c937aa89 3079 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(ele->ptr)));
ed9b544e 3080 addReply(c,ele);
3081 addReply(c,shared.crlf);
3082 cardinality++;
3083 } else {
3084 dictAdd(dstset->ptr,ele,NULL);
3085 incrRefCount(ele);
3086 }
3087 }
3088 dictReleaseIterator(di);
3089
83cdfe18
AG
3090 if (dstkey) {
3091 /* Store the resulting set into the target */
3092 deleteKey(c->db,dstkey);
3093 dictAdd(c->db->dict,dstkey,dstset);
3094 incrRefCount(dstkey);
3095 }
3096
40d224a9 3097 if (!dstkey) {
c937aa89 3098 lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",cardinality);
40d224a9 3099 } else {
03fd01c7 3100 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",
3101 dictSize((dict*)dstset->ptr)));
40d224a9 3102 server.dirty++;
3103 }
ed9b544e 3104 zfree(dv);
3105}
3106
3107static void sinterCommand(redisClient *c) {
3108 sinterGenericCommand(c,c->argv+1,c->argc-1,NULL);
3109}
3110
3111static void sinterstoreCommand(redisClient *c) {
3112 sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
3113}
3114
f4f56e1d 3115#define REDIS_OP_UNION 0
3116#define REDIS_OP_DIFF 1
3117
3118static void sunionDiffGenericCommand(redisClient *c, robj **setskeys, int setsnum, robj *dstkey, int op) {
40d224a9 3119 dict **dv = zmalloc(sizeof(dict*)*setsnum);
3120 dictIterator *di;
3121 dictEntry *de;
f4f56e1d 3122 robj *dstset = NULL;
40d224a9 3123 int j, cardinality = 0;
3124
f4f56e1d 3125 if (!dv) oom("sunionDiffGenericCommand");
40d224a9 3126 for (j = 0; j < setsnum; j++) {
3127 robj *setobj;
3128
3129 setobj = dstkey ?
3130 lookupKeyWrite(c->db,setskeys[j]) :
3131 lookupKeyRead(c->db,setskeys[j]);
3132 if (!setobj) {
3133 dv[j] = NULL;
3134 continue;
3135 }
3136 if (setobj->type != REDIS_SET) {
3137 zfree(dv);
3138 addReply(c,shared.wrongtypeerr);
3139 return;
3140 }
3141 dv[j] = setobj->ptr;
3142 }
3143
3144 /* We need a temp set object to store our union. If the dstkey
3145 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
3146 * this set object will be the resulting object to set into the target key*/
3147 dstset = createSetObject();
3148
40d224a9 3149 /* Iterate all the elements of all the sets, add every element a single
3150 * time to the result set */
3151 for (j = 0; j < setsnum; j++) {
51829ed3 3152 if (op == REDIS_OP_DIFF && j == 0 && !dv[j]) break; /* result set is empty */
40d224a9 3153 if (!dv[j]) continue; /* non existing keys are like empty sets */
3154
3155 di = dictGetIterator(dv[j]);
3156 if (!di) oom("dictGetIterator");
3157
3158 while((de = dictNext(di)) != NULL) {
3159 robj *ele;
3160
3161 /* dictAdd will not add the same element multiple times */
3162 ele = dictGetEntryKey(de);
f4f56e1d 3163 if (op == REDIS_OP_UNION || j == 0) {
3164 if (dictAdd(dstset->ptr,ele,NULL) == DICT_OK) {
3165 incrRefCount(ele);
40d224a9 3166 cardinality++;
3167 }
f4f56e1d 3168 } else if (op == REDIS_OP_DIFF) {
3169 if (dictDelete(dstset->ptr,ele) == DICT_OK) {
3170 cardinality--;
3171 }
40d224a9 3172 }
3173 }
3174 dictReleaseIterator(di);
51829ed3
AG
3175
3176 if (op == REDIS_OP_DIFF && cardinality == 0) break; /* result set is empty */
40d224a9 3177 }
3178
f4f56e1d 3179 /* Output the content of the resulting set, if not in STORE mode */
3180 if (!dstkey) {
3181 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",cardinality));
3182 di = dictGetIterator(dstset->ptr);
3183 if (!di) oom("dictGetIterator");
3184 while((de = dictNext(di)) != NULL) {
3185 robj *ele;
3186
3187 ele = dictGetEntryKey(de);
3188 addReplySds(c,sdscatprintf(sdsempty(),
3189 "$%d\r\n",sdslen(ele->ptr)));
3190 addReply(c,ele);
3191 addReply(c,shared.crlf);
3192 }
3193 dictReleaseIterator(di);
83cdfe18
AG
3194 } else {
3195 /* If we have a target key where to store the resulting set
3196 * create this key with the result set inside */
3197 deleteKey(c->db,dstkey);
3198 dictAdd(c->db->dict,dstkey,dstset);
3199 incrRefCount(dstkey);
f4f56e1d 3200 }
3201
3202 /* Cleanup */
40d224a9 3203 if (!dstkey) {
40d224a9 3204 decrRefCount(dstset);
3205 } else {
03fd01c7 3206 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",
3207 dictSize((dict*)dstset->ptr)));
40d224a9 3208 server.dirty++;
3209 }
3210 zfree(dv);
3211}
3212
3213static void sunionCommand(redisClient *c) {
f4f56e1d 3214 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_UNION);
40d224a9 3215}
3216
3217static void sunionstoreCommand(redisClient *c) {
f4f56e1d 3218 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_UNION);
3219}
3220
3221static void sdiffCommand(redisClient *c) {
3222 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_DIFF);
3223}
3224
3225static void sdiffstoreCommand(redisClient *c) {
3226 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_DIFF);
40d224a9 3227}
3228
ed9b544e 3229static void flushdbCommand(redisClient *c) {
ca37e9cd 3230 server.dirty += dictSize(c->db->dict);
3305306f 3231 dictEmpty(c->db->dict);
3232 dictEmpty(c->db->expires);
ed9b544e 3233 addReply(c,shared.ok);
ed9b544e 3234}
3235
3236static void flushallCommand(redisClient *c) {
ca37e9cd 3237 server.dirty += emptyDb();
ed9b544e 3238 addReply(c,shared.ok);
f78fd11b 3239 rdbSave(server.dbfilename);
ca37e9cd 3240 server.dirty++;
ed9b544e 3241}
3242
3243redisSortOperation *createSortOperation(int type, robj *pattern) {
3244 redisSortOperation *so = zmalloc(sizeof(*so));
3245 if (!so) oom("createSortOperation");
3246 so->type = type;
3247 so->pattern = pattern;
3248 return so;
3249}
3250
3251/* Return the value associated to the key with a name obtained
3252 * substituting the first occurence of '*' in 'pattern' with 'subst' */
3305306f 3253robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
ed9b544e 3254 char *p;
3255 sds spat, ssub;
3256 robj keyobj;
3257 int prefixlen, sublen, postfixlen;
ed9b544e 3258 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
3259 struct {
3260 long len;
3261 long free;
3262 char buf[REDIS_SORTKEY_MAX+1];
3263 } keyname;
3264
ed9b544e 3265 spat = pattern->ptr;
3266 ssub = subst->ptr;
3267 if (sdslen(spat)+sdslen(ssub)-1 > REDIS_SORTKEY_MAX) return NULL;
3268 p = strchr(spat,'*');
3269 if (!p) return NULL;
3270
3271 prefixlen = p-spat;
3272 sublen = sdslen(ssub);
3273 postfixlen = sdslen(spat)-(prefixlen+1);
3274 memcpy(keyname.buf,spat,prefixlen);
3275 memcpy(keyname.buf+prefixlen,ssub,sublen);
3276 memcpy(keyname.buf+prefixlen+sublen,p+1,postfixlen);
3277 keyname.buf[prefixlen+sublen+postfixlen] = '\0';
3278 keyname.len = prefixlen+sublen+postfixlen;
3279
3280 keyobj.refcount = 1;
3281 keyobj.type = REDIS_STRING;
3282 keyobj.ptr = ((char*)&keyname)+(sizeof(long)*2);
3283
a4d1ba9a 3284 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
3305306f 3285 return lookupKeyRead(db,&keyobj);
ed9b544e 3286}
3287
3288/* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
3289 * the additional parameter is not standard but a BSD-specific we have to
3290 * pass sorting parameters via the global 'server' structure */
3291static int sortCompare(const void *s1, const void *s2) {
3292 const redisSortObject *so1 = s1, *so2 = s2;
3293 int cmp;
3294
3295 if (!server.sort_alpha) {
3296 /* Numeric sorting. Here it's trivial as we precomputed scores */
3297 if (so1->u.score > so2->u.score) {
3298 cmp = 1;
3299 } else if (so1->u.score < so2->u.score) {
3300 cmp = -1;
3301 } else {
3302 cmp = 0;
3303 }
3304 } else {
3305 /* Alphanumeric sorting */
3306 if (server.sort_bypattern) {
3307 if (!so1->u.cmpobj || !so2->u.cmpobj) {
3308 /* At least one compare object is NULL */
3309 if (so1->u.cmpobj == so2->u.cmpobj)
3310 cmp = 0;
3311 else if (so1->u.cmpobj == NULL)
3312 cmp = -1;
3313 else
3314 cmp = 1;
3315 } else {
3316 /* We have both the objects, use strcoll */
3317 cmp = strcoll(so1->u.cmpobj->ptr,so2->u.cmpobj->ptr);
3318 }
3319 } else {
3320 /* Compare elements directly */
3321 cmp = strcoll(so1->obj->ptr,so2->obj->ptr);
3322 }
3323 }
3324 return server.sort_desc ? -cmp : cmp;
3325}
3326
3327/* The SORT command is the most complex command in Redis. Warning: this code
3328 * is optimized for speed and a bit less for readability */
3329static void sortCommand(redisClient *c) {
ed9b544e 3330 list *operations;
3331 int outputlen = 0;
3332 int desc = 0, alpha = 0;
3333 int limit_start = 0, limit_count = -1, start, end;
3334 int j, dontsort = 0, vectorlen;
3335 int getop = 0; /* GET operation counter */
3336 robj *sortval, *sortby = NULL;
3337 redisSortObject *vector; /* Resulting vector to sort */
3338
3339 /* Lookup the key to sort. It must be of the right types */
3305306f 3340 sortval = lookupKeyRead(c->db,c->argv[1]);
3341 if (sortval == NULL) {
c937aa89 3342 addReply(c,shared.nokeyerr);
ed9b544e 3343 return;
3344 }
ed9b544e 3345 if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST) {
c937aa89 3346 addReply(c,shared.wrongtypeerr);
ed9b544e 3347 return;
3348 }
3349
3350 /* Create a list of operations to perform for every sorted element.
3351 * Operations can be GET/DEL/INCR/DECR */
3352 operations = listCreate();
092dac2a 3353 listSetFreeMethod(operations,zfree);
ed9b544e 3354 j = 2;
3355
3356 /* Now we need to protect sortval incrementing its count, in the future
3357 * SORT may have options able to overwrite/delete keys during the sorting
3358 * and the sorted key itself may get destroied */
3359 incrRefCount(sortval);
3360
3361 /* The SORT command has an SQL-alike syntax, parse it */
3362 while(j < c->argc) {
3363 int leftargs = c->argc-j-1;
3364 if (!strcasecmp(c->argv[j]->ptr,"asc")) {
3365 desc = 0;
3366 } else if (!strcasecmp(c->argv[j]->ptr,"desc")) {
3367 desc = 1;
3368 } else if (!strcasecmp(c->argv[j]->ptr,"alpha")) {
3369 alpha = 1;
3370 } else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) {
3371 limit_start = atoi(c->argv[j+1]->ptr);
3372 limit_count = atoi(c->argv[j+2]->ptr);
3373 j+=2;
3374 } else if (!strcasecmp(c->argv[j]->ptr,"by") && leftargs >= 1) {
3375 sortby = c->argv[j+1];
3376 /* If the BY pattern does not contain '*', i.e. it is constant,
3377 * we don't need to sort nor to lookup the weight keys. */
3378 if (strchr(c->argv[j+1]->ptr,'*') == NULL) dontsort = 1;
3379 j++;
3380 } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
3381 listAddNodeTail(operations,createSortOperation(
3382 REDIS_SORT_GET,c->argv[j+1]));
3383 getop++;
3384 j++;
3385 } else if (!strcasecmp(c->argv[j]->ptr,"del") && leftargs >= 1) {
3386 listAddNodeTail(operations,createSortOperation(
3387 REDIS_SORT_DEL,c->argv[j+1]));
3388 j++;
3389 } else if (!strcasecmp(c->argv[j]->ptr,"incr") && leftargs >= 1) {
3390 listAddNodeTail(operations,createSortOperation(
3391 REDIS_SORT_INCR,c->argv[j+1]));
3392 j++;
3393 } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
3394 listAddNodeTail(operations,createSortOperation(
3395 REDIS_SORT_DECR,c->argv[j+1]));
3396 j++;
3397 } else {
3398 decrRefCount(sortval);
3399 listRelease(operations);
c937aa89 3400 addReply(c,shared.syntaxerr);
ed9b544e 3401 return;
3402 }
3403 j++;
3404 }
3405
3406 /* Load the sorting vector with all the objects to sort */
3407 vectorlen = (sortval->type == REDIS_LIST) ?
3408 listLength((list*)sortval->ptr) :
3305306f 3409 dictSize((dict*)sortval->ptr);
ed9b544e 3410 vector = zmalloc(sizeof(redisSortObject)*vectorlen);
3411 if (!vector) oom("allocating objects vector for SORT");
3412 j = 0;
3413 if (sortval->type == REDIS_LIST) {
3414 list *list = sortval->ptr;
6208b3a7 3415 listNode *ln;
3416
3417 listRewind(list);
3418 while((ln = listYield(list))) {
ed9b544e 3419 robj *ele = ln->value;
3420 vector[j].obj = ele;
3421 vector[j].u.score = 0;
3422 vector[j].u.cmpobj = NULL;
ed9b544e 3423 j++;
3424 }
3425 } else {
3426 dict *set = sortval->ptr;
3427 dictIterator *di;
3428 dictEntry *setele;
3429
3430 di = dictGetIterator(set);
3431 if (!di) oom("dictGetIterator");
3432 while((setele = dictNext(di)) != NULL) {
3433 vector[j].obj = dictGetEntryKey(setele);
3434 vector[j].u.score = 0;
3435 vector[j].u.cmpobj = NULL;
3436 j++;
3437 }
3438 dictReleaseIterator(di);
3439 }
3440 assert(j == vectorlen);
3441
3442 /* Now it's time to load the right scores in the sorting vector */
3443 if (dontsort == 0) {
3444 for (j = 0; j < vectorlen; j++) {
3445 if (sortby) {
3446 robj *byval;
3447
3305306f 3448 byval = lookupKeyByPattern(c->db,sortby,vector[j].obj);
ed9b544e 3449 if (!byval || byval->type != REDIS_STRING) continue;
3450 if (alpha) {
3451 vector[j].u.cmpobj = byval;
3452 incrRefCount(byval);
3453 } else {
3454 vector[j].u.score = strtod(byval->ptr,NULL);
3455 }
3456 } else {
3457 if (!alpha) vector[j].u.score = strtod(vector[j].obj->ptr,NULL);
3458 }
3459 }
3460 }
3461
3462 /* We are ready to sort the vector... perform a bit of sanity check
3463 * on the LIMIT option too. We'll use a partial version of quicksort. */
3464 start = (limit_start < 0) ? 0 : limit_start;
3465 end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1;
3466 if (start >= vectorlen) {
3467 start = vectorlen-1;
3468 end = vectorlen-2;
3469 }
3470 if (end >= vectorlen) end = vectorlen-1;
3471
3472 if (dontsort == 0) {
3473 server.sort_desc = desc;
3474 server.sort_alpha = alpha;
3475 server.sort_bypattern = sortby ? 1 : 0;
5f5b9840 3476 if (sortby && (start != 0 || end != vectorlen-1))
3477 pqsort(vector,vectorlen,sizeof(redisSortObject),sortCompare, start,end);
3478 else
3479 qsort(vector,vectorlen,sizeof(redisSortObject),sortCompare);
ed9b544e 3480 }
3481
3482 /* Send command output to the output buffer, performing the specified
3483 * GET/DEL/INCR/DECR operations if any. */
3484 outputlen = getop ? getop*(end-start+1) : end-start+1;
c937aa89 3485 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",outputlen));
ed9b544e 3486 for (j = start; j <= end; j++) {
6208b3a7 3487 listNode *ln;
ed9b544e 3488 if (!getop) {
c937aa89 3489 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",
ed9b544e 3490 sdslen(vector[j].obj->ptr)));
3491 addReply(c,vector[j].obj);
3492 addReply(c,shared.crlf);
3493 }
6208b3a7 3494 listRewind(operations);
3495 while((ln = listYield(operations))) {
ed9b544e 3496 redisSortOperation *sop = ln->value;
3305306f 3497 robj *val = lookupKeyByPattern(c->db,sop->pattern,
ed9b544e 3498 vector[j].obj);
3499
3500 if (sop->type == REDIS_SORT_GET) {
3501 if (!val || val->type != REDIS_STRING) {
9eb00f21 3502 addReply(c,shared.nullbulk);
ed9b544e 3503 } else {
c937aa89 3504 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",
ed9b544e 3505 sdslen(val->ptr)));
3506 addReply(c,val);
3507 addReply(c,shared.crlf);
3508 }
3509 } else if (sop->type == REDIS_SORT_DEL) {
3510 /* TODO */
3511 }
ed9b544e 3512 }
3513 }
3514
3515 /* Cleanup */
3516 decrRefCount(sortval);
3517 listRelease(operations);
3518 for (j = 0; j < vectorlen; j++) {
3519 if (sortby && alpha && vector[j].u.cmpobj)
3520 decrRefCount(vector[j].u.cmpobj);
3521 }
3522 zfree(vector);
3523}
3524
3525static void infoCommand(redisClient *c) {
3526 sds info;
3527 time_t uptime = time(NULL)-server.stat_starttime;
3528
3529 info = sdscatprintf(sdsempty(),
3530 "redis_version:%s\r\n"
a0f643ea 3531 "uptime_in_seconds:%d\r\n"
3532 "uptime_in_days:%d\r\n"
ed9b544e 3533 "connected_clients:%d\r\n"
3534 "connected_slaves:%d\r\n"
5fba9f71 3535 "used_memory:%zu\r\n"
ed9b544e 3536 "changes_since_last_save:%lld\r\n"
be2bb6b0 3537 "bgsave_in_progress:%d\r\n"
ed9b544e 3538 "last_save_time:%d\r\n"
3539 "total_connections_received:%lld\r\n"
3540 "total_commands_processed:%lld\r\n"
a0f643ea 3541 "role:%s\r\n"
ed9b544e 3542 ,REDIS_VERSION,
a0f643ea 3543 uptime,
3544 uptime/(3600*24),
ed9b544e 3545 listLength(server.clients)-listLength(server.slaves),
3546 listLength(server.slaves),
3547 server.usedmemory,
3548 server.dirty,
be2bb6b0 3549 server.bgsaveinprogress,
ed9b544e 3550 server.lastsave,
3551 server.stat_numconnections,
3552 server.stat_numcommands,
a0f643ea 3553 server.masterhost == NULL ? "master" : "slave"
ed9b544e 3554 );
a0f643ea 3555 if (server.masterhost) {
3556 info = sdscatprintf(info,
3557 "master_host:%s\r\n"
3558 "master_port:%d\r\n"
3559 "master_link_status:%s\r\n"
3560 "master_last_io_seconds_ago:%d\r\n"
3561 ,server.masterhost,
3562 server.masterport,
3563 (server.replstate == REDIS_REPL_CONNECTED) ?
3564 "up" : "down",
3565 (int)(time(NULL)-server.master->lastinteraction)
3566 );
3567 }
c937aa89 3568 addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(info)));
ed9b544e 3569 addReplySds(c,info);
70003d28 3570 addReply(c,shared.crlf);
ed9b544e 3571}
3572
3305306f 3573static void monitorCommand(redisClient *c) {
3574 /* ignore MONITOR if aleady slave or in monitor mode */
3575 if (c->flags & REDIS_SLAVE) return;
3576
3577 c->flags |= (REDIS_SLAVE|REDIS_MONITOR);
3578 c->slaveseldb = 0;
3579 if (!listAddNodeTail(server.monitors,c)) oom("listAddNodeTail");
3580 addReply(c,shared.ok);
3581}
3582
3583/* ================================= Expire ================================= */
3584static int removeExpire(redisDb *db, robj *key) {
3585 if (dictDelete(db->expires,key) == DICT_OK) {
3586 return 1;
3587 } else {
3588 return 0;
3589 }
3590}
3591
3592static int setExpire(redisDb *db, robj *key, time_t when) {
3593 if (dictAdd(db->expires,key,(void*)when) == DICT_ERR) {
3594 return 0;
3595 } else {
3596 incrRefCount(key);
3597 return 1;
3598 }
3599}
3600
bb32ede5 3601/* Return the expire time of the specified key, or -1 if no expire
3602 * is associated with this key (i.e. the key is non volatile) */
3603static time_t getExpire(redisDb *db, robj *key) {
3604 dictEntry *de;
3605
3606 /* No expire? return ASAP */
3607 if (dictSize(db->expires) == 0 ||
3608 (de = dictFind(db->expires,key)) == NULL) return -1;
3609
3610 return (time_t) dictGetEntryVal(de);
3611}
3612
3305306f 3613static int expireIfNeeded(redisDb *db, robj *key) {
3614 time_t when;
3615 dictEntry *de;
3616
3617 /* No expire? return ASAP */
3618 if (dictSize(db->expires) == 0 ||
3619 (de = dictFind(db->expires,key)) == NULL) return 0;
3620
3621 /* Lookup the expire */
3622 when = (time_t) dictGetEntryVal(de);
3623 if (time(NULL) <= when) return 0;
3624
3625 /* Delete the key */
3626 dictDelete(db->expires,key);
3627 return dictDelete(db->dict,key) == DICT_OK;
3628}
3629
3630static int deleteIfVolatile(redisDb *db, robj *key) {
3631 dictEntry *de;
3632
3633 /* No expire? return ASAP */
3634 if (dictSize(db->expires) == 0 ||
3635 (de = dictFind(db->expires,key)) == NULL) return 0;
3636
3637 /* Delete the key */
0c66a471 3638 server.dirty++;
3305306f 3639 dictDelete(db->expires,key);
3640 return dictDelete(db->dict,key) == DICT_OK;
3641}
3642
3643static void expireCommand(redisClient *c) {
3644 dictEntry *de;
3645 int seconds = atoi(c->argv[2]->ptr);
3646
3647 de = dictFind(c->db->dict,c->argv[1]);
3648 if (de == NULL) {
3649 addReply(c,shared.czero);
3650 return;
3651 }
3652 if (seconds <= 0) {
3653 addReply(c, shared.czero);
3654 return;
3655 } else {
3656 time_t when = time(NULL)+seconds;
3657 if (setExpire(c->db,c->argv[1],when))
3658 addReply(c,shared.cone);
3659 else
3660 addReply(c,shared.czero);
3661 return;
3662 }
3663}
3664
fd88489a 3665static void ttlCommand(redisClient *c) {
3666 time_t expire;
3667 int ttl = -1;
3668
3669 expire = getExpire(c->db,c->argv[1]);
3670 if (expire != -1) {
3671 ttl = (int) (expire-time(NULL));
3672 if (ttl < 0) ttl = -1;
3673 }
3674 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",ttl));
3675}
3676
ed9b544e 3677/* =============================== Replication ============================= */
3678
a4d1ba9a 3679static int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 3680 ssize_t nwritten, ret = size;
3681 time_t start = time(NULL);
3682
3683 timeout++;
3684 while(size) {
3685 if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
3686 nwritten = write(fd,ptr,size);
3687 if (nwritten == -1) return -1;
3688 ptr += nwritten;
3689 size -= nwritten;
3690 }
3691 if ((time(NULL)-start) > timeout) {
3692 errno = ETIMEDOUT;
3693 return -1;
3694 }
3695 }
3696 return ret;
3697}
3698
a4d1ba9a 3699static int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 3700 ssize_t nread, totread = 0;
3701 time_t start = time(NULL);
3702
3703 timeout++;
3704 while(size) {
3705 if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
3706 nread = read(fd,ptr,size);
3707 if (nread == -1) return -1;
3708 ptr += nread;
3709 size -= nread;
3710 totread += nread;
3711 }
3712 if ((time(NULL)-start) > timeout) {
3713 errno = ETIMEDOUT;
3714 return -1;
3715 }
3716 }
3717 return totread;
3718}
3719
3720static int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
3721 ssize_t nread = 0;
3722
3723 size--;
3724 while(size) {
3725 char c;
3726
3727 if (syncRead(fd,&c,1,timeout) == -1) return -1;
3728 if (c == '\n') {
3729 *ptr = '\0';
3730 if (nread && *(ptr-1) == '\r') *(ptr-1) = '\0';
3731 return nread;
3732 } else {
3733 *ptr++ = c;
3734 *ptr = '\0';
3735 nread++;
3736 }
3737 }
3738 return nread;
3739}
3740
3741static void syncCommand(redisClient *c) {
40d224a9 3742 /* ignore SYNC if aleady slave or in monitor mode */
3743 if (c->flags & REDIS_SLAVE) return;
3744
3745 /* SYNC can't be issued when the server has pending data to send to
3746 * the client about already issued commands. We need a fresh reply
3747 * buffer registering the differences between the BGSAVE and the current
3748 * dataset, so that we can copy to other slaves if needed. */
3749 if (listLength(c->reply) != 0) {
3750 addReplySds(c,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
3751 return;
3752 }
3753
3754 redisLog(REDIS_NOTICE,"Slave ask for synchronization");
3755 /* Here we need to check if there is a background saving operation
3756 * in progress, or if it is required to start one */
3757 if (server.bgsaveinprogress) {
3758 /* Ok a background save is in progress. Let's check if it is a good
3759 * one for replication, i.e. if there is another slave that is
3760 * registering differences since the server forked to save */
3761 redisClient *slave;
3762 listNode *ln;
3763
6208b3a7 3764 listRewind(server.slaves);
3765 while((ln = listYield(server.slaves))) {
40d224a9 3766 slave = ln->value;
3767 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break;
40d224a9 3768 }
3769 if (ln) {
3770 /* Perfect, the server is already registering differences for
3771 * another slave. Set the right state, and copy the buffer. */
3772 listRelease(c->reply);
3773 c->reply = listDup(slave->reply);
3774 if (!c->reply) oom("listDup copying slave reply list");
3775 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
3776 redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC");
3777 } else {
3778 /* No way, we need to wait for the next BGSAVE in order to
3779 * register differences */
3780 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
3781 redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
3782 }
3783 } else {
3784 /* Ok we don't have a BGSAVE in progress, let's start one */
3785 redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
3786 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
3787 redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE");
3788 addReplySds(c,sdsnew("-ERR Unalbe to perform background save\r\n"));
3789 return;
3790 }
3791 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
3792 }
6208b3a7 3793 c->repldbfd = -1;
40d224a9 3794 c->flags |= REDIS_SLAVE;
3795 c->slaveseldb = 0;
3796 if (!listAddNodeTail(server.slaves,c)) oom("listAddNodeTail");
40d224a9 3797 return;
3798}
3799
6208b3a7 3800static void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
3801 redisClient *slave = privdata;
3802 REDIS_NOTUSED(el);
3803 REDIS_NOTUSED(mask);
3804 char buf[REDIS_IOBUF_LEN];
3805 ssize_t nwritten, buflen;
3806
3807 if (slave->repldboff == 0) {
3808 /* Write the bulk write count before to transfer the DB. In theory here
3809 * we don't know how much room there is in the output buffer of the
3810 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
3811 * operations) will never be smaller than the few bytes we need. */
3812 sds bulkcount;
3813
3814 bulkcount = sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
3815 slave->repldbsize);
3816 if (write(fd,bulkcount,sdslen(bulkcount)) != (signed)sdslen(bulkcount))
3817 {
3818 sdsfree(bulkcount);
3819 freeClient(slave);
3820 return;
3821 }
3822 sdsfree(bulkcount);
3823 }
3824 lseek(slave->repldbfd,slave->repldboff,SEEK_SET);
3825 buflen = read(slave->repldbfd,buf,REDIS_IOBUF_LEN);
3826 if (buflen <= 0) {
3827 redisLog(REDIS_WARNING,"Read error sending DB to slave: %s",
3828 (buflen == 0) ? "premature EOF" : strerror(errno));
3829 freeClient(slave);
3830 return;
3831 }
3832 if ((nwritten = write(fd,buf,buflen)) == -1) {
3833 redisLog(REDIS_DEBUG,"Write error sending DB to slave: %s",
3834 strerror(errno));
3835 freeClient(slave);
3836 return;
3837 }
3838 slave->repldboff += nwritten;
3839 if (slave->repldboff == slave->repldbsize) {
3840 close(slave->repldbfd);
3841 slave->repldbfd = -1;
3842 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
3843 slave->replstate = REDIS_REPL_ONLINE;
3844 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
3845 sendReplyToClient, slave, NULL) == AE_ERR) {
3846 freeClient(slave);
3847 return;
3848 }
3849 addReplySds(slave,sdsempty());
3850 redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
3851 }
3852}
ed9b544e 3853
6208b3a7 3854static void updateSalvesWaitingBgsave(int bgsaveerr) {
3855 listNode *ln;
3856 int startbgsave = 0;
ed9b544e 3857
6208b3a7 3858 listRewind(server.slaves);
3859 while((ln = listYield(server.slaves))) {
3860 redisClient *slave = ln->value;
ed9b544e 3861
6208b3a7 3862 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) {
3863 startbgsave = 1;
3864 slave->replstate = REDIS_REPL_WAIT_BGSAVE_END;
3865 } else if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
3866 struct stat buf;
3867
3868 if (bgsaveerr != REDIS_OK) {
3869 freeClient(slave);
3870 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE child returned an error");
3871 continue;
3872 }
3873 if ((slave->repldbfd = open(server.dbfilename,O_RDONLY)) == -1 ||
3874 fstat(slave->repldbfd,&buf) == -1) {
3875 freeClient(slave);
3876 redisLog(REDIS_WARNING,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno));
3877 continue;
3878 }
3879 slave->repldboff = 0;
3880 slave->repldbsize = buf.st_size;
3881 slave->replstate = REDIS_REPL_SEND_BULK;
3882 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
3883 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE, sendBulkToSlave, slave, NULL) == AE_ERR) {
3884 freeClient(slave);
3885 continue;
3886 }
3887 }
ed9b544e 3888 }
6208b3a7 3889 if (startbgsave) {
3890 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
3891 listRewind(server.slaves);
3892 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE failed");
3893 while((ln = listYield(server.slaves))) {
3894 redisClient *slave = ln->value;
ed9b544e 3895
6208b3a7 3896 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START)
3897 freeClient(slave);
3898 }
3899 }
3900 }
ed9b544e 3901}
3902
3903static int syncWithMaster(void) {
3904 char buf[1024], tmpfile[256];
3905 int dumpsize;
3906 int fd = anetTcpConnect(NULL,server.masterhost,server.masterport);
3907 int dfd;
3908
3909 if (fd == -1) {
3910 redisLog(REDIS_WARNING,"Unable to connect to MASTER: %s",
3911 strerror(errno));
3912 return REDIS_ERR;
3913 }
3914 /* Issue the SYNC command */
3915 if (syncWrite(fd,"SYNC \r\n",7,5) == -1) {
3916 close(fd);
3917 redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
3918 strerror(errno));
3919 return REDIS_ERR;
3920 }
3921 /* Read the bulk write count */
8c4d91fc 3922 if (syncReadLine(fd,buf,1024,3600) == -1) {
ed9b544e 3923 close(fd);
3924 redisLog(REDIS_WARNING,"I/O error reading bulk count from MASTER: %s",
3925 strerror(errno));
3926 return REDIS_ERR;
3927 }
c937aa89 3928 dumpsize = atoi(buf+1);
ed9b544e 3929 redisLog(REDIS_NOTICE,"Receiving %d bytes data dump from MASTER",dumpsize);
3930 /* Read the bulk write data on a temp file */
3931 snprintf(tmpfile,256,"temp-%d.%ld.rdb",(int)time(NULL),(long int)random());
3932 dfd = open(tmpfile,O_CREAT|O_WRONLY,0644);
3933 if (dfd == -1) {
3934 close(fd);
3935 redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
3936 return REDIS_ERR;
3937 }
3938 while(dumpsize) {
3939 int nread, nwritten;
3940
3941 nread = read(fd,buf,(dumpsize < 1024)?dumpsize:1024);
3942 if (nread == -1) {
3943 redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
3944 strerror(errno));
3945 close(fd);
3946 close(dfd);
3947 return REDIS_ERR;
3948 }
3949 nwritten = write(dfd,buf,nread);
3950 if (nwritten == -1) {
3951 redisLog(REDIS_WARNING,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
3952 close(fd);
3953 close(dfd);
3954 return REDIS_ERR;
3955 }
3956 dumpsize -= nread;
3957 }
3958 close(dfd);
3959 if (rename(tmpfile,server.dbfilename) == -1) {
3960 redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
3961 unlink(tmpfile);
3962 close(fd);
3963 return REDIS_ERR;
3964 }
3965 emptyDb();
f78fd11b 3966 if (rdbLoad(server.dbfilename) != REDIS_OK) {
ed9b544e 3967 redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
3968 close(fd);
3969 return REDIS_ERR;
3970 }
3971 server.master = createClient(fd);
3972 server.master->flags |= REDIS_MASTER;
3973 server.replstate = REDIS_REPL_CONNECTED;
3974 return REDIS_OK;
3975}
3976
321b0e13 3977static void slaveofCommand(redisClient *c) {
3978 if (!strcasecmp(c->argv[1]->ptr,"no") &&
3979 !strcasecmp(c->argv[2]->ptr,"one")) {
3980 if (server.masterhost) {
3981 sdsfree(server.masterhost);
3982 server.masterhost = NULL;
3983 if (server.master) freeClient(server.master);
3984 server.replstate = REDIS_REPL_NONE;
3985 redisLog(REDIS_NOTICE,"MASTER MODE enabled (user request)");
3986 }
3987 } else {
3988 sdsfree(server.masterhost);
3989 server.masterhost = sdsdup(c->argv[1]->ptr);
3990 server.masterport = atoi(c->argv[2]->ptr);
3991 if (server.master) freeClient(server.master);
3992 server.replstate = REDIS_REPL_CONNECT;
3993 redisLog(REDIS_NOTICE,"SLAVE OF %s:%d enabled (user request)",
3994 server.masterhost, server.masterport);
3995 }
3996 addReply(c,shared.ok);
3997}
3998
3fd78bcd 3999/* ============================ Maxmemory directive ======================== */
4000
4001/* This function gets called when 'maxmemory' is set on the config file to limit
4002 * the max memory used by the server, and we are out of memory.
4003 * This function will try to, in order:
4004 *
4005 * - Free objects from the free list
4006 * - Try to remove keys with an EXPIRE set
4007 *
4008 * It is not possible to free enough memory to reach used-memory < maxmemory
4009 * the server will start refusing commands that will enlarge even more the
4010 * memory usage.
4011 */
4012static void freeMemoryIfNeeded(void) {
4013 while (server.maxmemory && zmalloc_used_memory() > server.maxmemory) {
4014 if (listLength(server.objfreelist)) {
4015 robj *o;
4016
4017 listNode *head = listFirst(server.objfreelist);
4018 o = listNodeValue(head);
4019 listDelNode(server.objfreelist,head);
4020 zfree(o);
4021 } else {
4022 int j, k, freed = 0;
4023
4024 for (j = 0; j < server.dbnum; j++) {
4025 int minttl = -1;
4026 robj *minkey = NULL;
4027 struct dictEntry *de;
4028
4029 if (dictSize(server.db[j].expires)) {
4030 freed = 1;
4031 /* From a sample of three keys drop the one nearest to
4032 * the natural expire */
4033 for (k = 0; k < 3; k++) {
4034 time_t t;
4035
4036 de = dictGetRandomKey(server.db[j].expires);
4037 t = (time_t) dictGetEntryVal(de);
4038 if (minttl == -1 || t < minttl) {
4039 minkey = dictGetEntryKey(de);
4040 minttl = t;
4041 }
4042 }
4043 deleteKey(server.db+j,minkey);
4044 }
4045 }
4046 if (!freed) return; /* nothing to free... */
4047 }
4048 }
4049}
4050
ed9b544e 4051/* =================================== Main! ================================ */
4052
0bc03378 4053#ifdef __linux__
4054int linuxOvercommitMemoryValue(void) {
4055 FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
4056 char buf[64];
4057
4058 if (!fp) return -1;
4059 if (fgets(buf,64,fp) == NULL) {
4060 fclose(fp);
4061 return -1;
4062 }
4063 fclose(fp);
4064
4065 return atoi(buf);
4066}
4067
4068void linuxOvercommitMemoryWarning(void) {
4069 if (linuxOvercommitMemoryValue() == 0) {
4070 redisLog(REDIS_WARNING,"WARNING overcommit_memory is set to 0! Background save may fail under low condition memory. To fix this issue add 'echo 1 > /proc/sys/vm/overcommit_memory' in your init scripts.");
4071 }
4072}
4073#endif /* __linux__ */
4074
ed9b544e 4075static void daemonize(void) {
4076 int fd;
4077 FILE *fp;
4078
4079 if (fork() != 0) exit(0); /* parent exits */
4080 setsid(); /* create a new session */
4081
4082 /* Every output goes to /dev/null. If Redis is daemonized but
4083 * the 'logfile' is set to 'stdout' in the configuration file
4084 * it will not log at all. */
4085 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
4086 dup2(fd, STDIN_FILENO);
4087 dup2(fd, STDOUT_FILENO);
4088 dup2(fd, STDERR_FILENO);
4089 if (fd > STDERR_FILENO) close(fd);
4090 }
4091 /* Try to write the pid file */
ed329fcf 4092 fp = fopen(server.pidfile,"w");
ed9b544e 4093 if (fp) {
4094 fprintf(fp,"%d\n",getpid());
4095 fclose(fp);
4096 }
4097}
4098
4099int main(int argc, char **argv) {
0bc03378 4100#ifdef __linux__
4101 linuxOvercommitMemoryWarning();
4102#endif
4103
ed9b544e 4104 initServerConfig();
4105 if (argc == 2) {
4106 ResetServerSaveParams();
4107 loadServerConfig(argv[1]);
4108 } else if (argc > 2) {
4109 fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
4110 exit(1);
8cca9b82 4111 } else {
4112 redisLog(REDIS_WARNING,"Warning: no config file specified, using the default config. In order to specify a config file use 'redis-server /path/to/redis.conf'");
ed9b544e 4113 }
4114 initServer();
4115 if (server.daemonize) daemonize();
4116 redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
f78fd11b 4117 if (rdbLoad(server.dbfilename) == REDIS_OK)
ed9b544e 4118 redisLog(REDIS_NOTICE,"DB loaded from disk");
4119 if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,
4120 acceptHandler, NULL, NULL) == AE_ERR) oom("creating file event");
46713f83 4121 redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
ed9b544e 4122 aeMain(server.el);
4123 aeDeleteEventLoop(server.el);
4124 return 0;
4125}