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