]> git.saurik.com Git - redis.git/blame - redis.c
Fixed daemonization when using kqueue/kevent. Now the server initialization is perfor...
[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
76d31044 30#define REDIS_VERSION "1.1.90"
23d4709d 31
32#include "fmacros.h"
fbf9bcdb 33#include "config.h"
ed9b544e 34
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <time.h>
39#include <unistd.h>
c9468bcf 40#define __USE_POSIX199309
ed9b544e 41#include <signal.h>
fbf9bcdb 42
43#ifdef HAVE_BACKTRACE
c9468bcf 44#include <execinfo.h>
45#include <ucontext.h>
fbf9bcdb 46#endif /* HAVE_BACKTRACE */
47
ed9b544e 48#include <sys/wait.h>
49#include <errno.h>
50#include <assert.h>
51#include <ctype.h>
52#include <stdarg.h>
53#include <inttypes.h>
54#include <arpa/inet.h>
55#include <sys/stat.h>
56#include <fcntl.h>
57#include <sys/time.h>
58#include <sys/resource.h>
2895e862 59#include <sys/uio.h>
f78fd11b 60#include <limits.h>
a7866db6 61#include <math.h>
0bc1b2f6 62
63#if defined(__sun)
5043dff3 64#include "solarisfixes.h"
65#endif
ed9b544e 66
c9468bcf 67#include "redis.h"
ed9b544e 68#include "ae.h" /* Event driven programming library */
69#include "sds.h" /* Dynamic safe strings */
70#include "anet.h" /* Networking the easy way */
71#include "dict.h" /* Hash tables */
72#include "adlist.h" /* Linked lists */
73#include "zmalloc.h" /* total memory usage aware version of malloc/free */
5f5b9840 74#include "lzf.h" /* LZF compression library */
75#include "pqsort.h" /* Partial qsort for SORT+LIMIT */
ed9b544e 76
77/* Error codes */
78#define REDIS_OK 0
79#define REDIS_ERR -1
80
81/* Static server configuration */
82#define REDIS_SERVERPORT 6379 /* TCP port */
83#define REDIS_MAXIDLETIME (60*5) /* default client timeout */
6208b3a7 84#define REDIS_IOBUF_LEN 1024
ed9b544e 85#define REDIS_LOADBUF_LEN 1024
93ea3759 86#define REDIS_STATIC_ARGS 4
ed9b544e 87#define REDIS_DEFAULT_DBNUM 16
88#define REDIS_CONFIGLINE_MAX 1024
89#define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
90#define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
94754ccc 91#define REDIS_EXPIRELOOKUPS_PER_CRON 100 /* try to expire 100 keys/second */
6f376729 92#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
2895e862 93#define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
94
95/* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
96#define REDIS_WRITEV_THRESHOLD 3
97/* Max number of iovecs used for each writev call */
98#define REDIS_WRITEV_IOVEC_COUNT 256
ed9b544e 99
100/* Hash table parameters */
101#define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
ed9b544e 102
103/* Command flags */
3fd78bcd 104#define REDIS_CMD_BULK 1 /* Bulk write command */
105#define REDIS_CMD_INLINE 2 /* Inline command */
106/* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
107 this flags will return an error when the 'maxmemory' option is set in the
108 config file and the server is using more than maxmemory bytes of memory.
109 In short this commands are denied on low memory conditions. */
110#define REDIS_CMD_DENYOOM 4
ed9b544e 111
112/* Object types */
113#define REDIS_STRING 0
114#define REDIS_LIST 1
115#define REDIS_SET 2
1812e024 116#define REDIS_ZSET 3
117#define REDIS_HASH 4
f78fd11b 118
942a3961 119/* Objects encoding */
120#define REDIS_ENCODING_RAW 0 /* Raw representation */
121#define REDIS_ENCODING_INT 1 /* Encoded as integer */
122
f78fd11b 123/* Object types only used for dumping to disk */
bb32ede5 124#define REDIS_EXPIRETIME 253
ed9b544e 125#define REDIS_SELECTDB 254
126#define REDIS_EOF 255
127
f78fd11b 128/* Defines related to the dump file format. To store 32 bits lengths for short
129 * keys requires a lot of space, so we check the most significant 2 bits of
130 * the first byte to interpreter the length:
131 *
132 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
133 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
134 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
a4d1ba9a 135 * 11|000000 this means: specially encoded object will follow. The six bits
136 * number specify the kind of object that follows.
137 * See the REDIS_RDB_ENC_* defines.
f78fd11b 138 *
10c43610 139 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
140 * values, will fit inside. */
f78fd11b 141#define REDIS_RDB_6BITLEN 0
142#define REDIS_RDB_14BITLEN 1
143#define REDIS_RDB_32BITLEN 2
17be1a4a 144#define REDIS_RDB_ENCVAL 3
f78fd11b 145#define REDIS_RDB_LENERR UINT_MAX
146
a4d1ba9a 147/* When a length of a string object stored on disk has the first two bits
148 * set, the remaining two bits specify a special encoding for the object
149 * accordingly to the following defines: */
150#define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
151#define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
152#define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
774e3047 153#define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
a4d1ba9a 154
ed9b544e 155/* Client flags */
156#define REDIS_CLOSE 1 /* This client connection should be closed ASAP */
157#define REDIS_SLAVE 2 /* This client is a slave server */
158#define REDIS_MASTER 4 /* This client is a master server */
87eca727 159#define REDIS_MONITOR 8 /* This client is a slave monitor, see MONITOR */
ed9b544e 160
40d224a9 161/* Slave replication state - slave side */
ed9b544e 162#define REDIS_REPL_NONE 0 /* No active replication */
163#define REDIS_REPL_CONNECT 1 /* Must connect to master */
164#define REDIS_REPL_CONNECTED 2 /* Connected to master */
165
40d224a9 166/* Slave replication state - from the point of view of master
167 * Note that in SEND_BULK and ONLINE state the slave receives new updates
168 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
169 * to start the next background saving in order to send updates to it. */
170#define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
171#define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
172#define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
173#define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
174
ed9b544e 175/* List related stuff */
176#define REDIS_HEAD 0
177#define REDIS_TAIL 1
178
179/* Sort operations */
180#define REDIS_SORT_GET 0
443c6409 181#define REDIS_SORT_ASC 1
182#define REDIS_SORT_DESC 2
ed9b544e 183#define REDIS_SORTKEY_MAX 1024
184
185/* Log levels */
186#define REDIS_DEBUG 0
187#define REDIS_NOTICE 1
188#define REDIS_WARNING 2
189
190/* Anti-warning macro... */
191#define REDIS_NOTUSED(V) ((void) V)
192
6b47e12e 193#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
194#define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
ed9b544e 195
48f0308a 196/* Append only defines */
197#define APPENDFSYNC_NO 0
198#define APPENDFSYNC_ALWAYS 1
199#define APPENDFSYNC_EVERYSEC 2
200
dfc5e96c 201/* We can print the stacktrace, so our assert is defined this way: */
202#define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e),exit(1)))
203static void _redisAssert(char *estr);
204
ed9b544e 205/*================================= Data types ============================== */
206
207/* A redis object, that is a type able to hold a string / list / set */
208typedef struct redisObject {
ed9b544e 209 void *ptr;
942a3961 210 unsigned char type;
211 unsigned char encoding;
212 unsigned char notused[2];
ed9b544e 213 int refcount;
214} robj;
215
dfc5e96c 216/* Macro used to initalize a Redis object allocated on the stack.
217 * Note that this macro is taken near the structure definition to make sure
218 * we'll update it when the structure is changed, to avoid bugs like
219 * bug #85 introduced exactly in this way. */
220#define initStaticStringObject(_var,_ptr) do { \
221 _var.refcount = 1; \
222 _var.type = REDIS_STRING; \
223 _var.encoding = REDIS_ENCODING_RAW; \
224 _var.ptr = _ptr; \
225} while(0);
226
3305306f 227typedef struct redisDb {
228 dict *dict;
229 dict *expires;
230 int id;
231} redisDb;
232
ed9b544e 233/* With multiplexing we need to take per-clinet state.
234 * Clients are taken in a liked list. */
235typedef struct redisClient {
236 int fd;
3305306f 237 redisDb *db;
ed9b544e 238 int dictid;
239 sds querybuf;
e8a74421 240 robj **argv, **mbargv;
241 int argc, mbargc;
40d224a9 242 int bulklen; /* bulk read len. -1 if not in bulk read mode */
e8a74421 243 int multibulk; /* multi bulk command format active */
ed9b544e 244 list *reply;
245 int sentlen;
246 time_t lastinteraction; /* time of the last interaction, used for timeout */
40d224a9 247 int flags; /* REDIS_CLOSE | REDIS_SLAVE | REDIS_MONITOR */
248 int slaveseldb; /* slave selected db, if this client is a slave */
249 int authenticated; /* when requirepass is non-NULL */
250 int replstate; /* replication state if this is a slave */
251 int repldbfd; /* replication DB file descriptor */
6208b3a7 252 long repldboff; /* replication DB file offset */
40d224a9 253 off_t repldbsize; /* replication DB file size */
ed9b544e 254} redisClient;
255
256struct saveparam {
257 time_t seconds;
258 int changes;
259};
260
261/* Global server state structure */
262struct redisServer {
263 int port;
264 int fd;
3305306f 265 redisDb *db;
10c43610 266 dict *sharingpool;
267 unsigned int sharingpoolsize;
ed9b544e 268 long long dirty; /* changes to DB from the last save */
269 list *clients;
87eca727 270 list *slaves, *monitors;
ed9b544e 271 char neterr[ANET_ERR_LEN];
272 aeEventLoop *el;
273 int cronloops; /* number of times the cron function run */
274 list *objfreelist; /* A list of freed objects to avoid malloc() */
275 time_t lastsave; /* Unix time of last save succeeede */
5fba9f71 276 size_t usedmemory; /* Used memory in megabytes */
ed9b544e 277 /* Fields used only for stats */
278 time_t stat_starttime; /* server start time */
279 long long stat_numcommands; /* number of processed commands */
280 long long stat_numconnections; /* number of connections received */
281 /* Configuration */
282 int verbosity;
283 int glueoutputbuf;
284 int maxidletime;
285 int dbnum;
286 int daemonize;
44b38ef4 287 int appendonly;
48f0308a 288 int appendfsync;
289 time_t lastfsync;
44b38ef4 290 int appendfd;
291 int appendseldb;
ed329fcf 292 char *pidfile;
9f3c422c 293 pid_t bgsavechildpid;
9d65a1bb 294 pid_t bgrewritechildpid;
295 sds bgrewritebuf; /* buffer taken by parent during oppend only rewrite */
ed9b544e 296 struct saveparam *saveparams;
297 int saveparamslen;
298 char *logfile;
299 char *bindaddr;
300 char *dbfilename;
44b38ef4 301 char *appendfilename;
abcb223e 302 char *requirepass;
10c43610 303 int shareobjects;
ed9b544e 304 /* Replication related */
305 int isslave;
d0ccebcf 306 char *masterauth;
ed9b544e 307 char *masterhost;
308 int masterport;
40d224a9 309 redisClient *master; /* client that is master for this slave */
ed9b544e 310 int replstate;
285add55 311 unsigned int maxclients;
d4465900 312 unsigned long maxmemory;
ed9b544e 313 /* Sort parameters - qsort_r() is only available under BSD so we
314 * have to take this state global, in order to pass it to sortCompare() */
315 int sort_desc;
316 int sort_alpha;
317 int sort_bypattern;
318};
319
320typedef void redisCommandProc(redisClient *c);
321struct redisCommand {
322 char *name;
323 redisCommandProc *proc;
324 int arity;
325 int flags;
326};
327
de96dbfe 328struct redisFunctionSym {
329 char *name;
56906eef 330 unsigned long pointer;
de96dbfe 331};
332
ed9b544e 333typedef struct _redisSortObject {
334 robj *obj;
335 union {
336 double score;
337 robj *cmpobj;
338 } u;
339} redisSortObject;
340
341typedef struct _redisSortOperation {
342 int type;
343 robj *pattern;
344} redisSortOperation;
345
6b47e12e 346/* ZSETs use a specialized version of Skiplists */
347
348typedef struct zskiplistNode {
349 struct zskiplistNode **forward;
e3870fab 350 struct zskiplistNode *backward;
6b47e12e 351 double score;
352 robj *obj;
353} zskiplistNode;
354
355typedef struct zskiplist {
e3870fab 356 struct zskiplistNode *header, *tail;
d13f767c 357 unsigned long length;
6b47e12e 358 int level;
359} zskiplist;
360
1812e024 361typedef struct zset {
362 dict *dict;
6b47e12e 363 zskiplist *zsl;
1812e024 364} zset;
365
6b47e12e 366/* Our shared "common" objects */
367
ed9b544e 368struct sharedObjectsStruct {
c937aa89 369 robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *pong, *space,
7b45bfb2 370 *colon, *nullbulk, *nullmultibulk,
c937aa89 371 *emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr,
372 *outofrangeerr, *plus,
ed9b544e 373 *select0, *select1, *select2, *select3, *select4,
374 *select5, *select6, *select7, *select8, *select9;
375} shared;
376
a7866db6 377/* Global vars that are actally used as constants. The following double
378 * values are used for double on-disk serialization, and are initialized
379 * at runtime to avoid strange compiler optimizations. */
380
381static double R_Zero, R_PosInf, R_NegInf, R_Nan;
382
ed9b544e 383/*================================ Prototypes =============================== */
384
385static void freeStringObject(robj *o);
386static void freeListObject(robj *o);
387static void freeSetObject(robj *o);
388static void decrRefCount(void *o);
389static robj *createObject(int type, void *ptr);
390static void freeClient(redisClient *c);
f78fd11b 391static int rdbLoad(char *filename);
ed9b544e 392static void addReply(redisClient *c, robj *obj);
393static void addReplySds(redisClient *c, sds s);
394static void incrRefCount(robj *o);
f78fd11b 395static int rdbSaveBackground(char *filename);
ed9b544e 396static robj *createStringObject(char *ptr, size_t len);
87eca727 397static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc);
44b38ef4 398static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc);
ed9b544e 399static int syncWithMaster(void);
10c43610 400static robj *tryObjectSharing(robj *o);
942a3961 401static int tryObjectEncoding(robj *o);
9d65a1bb 402static robj *getDecodedObject(robj *o);
3305306f 403static int removeExpire(redisDb *db, robj *key);
404static int expireIfNeeded(redisDb *db, robj *key);
405static int deleteIfVolatile(redisDb *db, robj *key);
94754ccc 406static int deleteKey(redisDb *db, robj *key);
bb32ede5 407static time_t getExpire(redisDb *db, robj *key);
408static int setExpire(redisDb *db, robj *key, time_t when);
a3b21203 409static void updateSlavesWaitingBgsave(int bgsaveerr);
3fd78bcd 410static void freeMemoryIfNeeded(void);
de96dbfe 411static int processCommand(redisClient *c);
56906eef 412static void setupSigSegvAction(void);
a3b21203 413static void rdbRemoveTempFile(pid_t childpid);
9d65a1bb 414static void aofRemoveTempFile(pid_t childpid);
0ea663ea 415static size_t stringObjectLen(robj *o);
638e42ac 416static void processInputBuffer(redisClient *c);
6b47e12e 417static zskiplist *zslCreate(void);
fd8ccf44 418static void zslFree(zskiplist *zsl);
2b59cfdf 419static void zslInsert(zskiplist *zsl, double score, robj *obj);
2895e862 420static void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask);
ed9b544e 421
abcb223e 422static void authCommand(redisClient *c);
ed9b544e 423static void pingCommand(redisClient *c);
424static void echoCommand(redisClient *c);
425static void setCommand(redisClient *c);
426static void setnxCommand(redisClient *c);
427static void getCommand(redisClient *c);
428static void delCommand(redisClient *c);
429static void existsCommand(redisClient *c);
430static void incrCommand(redisClient *c);
431static void decrCommand(redisClient *c);
432static void incrbyCommand(redisClient *c);
433static void decrbyCommand(redisClient *c);
434static void selectCommand(redisClient *c);
435static void randomkeyCommand(redisClient *c);
436static void keysCommand(redisClient *c);
437static void dbsizeCommand(redisClient *c);
438static void lastsaveCommand(redisClient *c);
439static void saveCommand(redisClient *c);
440static void bgsaveCommand(redisClient *c);
9d65a1bb 441static void bgrewriteaofCommand(redisClient *c);
ed9b544e 442static void shutdownCommand(redisClient *c);
443static void moveCommand(redisClient *c);
444static void renameCommand(redisClient *c);
445static void renamenxCommand(redisClient *c);
446static void lpushCommand(redisClient *c);
447static void rpushCommand(redisClient *c);
448static void lpopCommand(redisClient *c);
449static void rpopCommand(redisClient *c);
450static void llenCommand(redisClient *c);
451static void lindexCommand(redisClient *c);
452static void lrangeCommand(redisClient *c);
453static void ltrimCommand(redisClient *c);
454static void typeCommand(redisClient *c);
455static void lsetCommand(redisClient *c);
456static void saddCommand(redisClient *c);
457static void sremCommand(redisClient *c);
a4460ef4 458static void smoveCommand(redisClient *c);
ed9b544e 459static void sismemberCommand(redisClient *c);
460static void scardCommand(redisClient *c);
12fea928 461static void spopCommand(redisClient *c);
2abb95a9 462static void srandmemberCommand(redisClient *c);
ed9b544e 463static void sinterCommand(redisClient *c);
464static void sinterstoreCommand(redisClient *c);
40d224a9 465static void sunionCommand(redisClient *c);
466static void sunionstoreCommand(redisClient *c);
f4f56e1d 467static void sdiffCommand(redisClient *c);
468static void sdiffstoreCommand(redisClient *c);
ed9b544e 469static void syncCommand(redisClient *c);
470static void flushdbCommand(redisClient *c);
471static void flushallCommand(redisClient *c);
472static void sortCommand(redisClient *c);
473static void lremCommand(redisClient *c);
0f5f7e9a 474static void rpoplpushcommand(redisClient *c);
ed9b544e 475static void infoCommand(redisClient *c);
70003d28 476static void mgetCommand(redisClient *c);
87eca727 477static void monitorCommand(redisClient *c);
3305306f 478static void expireCommand(redisClient *c);
802e8373 479static void expireatCommand(redisClient *c);
f6b141c5 480static void getsetCommand(redisClient *c);
fd88489a 481static void ttlCommand(redisClient *c);
321b0e13 482static void slaveofCommand(redisClient *c);
7f957c92 483static void debugCommand(redisClient *c);
f6b141c5 484static void msetCommand(redisClient *c);
485static void msetnxCommand(redisClient *c);
fd8ccf44 486static void zaddCommand(redisClient *c);
7db723ad 487static void zincrbyCommand(redisClient *c);
cc812361 488static void zrangeCommand(redisClient *c);
50c55df5 489static void zrangebyscoreCommand(redisClient *c);
e3870fab 490static void zrevrangeCommand(redisClient *c);
3c41331e 491static void zcardCommand(redisClient *c);
1b7106e7 492static void zremCommand(redisClient *c);
6e333bbe 493static void zscoreCommand(redisClient *c);
1807985b 494static void zremrangebyscoreCommand(redisClient *c);
f6b141c5 495
ed9b544e 496/*================================= Globals ================================= */
497
498/* Global vars */
499static struct redisServer server; /* server global state */
500static struct redisCommand cmdTable[] = {
501 {"get",getCommand,2,REDIS_CMD_INLINE},
3fd78bcd 502 {"set",setCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
503 {"setnx",setnxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
5109cdff 504 {"del",delCommand,-2,REDIS_CMD_INLINE},
ed9b544e 505 {"exists",existsCommand,2,REDIS_CMD_INLINE},
3fd78bcd 506 {"incr",incrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
507 {"decr",decrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
70003d28 508 {"mget",mgetCommand,-2,REDIS_CMD_INLINE},
3fd78bcd 509 {"rpush",rpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
510 {"lpush",lpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 511 {"rpop",rpopCommand,2,REDIS_CMD_INLINE},
512 {"lpop",lpopCommand,2,REDIS_CMD_INLINE},
513 {"llen",llenCommand,2,REDIS_CMD_INLINE},
514 {"lindex",lindexCommand,3,REDIS_CMD_INLINE},
3fd78bcd 515 {"lset",lsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 516 {"lrange",lrangeCommand,4,REDIS_CMD_INLINE},
517 {"ltrim",ltrimCommand,4,REDIS_CMD_INLINE},
518 {"lrem",lremCommand,4,REDIS_CMD_BULK},
0b13687c 519 {"rpoplpush",rpoplpushcommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
3fd78bcd 520 {"sadd",saddCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 521 {"srem",sremCommand,3,REDIS_CMD_BULK},
a4460ef4 522 {"smove",smoveCommand,4,REDIS_CMD_BULK},
ed9b544e 523 {"sismember",sismemberCommand,3,REDIS_CMD_BULK},
524 {"scard",scardCommand,2,REDIS_CMD_INLINE},
12fea928 525 {"spop",spopCommand,2,REDIS_CMD_INLINE},
2abb95a9 526 {"srandmember",srandmemberCommand,2,REDIS_CMD_INLINE},
3fd78bcd 527 {"sinter",sinterCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
528 {"sinterstore",sinterstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
529 {"sunion",sunionCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
530 {"sunionstore",sunionstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
531 {"sdiff",sdiffCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
532 {"sdiffstore",sdiffstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
ed9b544e 533 {"smembers",sinterCommand,2,REDIS_CMD_INLINE},
fd8ccf44 534 {"zadd",zaddCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
7db723ad 535 {"zincrby",zincrbyCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
1b7106e7 536 {"zrem",zremCommand,3,REDIS_CMD_BULK},
1807985b 537 {"zremrangebyscore",zremrangebyscoreCommand,4,REDIS_CMD_INLINE},
cc812361 538 {"zrange",zrangeCommand,4,REDIS_CMD_INLINE},
80181f78 539 {"zrangebyscore",zrangebyscoreCommand,-4,REDIS_CMD_INLINE},
e3870fab 540 {"zrevrange",zrevrangeCommand,4,REDIS_CMD_INLINE},
3c41331e 541 {"zcard",zcardCommand,2,REDIS_CMD_INLINE},
6e333bbe 542 {"zscore",zscoreCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
3fd78bcd 543 {"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
544 {"decrby",decrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
f6b141c5 545 {"getset",getsetCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
546 {"mset",msetCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
547 {"msetnx",msetnxCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 548 {"randomkey",randomkeyCommand,1,REDIS_CMD_INLINE},
549 {"select",selectCommand,2,REDIS_CMD_INLINE},
550 {"move",moveCommand,3,REDIS_CMD_INLINE},
551 {"rename",renameCommand,3,REDIS_CMD_INLINE},
552 {"renamenx",renamenxCommand,3,REDIS_CMD_INLINE},
321b0e13 553 {"expire",expireCommand,3,REDIS_CMD_INLINE},
802e8373 554 {"expireat",expireatCommand,3,REDIS_CMD_INLINE},
ed9b544e 555 {"keys",keysCommand,2,REDIS_CMD_INLINE},
556 {"dbsize",dbsizeCommand,1,REDIS_CMD_INLINE},
abcb223e 557 {"auth",authCommand,2,REDIS_CMD_INLINE},
ed9b544e 558 {"ping",pingCommand,1,REDIS_CMD_INLINE},
559 {"echo",echoCommand,2,REDIS_CMD_BULK},
560 {"save",saveCommand,1,REDIS_CMD_INLINE},
561 {"bgsave",bgsaveCommand,1,REDIS_CMD_INLINE},
9d65a1bb 562 {"bgrewriteaof",bgrewriteaofCommand,1,REDIS_CMD_INLINE},
ed9b544e 563 {"shutdown",shutdownCommand,1,REDIS_CMD_INLINE},
564 {"lastsave",lastsaveCommand,1,REDIS_CMD_INLINE},
565 {"type",typeCommand,2,REDIS_CMD_INLINE},
566 {"sync",syncCommand,1,REDIS_CMD_INLINE},
567 {"flushdb",flushdbCommand,1,REDIS_CMD_INLINE},
568 {"flushall",flushallCommand,1,REDIS_CMD_INLINE},
3fd78bcd 569 {"sort",sortCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
ed9b544e 570 {"info",infoCommand,1,REDIS_CMD_INLINE},
87eca727 571 {"monitor",monitorCommand,1,REDIS_CMD_INLINE},
fd88489a 572 {"ttl",ttlCommand,2,REDIS_CMD_INLINE},
321b0e13 573 {"slaveof",slaveofCommand,3,REDIS_CMD_INLINE},
7f957c92 574 {"debug",debugCommand,-2,REDIS_CMD_INLINE},
ed9b544e 575 {NULL,NULL,0,0}
576};
bcfc686d 577
ed9b544e 578/*============================ Utility functions ============================ */
579
580/* Glob-style pattern matching. */
581int stringmatchlen(const char *pattern, int patternLen,
582 const char *string, int stringLen, int nocase)
583{
584 while(patternLen) {
585 switch(pattern[0]) {
586 case '*':
587 while (pattern[1] == '*') {
588 pattern++;
589 patternLen--;
590 }
591 if (patternLen == 1)
592 return 1; /* match */
593 while(stringLen) {
594 if (stringmatchlen(pattern+1, patternLen-1,
595 string, stringLen, nocase))
596 return 1; /* match */
597 string++;
598 stringLen--;
599 }
600 return 0; /* no match */
601 break;
602 case '?':
603 if (stringLen == 0)
604 return 0; /* no match */
605 string++;
606 stringLen--;
607 break;
608 case '[':
609 {
610 int not, match;
611
612 pattern++;
613 patternLen--;
614 not = pattern[0] == '^';
615 if (not) {
616 pattern++;
617 patternLen--;
618 }
619 match = 0;
620 while(1) {
621 if (pattern[0] == '\\') {
622 pattern++;
623 patternLen--;
624 if (pattern[0] == string[0])
625 match = 1;
626 } else if (pattern[0] == ']') {
627 break;
628 } else if (patternLen == 0) {
629 pattern--;
630 patternLen++;
631 break;
632 } else if (pattern[1] == '-' && patternLen >= 3) {
633 int start = pattern[0];
634 int end = pattern[2];
635 int c = string[0];
636 if (start > end) {
637 int t = start;
638 start = end;
639 end = t;
640 }
641 if (nocase) {
642 start = tolower(start);
643 end = tolower(end);
644 c = tolower(c);
645 }
646 pattern += 2;
647 patternLen -= 2;
648 if (c >= start && c <= end)
649 match = 1;
650 } else {
651 if (!nocase) {
652 if (pattern[0] == string[0])
653 match = 1;
654 } else {
655 if (tolower((int)pattern[0]) == tolower((int)string[0]))
656 match = 1;
657 }
658 }
659 pattern++;
660 patternLen--;
661 }
662 if (not)
663 match = !match;
664 if (!match)
665 return 0; /* no match */
666 string++;
667 stringLen--;
668 break;
669 }
670 case '\\':
671 if (patternLen >= 2) {
672 pattern++;
673 patternLen--;
674 }
675 /* fall through */
676 default:
677 if (!nocase) {
678 if (pattern[0] != string[0])
679 return 0; /* no match */
680 } else {
681 if (tolower((int)pattern[0]) != tolower((int)string[0]))
682 return 0; /* no match */
683 }
684 string++;
685 stringLen--;
686 break;
687 }
688 pattern++;
689 patternLen--;
690 if (stringLen == 0) {
691 while(*pattern == '*') {
692 pattern++;
693 patternLen--;
694 }
695 break;
696 }
697 }
698 if (patternLen == 0 && stringLen == 0)
699 return 1;
700 return 0;
701}
702
56906eef 703static void redisLog(int level, const char *fmt, ...) {
ed9b544e 704 va_list ap;
705 FILE *fp;
706
707 fp = (server.logfile == NULL) ? stdout : fopen(server.logfile,"a");
708 if (!fp) return;
709
710 va_start(ap, fmt);
711 if (level >= server.verbosity) {
712 char *c = ".-*";
1904ecc1 713 char buf[64];
714 time_t now;
715
716 now = time(NULL);
6c9385e0 717 strftime(buf,64,"%d %b %H:%M:%S",localtime(&now));
1904ecc1 718 fprintf(fp,"%s %c ",buf,c[level]);
ed9b544e 719 vfprintf(fp, fmt, ap);
720 fprintf(fp,"\n");
721 fflush(fp);
722 }
723 va_end(ap);
724
725 if (server.logfile) fclose(fp);
726}
727
728/*====================== Hash table type implementation ==================== */
729
730/* This is an hash table type that uses the SDS dynamic strings libary as
731 * keys and radis objects as values (objects can hold SDS strings,
732 * lists, sets). */
733
1812e024 734static void dictVanillaFree(void *privdata, void *val)
735{
736 DICT_NOTUSED(privdata);
737 zfree(val);
738}
739
ed9b544e 740static int sdsDictKeyCompare(void *privdata, const void *key1,
741 const void *key2)
742{
743 int l1,l2;
744 DICT_NOTUSED(privdata);
745
746 l1 = sdslen((sds)key1);
747 l2 = sdslen((sds)key2);
748 if (l1 != l2) return 0;
749 return memcmp(key1, key2, l1) == 0;
750}
751
752static void dictRedisObjectDestructor(void *privdata, void *val)
753{
754 DICT_NOTUSED(privdata);
755
756 decrRefCount(val);
757}
758
942a3961 759static int dictObjKeyCompare(void *privdata, const void *key1,
ed9b544e 760 const void *key2)
761{
762 const robj *o1 = key1, *o2 = key2;
763 return sdsDictKeyCompare(privdata,o1->ptr,o2->ptr);
764}
765
942a3961 766static unsigned int dictObjHash(const void *key) {
ed9b544e 767 const robj *o = key;
768 return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
769}
770
942a3961 771static int dictEncObjKeyCompare(void *privdata, const void *key1,
772 const void *key2)
773{
9d65a1bb 774 robj *o1 = (robj*) key1, *o2 = (robj*) key2;
775 int cmp;
942a3961 776
9d65a1bb 777 o1 = getDecodedObject(o1);
778 o2 = getDecodedObject(o2);
779 cmp = sdsDictKeyCompare(privdata,o1->ptr,o2->ptr);
780 decrRefCount(o1);
781 decrRefCount(o2);
782 return cmp;
942a3961 783}
784
785static unsigned int dictEncObjHash(const void *key) {
9d65a1bb 786 robj *o = (robj*) key;
942a3961 787
9d65a1bb 788 o = getDecodedObject(o);
789 unsigned int hash = dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
790 decrRefCount(o);
791 return hash;
942a3961 792}
793
ed9b544e 794static dictType setDictType = {
942a3961 795 dictEncObjHash, /* hash function */
ed9b544e 796 NULL, /* key dup */
797 NULL, /* val dup */
942a3961 798 dictEncObjKeyCompare, /* key compare */
ed9b544e 799 dictRedisObjectDestructor, /* key destructor */
800 NULL /* val destructor */
801};
802
1812e024 803static dictType zsetDictType = {
804 dictEncObjHash, /* hash function */
805 NULL, /* key dup */
806 NULL, /* val dup */
807 dictEncObjKeyCompare, /* key compare */
808 dictRedisObjectDestructor, /* key destructor */
da0a1620 809 dictVanillaFree /* val destructor of malloc(sizeof(double)) */
1812e024 810};
811
ed9b544e 812static dictType hashDictType = {
942a3961 813 dictObjHash, /* hash function */
ed9b544e 814 NULL, /* key dup */
815 NULL, /* val dup */
942a3961 816 dictObjKeyCompare, /* key compare */
ed9b544e 817 dictRedisObjectDestructor, /* key destructor */
818 dictRedisObjectDestructor /* val destructor */
819};
820
821/* ========================= Random utility functions ======================= */
822
823/* Redis generally does not try to recover from out of memory conditions
824 * when allocating objects or strings, it is not clear if it will be possible
825 * to report this condition to the client since the networking layer itself
826 * is based on heap allocation for send buffers, so we simply abort.
827 * At least the code will be simpler to read... */
828static void oom(const char *msg) {
71c54b21 829 redisLog(REDIS_WARNING, "%s: Out of memory\n",msg);
ed9b544e 830 sleep(1);
831 abort();
832}
833
834/* ====================== Redis server networking stuff ===================== */
56906eef 835static void closeTimedoutClients(void) {
ed9b544e 836 redisClient *c;
ed9b544e 837 listNode *ln;
838 time_t now = time(NULL);
839
6208b3a7 840 listRewind(server.clients);
841 while ((ln = listYield(server.clients)) != NULL) {
ed9b544e 842 c = listNodeValue(ln);
843 if (!(c->flags & REDIS_SLAVE) && /* no timeout for slaves */
c7cf2ec9 844 !(c->flags & REDIS_MASTER) && /* no timeout for masters */
ed9b544e 845 (now - c->lastinteraction > server.maxidletime)) {
846 redisLog(REDIS_DEBUG,"Closing idle client");
847 freeClient(c);
848 }
849 }
ed9b544e 850}
851
12fea928 852static int htNeedsResize(dict *dict) {
853 long long size, used;
854
855 size = dictSlots(dict);
856 used = dictSize(dict);
857 return (size && used && size > DICT_HT_INITIAL_SIZE &&
858 (used*100/size < REDIS_HT_MINFILL));
859}
860
0bc03378 861/* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
862 * we resize the hash table to save memory */
56906eef 863static void tryResizeHashTables(void) {
0bc03378 864 int j;
865
866 for (j = 0; j < server.dbnum; j++) {
12fea928 867 if (htNeedsResize(server.db[j].dict)) {
868 redisLog(REDIS_DEBUG,"The hash table %d is too sparse, resize it...",j);
0bc03378 869 dictResize(server.db[j].dict);
12fea928 870 redisLog(REDIS_DEBUG,"Hash table %d resized.",j);
0bc03378 871 }
12fea928 872 if (htNeedsResize(server.db[j].expires))
873 dictResize(server.db[j].expires);
0bc03378 874 }
875}
876
9d65a1bb 877/* A background saving child (BGSAVE) terminated its work. Handle this. */
878void backgroundSaveDoneHandler(int statloc) {
879 int exitcode = WEXITSTATUS(statloc);
880 int bysignal = WIFSIGNALED(statloc);
881
882 if (!bysignal && exitcode == 0) {
883 redisLog(REDIS_NOTICE,
884 "Background saving terminated with success");
885 server.dirty = 0;
886 server.lastsave = time(NULL);
887 } else if (!bysignal && exitcode != 0) {
888 redisLog(REDIS_WARNING, "Background saving error");
889 } else {
890 redisLog(REDIS_WARNING,
891 "Background saving terminated by signal");
892 rdbRemoveTempFile(server.bgsavechildpid);
893 }
894 server.bgsavechildpid = -1;
895 /* Possibly there are slaves waiting for a BGSAVE in order to be served
896 * (the first stage of SYNC is a bulk transfer of dump.rdb) */
897 updateSlavesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR);
898}
899
900/* A background append only file rewriting (BGREWRITEAOF) terminated its work.
901 * Handle this. */
902void backgroundRewriteDoneHandler(int statloc) {
903 int exitcode = WEXITSTATUS(statloc);
904 int bysignal = WIFSIGNALED(statloc);
905
906 if (!bysignal && exitcode == 0) {
907 int fd;
908 char tmpfile[256];
909
910 redisLog(REDIS_NOTICE,
911 "Background append only file rewriting terminated with success");
912 /* Now it's time to flush the differences accumulated by the parent */
913 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) server.bgrewritechildpid);
914 fd = open(tmpfile,O_WRONLY|O_APPEND);
915 if (fd == -1) {
916 redisLog(REDIS_WARNING, "Not able to open the temp append only file produced by the child: %s", strerror(errno));
917 goto cleanup;
918 }
919 /* Flush our data... */
920 if (write(fd,server.bgrewritebuf,sdslen(server.bgrewritebuf)) !=
921 (signed) sdslen(server.bgrewritebuf)) {
922 redisLog(REDIS_WARNING, "Error or short write trying to flush the parent diff of the append log file in the child temp file: %s", strerror(errno));
923 close(fd);
924 goto cleanup;
925 }
926 redisLog(REDIS_WARNING,"Parent diff flushed into the new append log file with success");
927 /* Now our work is to rename the temp file into the stable file. And
928 * switch the file descriptor used by the server for append only. */
929 if (rename(tmpfile,server.appendfilename) == -1) {
930 redisLog(REDIS_WARNING,"Can't rename the temp append only file into the stable one: %s", strerror(errno));
931 close(fd);
932 goto cleanup;
933 }
934 /* Mission completed... almost */
935 redisLog(REDIS_NOTICE,"Append only file successfully rewritten.");
936 if (server.appendfd != -1) {
937 /* If append only is actually enabled... */
938 close(server.appendfd);
939 server.appendfd = fd;
940 fsync(fd);
85a83172 941 server.appendseldb = -1; /* Make sure it will issue SELECT */
9d65a1bb 942 redisLog(REDIS_NOTICE,"The new append only file was selected for future appends.");
943 } else {
944 /* If append only is disabled we just generate a dump in this
945 * format. Why not? */
946 close(fd);
947 }
948 } else if (!bysignal && exitcode != 0) {
949 redisLog(REDIS_WARNING, "Background append only file rewriting error");
950 } else {
951 redisLog(REDIS_WARNING,
952 "Background append only file rewriting terminated by signal");
953 }
954cleanup:
955 sdsfree(server.bgrewritebuf);
956 server.bgrewritebuf = sdsempty();
957 aofRemoveTempFile(server.bgrewritechildpid);
958 server.bgrewritechildpid = -1;
959}
960
56906eef 961static int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
94754ccc 962 int j, loops = server.cronloops++;
ed9b544e 963 REDIS_NOTUSED(eventLoop);
964 REDIS_NOTUSED(id);
965 REDIS_NOTUSED(clientData);
966
967 /* Update the global state with the amount of used memory */
968 server.usedmemory = zmalloc_used_memory();
969
0bc03378 970 /* Show some info about non-empty databases */
ed9b544e 971 for (j = 0; j < server.dbnum; j++) {
dec423d9 972 long long size, used, vkeys;
94754ccc 973
3305306f 974 size = dictSlots(server.db[j].dict);
975 used = dictSize(server.db[j].dict);
94754ccc 976 vkeys = dictSize(server.db[j].expires);
c3cb078d 977 if (!(loops % 5) && (used || vkeys)) {
978 redisLog(REDIS_DEBUG,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j,used,vkeys,size);
a4d1ba9a 979 /* dictPrintStats(server.dict); */
ed9b544e 980 }
ed9b544e 981 }
982
0bc03378 983 /* We don't want to resize the hash tables while a bacground saving
984 * is in progress: the saving child is created using fork() that is
985 * implemented with a copy-on-write semantic in most modern systems, so
986 * if we resize the HT while there is the saving child at work actually
987 * a lot of memory movements in the parent will cause a lot of pages
988 * copied. */
9d65a1bb 989 if (server.bgsavechildpid == -1) tryResizeHashTables();
0bc03378 990
ed9b544e 991 /* Show information about connected clients */
992 if (!(loops % 5)) {
21aecf4b 993 redisLog(REDIS_DEBUG,"%d clients connected (%d slaves), %zu bytes in use, %d shared objects",
ed9b544e 994 listLength(server.clients)-listLength(server.slaves),
995 listLength(server.slaves),
10c43610 996 server.usedmemory,
3305306f 997 dictSize(server.sharingpool));
ed9b544e 998 }
999
1000 /* Close connections of timedout clients */
0150db36 1001 if (server.maxidletime && !(loops % 10))
ed9b544e 1002 closeTimedoutClients();
1003
9d65a1bb 1004 /* Check if a background saving or AOF rewrite in progress terminated */
1005 if (server.bgsavechildpid != -1 || server.bgrewritechildpid != -1) {
ed9b544e 1006 int statloc;
9d65a1bb 1007 pid_t pid;
1008
1009 if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
1010 if (pid == server.bgsavechildpid) {
1011 backgroundSaveDoneHandler(statloc);
ed9b544e 1012 } else {
9d65a1bb 1013 backgroundRewriteDoneHandler(statloc);
ed9b544e 1014 }
ed9b544e 1015 }
1016 } else {
1017 /* If there is not a background saving in progress check if
1018 * we have to save now */
1019 time_t now = time(NULL);
1020 for (j = 0; j < server.saveparamslen; j++) {
1021 struct saveparam *sp = server.saveparams+j;
1022
1023 if (server.dirty >= sp->changes &&
1024 now-server.lastsave > sp->seconds) {
1025 redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...",
1026 sp->changes, sp->seconds);
f78fd11b 1027 rdbSaveBackground(server.dbfilename);
ed9b544e 1028 break;
1029 }
1030 }
1031 }
94754ccc 1032
f2324293 1033 /* Try to expire a few timed out keys. The algorithm used is adaptive and
1034 * will use few CPU cycles if there are few expiring keys, otherwise
1035 * it will get more aggressive to avoid that too much memory is used by
1036 * keys that can be removed from the keyspace. */
94754ccc 1037 for (j = 0; j < server.dbnum; j++) {
f2324293 1038 int expired;
94754ccc 1039 redisDb *db = server.db+j;
94754ccc 1040
f2324293 1041 /* Continue to expire if at the end of the cycle more than 25%
1042 * of the keys were expired. */
1043 do {
1044 int num = dictSize(db->expires);
94754ccc 1045 time_t now = time(NULL);
1046
f2324293 1047 expired = 0;
94754ccc 1048 if (num > REDIS_EXPIRELOOKUPS_PER_CRON)
1049 num = REDIS_EXPIRELOOKUPS_PER_CRON;
1050 while (num--) {
1051 dictEntry *de;
1052 time_t t;
1053
1054 if ((de = dictGetRandomKey(db->expires)) == NULL) break;
1055 t = (time_t) dictGetEntryVal(de);
1056 if (now > t) {
1057 deleteKey(db,dictGetEntryKey(de));
f2324293 1058 expired++;
94754ccc 1059 }
1060 }
f2324293 1061 } while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/4);
94754ccc 1062 }
1063
ed9b544e 1064 /* Check if we should connect to a MASTER */
1065 if (server.replstate == REDIS_REPL_CONNECT) {
1066 redisLog(REDIS_NOTICE,"Connecting to MASTER...");
1067 if (syncWithMaster() == REDIS_OK) {
1068 redisLog(REDIS_NOTICE,"MASTER <-> SLAVE sync succeeded");
1069 }
1070 }
1071 return 1000;
1072}
1073
1074static void createSharedObjects(void) {
1075 shared.crlf = createObject(REDIS_STRING,sdsnew("\r\n"));
1076 shared.ok = createObject(REDIS_STRING,sdsnew("+OK\r\n"));
1077 shared.err = createObject(REDIS_STRING,sdsnew("-ERR\r\n"));
c937aa89 1078 shared.emptybulk = createObject(REDIS_STRING,sdsnew("$0\r\n\r\n"));
1079 shared.czero = createObject(REDIS_STRING,sdsnew(":0\r\n"));
1080 shared.cone = createObject(REDIS_STRING,sdsnew(":1\r\n"));
1081 shared.nullbulk = createObject(REDIS_STRING,sdsnew("$-1\r\n"));
1082 shared.nullmultibulk = createObject(REDIS_STRING,sdsnew("*-1\r\n"));
1083 shared.emptymultibulk = createObject(REDIS_STRING,sdsnew("*0\r\n"));
ed9b544e 1084 /* no such key */
ed9b544e 1085 shared.pong = createObject(REDIS_STRING,sdsnew("+PONG\r\n"));
1086 shared.wrongtypeerr = createObject(REDIS_STRING,sdsnew(
1087 "-ERR Operation against a key holding the wrong kind of value\r\n"));
ed9b544e 1088 shared.nokeyerr = createObject(REDIS_STRING,sdsnew(
1089 "-ERR no such key\r\n"));
ed9b544e 1090 shared.syntaxerr = createObject(REDIS_STRING,sdsnew(
1091 "-ERR syntax error\r\n"));
c937aa89 1092 shared.sameobjecterr = createObject(REDIS_STRING,sdsnew(
1093 "-ERR source and destination objects are the same\r\n"));
1094 shared.outofrangeerr = createObject(REDIS_STRING,sdsnew(
1095 "-ERR index out of range\r\n"));
ed9b544e 1096 shared.space = createObject(REDIS_STRING,sdsnew(" "));
c937aa89 1097 shared.colon = createObject(REDIS_STRING,sdsnew(":"));
1098 shared.plus = createObject(REDIS_STRING,sdsnew("+"));
ed9b544e 1099 shared.select0 = createStringObject("select 0\r\n",10);
1100 shared.select1 = createStringObject("select 1\r\n",10);
1101 shared.select2 = createStringObject("select 2\r\n",10);
1102 shared.select3 = createStringObject("select 3\r\n",10);
1103 shared.select4 = createStringObject("select 4\r\n",10);
1104 shared.select5 = createStringObject("select 5\r\n",10);
1105 shared.select6 = createStringObject("select 6\r\n",10);
1106 shared.select7 = createStringObject("select 7\r\n",10);
1107 shared.select8 = createStringObject("select 8\r\n",10);
1108 shared.select9 = createStringObject("select 9\r\n",10);
1109}
1110
1111static void appendServerSaveParams(time_t seconds, int changes) {
1112 server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));
ed9b544e 1113 server.saveparams[server.saveparamslen].seconds = seconds;
1114 server.saveparams[server.saveparamslen].changes = changes;
1115 server.saveparamslen++;
1116}
1117
bcfc686d 1118static void resetServerSaveParams() {
ed9b544e 1119 zfree(server.saveparams);
1120 server.saveparams = NULL;
1121 server.saveparamslen = 0;
1122}
1123
1124static void initServerConfig() {
1125 server.dbnum = REDIS_DEFAULT_DBNUM;
1126 server.port = REDIS_SERVERPORT;
1127 server.verbosity = REDIS_DEBUG;
1128 server.maxidletime = REDIS_MAXIDLETIME;
1129 server.saveparams = NULL;
1130 server.logfile = NULL; /* NULL = log on standard output */
1131 server.bindaddr = NULL;
1132 server.glueoutputbuf = 1;
1133 server.daemonize = 0;
44b38ef4 1134 server.appendonly = 0;
4e141d5a 1135 server.appendfsync = APPENDFSYNC_ALWAYS;
48f0308a 1136 server.lastfsync = time(NULL);
44b38ef4 1137 server.appendfd = -1;
1138 server.appendseldb = -1; /* Make sure the first time will not match */
ed329fcf 1139 server.pidfile = "/var/run/redis.pid";
ed9b544e 1140 server.dbfilename = "dump.rdb";
9d65a1bb 1141 server.appendfilename = "appendonly.aof";
abcb223e 1142 server.requirepass = NULL;
10c43610 1143 server.shareobjects = 0;
21aecf4b 1144 server.sharingpoolsize = 1024;
285add55 1145 server.maxclients = 0;
3fd78bcd 1146 server.maxmemory = 0;
bcfc686d 1147 resetServerSaveParams();
ed9b544e 1148
1149 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
1150 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
1151 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1152 /* Replication related */
1153 server.isslave = 0;
d0ccebcf 1154 server.masterauth = NULL;
ed9b544e 1155 server.masterhost = NULL;
1156 server.masterport = 6379;
1157 server.master = NULL;
1158 server.replstate = REDIS_REPL_NONE;
a7866db6 1159
1160 /* Double constants initialization */
1161 R_Zero = 0.0;
1162 R_PosInf = 1.0/R_Zero;
1163 R_NegInf = -1.0/R_Zero;
1164 R_Nan = R_Zero/R_Zero;
ed9b544e 1165}
1166
1167static void initServer() {
1168 int j;
1169
1170 signal(SIGHUP, SIG_IGN);
1171 signal(SIGPIPE, SIG_IGN);
fe3bbfbe 1172 setupSigSegvAction();
ed9b544e 1173
1174 server.clients = listCreate();
1175 server.slaves = listCreate();
87eca727 1176 server.monitors = listCreate();
ed9b544e 1177 server.objfreelist = listCreate();
1178 createSharedObjects();
1179 server.el = aeCreateEventLoop();
3305306f 1180 server.db = zmalloc(sizeof(redisDb)*server.dbnum);
10c43610 1181 server.sharingpool = dictCreate(&setDictType,NULL);
ed9b544e 1182 server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr);
1183 if (server.fd == -1) {
1184 redisLog(REDIS_WARNING, "Opening TCP port: %s", server.neterr);
1185 exit(1);
1186 }
3305306f 1187 for (j = 0; j < server.dbnum; j++) {
1188 server.db[j].dict = dictCreate(&hashDictType,NULL);
1189 server.db[j].expires = dictCreate(&setDictType,NULL);
1190 server.db[j].id = j;
1191 }
ed9b544e 1192 server.cronloops = 0;
9f3c422c 1193 server.bgsavechildpid = -1;
9d65a1bb 1194 server.bgrewritechildpid = -1;
1195 server.bgrewritebuf = sdsempty();
ed9b544e 1196 server.lastsave = time(NULL);
1197 server.dirty = 0;
1198 server.usedmemory = 0;
1199 server.stat_numcommands = 0;
1200 server.stat_numconnections = 0;
1201 server.stat_starttime = time(NULL);
d8f8b666 1202 aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL);
44b38ef4 1203
1204 if (server.appendonly) {
71eba477 1205 server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
44b38ef4 1206 if (server.appendfd == -1) {
1207 redisLog(REDIS_WARNING, "Can't open the append-only file: %s",
1208 strerror(errno));
1209 exit(1);
1210 }
1211 }
ed9b544e 1212}
1213
1214/* Empty the whole database */
ca37e9cd 1215static long long emptyDb() {
ed9b544e 1216 int j;
ca37e9cd 1217 long long removed = 0;
ed9b544e 1218
3305306f 1219 for (j = 0; j < server.dbnum; j++) {
ca37e9cd 1220 removed += dictSize(server.db[j].dict);
3305306f 1221 dictEmpty(server.db[j].dict);
1222 dictEmpty(server.db[j].expires);
1223 }
ca37e9cd 1224 return removed;
ed9b544e 1225}
1226
85dd2f3a 1227static int yesnotoi(char *s) {
1228 if (!strcasecmp(s,"yes")) return 1;
1229 else if (!strcasecmp(s,"no")) return 0;
1230 else return -1;
1231}
1232
ed9b544e 1233/* I agree, this is a very rudimental way to load a configuration...
1234 will improve later if the config gets more complex */
1235static void loadServerConfig(char *filename) {
c9a111ac 1236 FILE *fp;
ed9b544e 1237 char buf[REDIS_CONFIGLINE_MAX+1], *err = NULL;
1238 int linenum = 0;
1239 sds line = NULL;
c9a111ac 1240
1241 if (filename[0] == '-' && filename[1] == '\0')
1242 fp = stdin;
1243 else {
1244 if ((fp = fopen(filename,"r")) == NULL) {
1245 redisLog(REDIS_WARNING,"Fatal error, can't open config file");
1246 exit(1);
1247 }
ed9b544e 1248 }
c9a111ac 1249
ed9b544e 1250 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL) {
1251 sds *argv;
1252 int argc, j;
1253
1254 linenum++;
1255 line = sdsnew(buf);
1256 line = sdstrim(line," \t\r\n");
1257
1258 /* Skip comments and blank lines*/
1259 if (line[0] == '#' || line[0] == '\0') {
1260 sdsfree(line);
1261 continue;
1262 }
1263
1264 /* Split into arguments */
1265 argv = sdssplitlen(line,sdslen(line)," ",1,&argc);
1266 sdstolower(argv[0]);
1267
1268 /* Execute config directives */
bb0b03a3 1269 if (!strcasecmp(argv[0],"timeout") && argc == 2) {
ed9b544e 1270 server.maxidletime = atoi(argv[1]);
0150db36 1271 if (server.maxidletime < 0) {
ed9b544e 1272 err = "Invalid timeout value"; goto loaderr;
1273 }
bb0b03a3 1274 } else if (!strcasecmp(argv[0],"port") && argc == 2) {
ed9b544e 1275 server.port = atoi(argv[1]);
1276 if (server.port < 1 || server.port > 65535) {
1277 err = "Invalid port"; goto loaderr;
1278 }
bb0b03a3 1279 } else if (!strcasecmp(argv[0],"bind") && argc == 2) {
ed9b544e 1280 server.bindaddr = zstrdup(argv[1]);
bb0b03a3 1281 } else if (!strcasecmp(argv[0],"save") && argc == 3) {
ed9b544e 1282 int seconds = atoi(argv[1]);
1283 int changes = atoi(argv[2]);
1284 if (seconds < 1 || changes < 0) {
1285 err = "Invalid save parameters"; goto loaderr;
1286 }
1287 appendServerSaveParams(seconds,changes);
bb0b03a3 1288 } else if (!strcasecmp(argv[0],"dir") && argc == 2) {
ed9b544e 1289 if (chdir(argv[1]) == -1) {
1290 redisLog(REDIS_WARNING,"Can't chdir to '%s': %s",
1291 argv[1], strerror(errno));
1292 exit(1);
1293 }
bb0b03a3 1294 } else if (!strcasecmp(argv[0],"loglevel") && argc == 2) {
1295 if (!strcasecmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG;
1296 else if (!strcasecmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE;
1297 else if (!strcasecmp(argv[1],"warning")) server.verbosity = REDIS_WARNING;
ed9b544e 1298 else {
1299 err = "Invalid log level. Must be one of debug, notice, warning";
1300 goto loaderr;
1301 }
bb0b03a3 1302 } else if (!strcasecmp(argv[0],"logfile") && argc == 2) {
c9a111ac 1303 FILE *logfp;
ed9b544e 1304
1305 server.logfile = zstrdup(argv[1]);
bb0b03a3 1306 if (!strcasecmp(server.logfile,"stdout")) {
ed9b544e 1307 zfree(server.logfile);
1308 server.logfile = NULL;
1309 }
1310 if (server.logfile) {
1311 /* Test if we are able to open the file. The server will not
1312 * be able to abort just for this problem later... */
c9a111ac 1313 logfp = fopen(server.logfile,"a");
1314 if (logfp == NULL) {
ed9b544e 1315 err = sdscatprintf(sdsempty(),
1316 "Can't open the log file: %s", strerror(errno));
1317 goto loaderr;
1318 }
c9a111ac 1319 fclose(logfp);
ed9b544e 1320 }
bb0b03a3 1321 } else if (!strcasecmp(argv[0],"databases") && argc == 2) {
ed9b544e 1322 server.dbnum = atoi(argv[1]);
1323 if (server.dbnum < 1) {
1324 err = "Invalid number of databases"; goto loaderr;
1325 }
285add55 1326 } else if (!strcasecmp(argv[0],"maxclients") && argc == 2) {
1327 server.maxclients = atoi(argv[1]);
3fd78bcd 1328 } else if (!strcasecmp(argv[0],"maxmemory") && argc == 2) {
d4465900 1329 server.maxmemory = strtoll(argv[1], NULL, 10);
bb0b03a3 1330 } else if (!strcasecmp(argv[0],"slaveof") && argc == 3) {
ed9b544e 1331 server.masterhost = sdsnew(argv[1]);
1332 server.masterport = atoi(argv[2]);
1333 server.replstate = REDIS_REPL_CONNECT;
d0ccebcf 1334 } else if (!strcasecmp(argv[0],"masterauth") && argc == 2) {
1335 server.masterauth = zstrdup(argv[1]);
bb0b03a3 1336 } else if (!strcasecmp(argv[0],"glueoutputbuf") && argc == 2) {
85dd2f3a 1337 if ((server.glueoutputbuf = yesnotoi(argv[1])) == -1) {
ed9b544e 1338 err = "argument must be 'yes' or 'no'"; goto loaderr;
1339 }
bb0b03a3 1340 } else if (!strcasecmp(argv[0],"shareobjects") && argc == 2) {
85dd2f3a 1341 if ((server.shareobjects = yesnotoi(argv[1])) == -1) {
10c43610 1342 err = "argument must be 'yes' or 'no'"; goto loaderr;
1343 }
e52c65b9 1344 } else if (!strcasecmp(argv[0],"shareobjectspoolsize") && argc == 2) {
1345 server.sharingpoolsize = atoi(argv[1]);
1346 if (server.sharingpoolsize < 1) {
1347 err = "invalid object sharing pool size"; goto loaderr;
1348 }
bb0b03a3 1349 } else if (!strcasecmp(argv[0],"daemonize") && argc == 2) {
85dd2f3a 1350 if ((server.daemonize = yesnotoi(argv[1])) == -1) {
ed9b544e 1351 err = "argument must be 'yes' or 'no'"; goto loaderr;
1352 }
44b38ef4 1353 } else if (!strcasecmp(argv[0],"appendonly") && argc == 2) {
1354 if ((server.appendonly = yesnotoi(argv[1])) == -1) {
1355 err = "argument must be 'yes' or 'no'"; goto loaderr;
1356 }
48f0308a 1357 } else if (!strcasecmp(argv[0],"appendfsync") && argc == 2) {
1766c6da 1358 if (!strcasecmp(argv[1],"no")) {
48f0308a 1359 server.appendfsync = APPENDFSYNC_NO;
1766c6da 1360 } else if (!strcasecmp(argv[1],"always")) {
48f0308a 1361 server.appendfsync = APPENDFSYNC_ALWAYS;
1766c6da 1362 } else if (!strcasecmp(argv[1],"everysec")) {
48f0308a 1363 server.appendfsync = APPENDFSYNC_EVERYSEC;
1364 } else {
1365 err = "argument must be 'no', 'always' or 'everysec'";
1366 goto loaderr;
1367 }
bb0b03a3 1368 } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
abcb223e 1369 server.requirepass = zstrdup(argv[1]);
bb0b03a3 1370 } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
ed329fcf 1371 server.pidfile = zstrdup(argv[1]);
bb0b03a3 1372 } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) {
b8b553c8 1373 server.dbfilename = zstrdup(argv[1]);
ed9b544e 1374 } else {
1375 err = "Bad directive or wrong number of arguments"; goto loaderr;
1376 }
1377 for (j = 0; j < argc; j++)
1378 sdsfree(argv[j]);
1379 zfree(argv);
1380 sdsfree(line);
1381 }
c9a111ac 1382 if (fp != stdin) fclose(fp);
ed9b544e 1383 return;
1384
1385loaderr:
1386 fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n");
1387 fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
1388 fprintf(stderr, ">>> '%s'\n", line);
1389 fprintf(stderr, "%s\n", err);
1390 exit(1);
1391}
1392
1393static void freeClientArgv(redisClient *c) {
1394 int j;
1395
1396 for (j = 0; j < c->argc; j++)
1397 decrRefCount(c->argv[j]);
e8a74421 1398 for (j = 0; j < c->mbargc; j++)
1399 decrRefCount(c->mbargv[j]);
ed9b544e 1400 c->argc = 0;
e8a74421 1401 c->mbargc = 0;
ed9b544e 1402}
1403
1404static void freeClient(redisClient *c) {
1405 listNode *ln;
1406
1407 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
1408 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
1409 sdsfree(c->querybuf);
1410 listRelease(c->reply);
1411 freeClientArgv(c);
1412 close(c->fd);
1413 ln = listSearchKey(server.clients,c);
dfc5e96c 1414 redisAssert(ln != NULL);
ed9b544e 1415 listDelNode(server.clients,ln);
1416 if (c->flags & REDIS_SLAVE) {
6208b3a7 1417 if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1)
1418 close(c->repldbfd);
87eca727 1419 list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
1420 ln = listSearchKey(l,c);
dfc5e96c 1421 redisAssert(ln != NULL);
87eca727 1422 listDelNode(l,ln);
ed9b544e 1423 }
1424 if (c->flags & REDIS_MASTER) {
1425 server.master = NULL;
1426 server.replstate = REDIS_REPL_CONNECT;
1427 }
93ea3759 1428 zfree(c->argv);
e8a74421 1429 zfree(c->mbargv);
ed9b544e 1430 zfree(c);
1431}
1432
cc30e368 1433#define GLUEREPLY_UP_TO (1024)
ed9b544e 1434static void glueReplyBuffersIfNeeded(redisClient *c) {
c28b42ac 1435 int copylen = 0;
1436 char buf[GLUEREPLY_UP_TO];
6208b3a7 1437 listNode *ln;
ed9b544e 1438 robj *o;
1439
6208b3a7 1440 listRewind(c->reply);
1441 while((ln = listYield(c->reply))) {
c28b42ac 1442 int objlen;
1443
ed9b544e 1444 o = ln->value;
c28b42ac 1445 objlen = sdslen(o->ptr);
1446 if (copylen + objlen <= GLUEREPLY_UP_TO) {
1447 memcpy(buf+copylen,o->ptr,objlen);
1448 copylen += objlen;
ed9b544e 1449 listDelNode(c->reply,ln);
c28b42ac 1450 } else {
1451 if (copylen == 0) return;
1452 break;
ed9b544e 1453 }
ed9b544e 1454 }
c28b42ac 1455 /* Now the output buffer is empty, add the new single element */
1456 o = createObject(REDIS_STRING,sdsnewlen(buf,copylen));
1457 listAddNodeHead(c->reply,o);
ed9b544e 1458}
1459
1460static void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
1461 redisClient *c = privdata;
1462 int nwritten = 0, totwritten = 0, objlen;
1463 robj *o;
1464 REDIS_NOTUSED(el);
1465 REDIS_NOTUSED(mask);
1466
2895e862 1467 /* Use writev() if we have enough buffers to send */
7ea870c0 1468 if (!server.glueoutputbuf &&
1469 listLength(c->reply) > REDIS_WRITEV_THRESHOLD &&
1470 !(c->flags & REDIS_MASTER))
2895e862 1471 {
1472 sendReplyToClientWritev(el, fd, privdata, mask);
1473 return;
1474 }
2895e862 1475
ed9b544e 1476 while(listLength(c->reply)) {
c28b42ac 1477 if (server.glueoutputbuf && listLength(c->reply) > 1)
1478 glueReplyBuffersIfNeeded(c);
1479
ed9b544e 1480 o = listNodeValue(listFirst(c->reply));
1481 objlen = sdslen(o->ptr);
1482
1483 if (objlen == 0) {
1484 listDelNode(c->reply,listFirst(c->reply));
1485 continue;
1486 }
1487
1488 if (c->flags & REDIS_MASTER) {
6f376729 1489 /* Don't reply to a master */
ed9b544e 1490 nwritten = objlen - c->sentlen;
1491 } else {
a4d1ba9a 1492 nwritten = write(fd, ((char*)o->ptr)+c->sentlen, objlen - c->sentlen);
ed9b544e 1493 if (nwritten <= 0) break;
1494 }
1495 c->sentlen += nwritten;
1496 totwritten += nwritten;
1497 /* If we fully sent the object on head go to the next one */
1498 if (c->sentlen == objlen) {
1499 listDelNode(c->reply,listFirst(c->reply));
1500 c->sentlen = 0;
1501 }
6f376729 1502 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
12f9d551 1503 * bytes, in a single threaded server it's a good idea to serve
6f376729 1504 * other clients as well, even if a very large request comes from
1505 * super fast link that is always able to accept data (in real world
12f9d551 1506 * scenario think about 'KEYS *' against the loopback interfae) */
6f376729 1507 if (totwritten > REDIS_MAX_WRITE_PER_EVENT) break;
ed9b544e 1508 }
1509 if (nwritten == -1) {
1510 if (errno == EAGAIN) {
1511 nwritten = 0;
1512 } else {
1513 redisLog(REDIS_DEBUG,
1514 "Error writing to client: %s", strerror(errno));
1515 freeClient(c);
1516 return;
1517 }
1518 }
1519 if (totwritten > 0) c->lastinteraction = time(NULL);
1520 if (listLength(c->reply) == 0) {
1521 c->sentlen = 0;
1522 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
1523 }
1524}
1525
2895e862 1526static void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask)
1527{
1528 redisClient *c = privdata;
1529 int nwritten = 0, totwritten = 0, objlen, willwrite;
1530 robj *o;
1531 struct iovec iov[REDIS_WRITEV_IOVEC_COUNT];
1532 int offset, ion = 0;
1533 REDIS_NOTUSED(el);
1534 REDIS_NOTUSED(mask);
1535
1536 listNode *node;
1537 while (listLength(c->reply)) {
1538 offset = c->sentlen;
1539 ion = 0;
1540 willwrite = 0;
1541
1542 /* fill-in the iov[] array */
1543 for(node = listFirst(c->reply); node; node = listNextNode(node)) {
1544 o = listNodeValue(node);
1545 objlen = sdslen(o->ptr);
1546
1547 if (totwritten + objlen - offset > REDIS_MAX_WRITE_PER_EVENT)
1548 break;
1549
1550 if(ion == REDIS_WRITEV_IOVEC_COUNT)
1551 break; /* no more iovecs */
1552
1553 iov[ion].iov_base = ((char*)o->ptr) + offset;
1554 iov[ion].iov_len = objlen - offset;
1555 willwrite += objlen - offset;
1556 offset = 0; /* just for the first item */
1557 ion++;
1558 }
1559
1560 if(willwrite == 0)
1561 break;
1562
1563 /* write all collected blocks at once */
1564 if((nwritten = writev(fd, iov, ion)) < 0) {
1565 if (errno != EAGAIN) {
1566 redisLog(REDIS_DEBUG,
1567 "Error writing to client: %s", strerror(errno));
1568 freeClient(c);
1569 return;
1570 }
1571 break;
1572 }
1573
1574 totwritten += nwritten;
1575 offset = c->sentlen;
1576
1577 /* remove written robjs from c->reply */
1578 while (nwritten && listLength(c->reply)) {
1579 o = listNodeValue(listFirst(c->reply));
1580 objlen = sdslen(o->ptr);
1581
1582 if(nwritten >= objlen - offset) {
1583 listDelNode(c->reply, listFirst(c->reply));
1584 nwritten -= objlen - offset;
1585 c->sentlen = 0;
1586 } else {
1587 /* partial write */
1588 c->sentlen += nwritten;
1589 break;
1590 }
1591 offset = 0;
1592 }
1593 }
1594
1595 if (totwritten > 0)
1596 c->lastinteraction = time(NULL);
1597
1598 if (listLength(c->reply) == 0) {
1599 c->sentlen = 0;
1600 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
1601 }
1602}
1603
ed9b544e 1604static struct redisCommand *lookupCommand(char *name) {
1605 int j = 0;
1606 while(cmdTable[j].name != NULL) {
bb0b03a3 1607 if (!strcasecmp(name,cmdTable[j].name)) return &cmdTable[j];
ed9b544e 1608 j++;
1609 }
1610 return NULL;
1611}
1612
1613/* resetClient prepare the client to process the next command */
1614static void resetClient(redisClient *c) {
1615 freeClientArgv(c);
1616 c->bulklen = -1;
e8a74421 1617 c->multibulk = 0;
ed9b544e 1618}
1619
1620/* If this function gets called we already read a whole
1621 * command, argments are in the client argv/argc fields.
1622 * processCommand() execute the command or prepare the
1623 * server for a bulk read from the client.
1624 *
1625 * If 1 is returned the client is still alive and valid and
1626 * and other operations can be performed by the caller. Otherwise
1627 * if 0 is returned the client was destroied (i.e. after QUIT). */
1628static int processCommand(redisClient *c) {
1629 struct redisCommand *cmd;
1630 long long dirty;
1631
3fd78bcd 1632 /* Free some memory if needed (maxmemory setting) */
1633 if (server.maxmemory) freeMemoryIfNeeded();
1634
e8a74421 1635 /* Handle the multi bulk command type. This is an alternative protocol
1636 * supported by Redis in order to receive commands that are composed of
1637 * multiple binary-safe "bulk" arguments. The latency of processing is
1638 * a bit higher but this allows things like multi-sets, so if this
1639 * protocol is used only for MSET and similar commands this is a big win. */
1640 if (c->multibulk == 0 && c->argc == 1 && ((char*)(c->argv[0]->ptr))[0] == '*') {
1641 c->multibulk = atoi(((char*)c->argv[0]->ptr)+1);
1642 if (c->multibulk <= 0) {
1643 resetClient(c);
1644 return 1;
1645 } else {
1646 decrRefCount(c->argv[c->argc-1]);
1647 c->argc--;
1648 return 1;
1649 }
1650 } else if (c->multibulk) {
1651 if (c->bulklen == -1) {
1652 if (((char*)c->argv[0]->ptr)[0] != '$') {
1653 addReplySds(c,sdsnew("-ERR multi bulk protocol error\r\n"));
1654 resetClient(c);
1655 return 1;
1656 } else {
1657 int bulklen = atoi(((char*)c->argv[0]->ptr)+1);
1658 decrRefCount(c->argv[0]);
1659 if (bulklen < 0 || bulklen > 1024*1024*1024) {
1660 c->argc--;
1661 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
1662 resetClient(c);
1663 return 1;
1664 }
1665 c->argc--;
1666 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
1667 return 1;
1668 }
1669 } else {
1670 c->mbargv = zrealloc(c->mbargv,(sizeof(robj*))*(c->mbargc+1));
1671 c->mbargv[c->mbargc] = c->argv[0];
1672 c->mbargc++;
1673 c->argc--;
1674 c->multibulk--;
1675 if (c->multibulk == 0) {
1676 robj **auxargv;
1677 int auxargc;
1678
1679 /* Here we need to swap the multi-bulk argc/argv with the
1680 * normal argc/argv of the client structure. */
1681 auxargv = c->argv;
1682 c->argv = c->mbargv;
1683 c->mbargv = auxargv;
1684
1685 auxargc = c->argc;
1686 c->argc = c->mbargc;
1687 c->mbargc = auxargc;
1688
1689 /* We need to set bulklen to something different than -1
1690 * in order for the code below to process the command without
1691 * to try to read the last argument of a bulk command as
1692 * a special argument. */
1693 c->bulklen = 0;
1694 /* continue below and process the command */
1695 } else {
1696 c->bulklen = -1;
1697 return 1;
1698 }
1699 }
1700 }
1701 /* -- end of multi bulk commands processing -- */
1702
ed9b544e 1703 /* The QUIT command is handled as a special case. Normal command
1704 * procs are unable to close the client connection safely */
bb0b03a3 1705 if (!strcasecmp(c->argv[0]->ptr,"quit")) {
ed9b544e 1706 freeClient(c);
1707 return 0;
1708 }
1709 cmd = lookupCommand(c->argv[0]->ptr);
1710 if (!cmd) {
1711 addReplySds(c,sdsnew("-ERR unknown command\r\n"));
1712 resetClient(c);
1713 return 1;
1714 } else if ((cmd->arity > 0 && cmd->arity != c->argc) ||
1715 (c->argc < -cmd->arity)) {
1716 addReplySds(c,sdsnew("-ERR wrong number of arguments\r\n"));
1717 resetClient(c);
1718 return 1;
3fd78bcd 1719 } else if (server.maxmemory && cmd->flags & REDIS_CMD_DENYOOM && zmalloc_used_memory() > server.maxmemory) {
1720 addReplySds(c,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
1721 resetClient(c);
1722 return 1;
ed9b544e 1723 } else if (cmd->flags & REDIS_CMD_BULK && c->bulklen == -1) {
1724 int bulklen = atoi(c->argv[c->argc-1]->ptr);
1725
1726 decrRefCount(c->argv[c->argc-1]);
1727 if (bulklen < 0 || bulklen > 1024*1024*1024) {
1728 c->argc--;
1729 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
1730 resetClient(c);
1731 return 1;
1732 }
1733 c->argc--;
1734 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
1735 /* It is possible that the bulk read is already in the
8d0490e7 1736 * buffer. Check this condition and handle it accordingly.
1737 * This is just a fast path, alternative to call processInputBuffer().
1738 * It's a good idea since the code is small and this condition
1739 * happens most of the times. */
ed9b544e 1740 if ((signed)sdslen(c->querybuf) >= c->bulklen) {
1741 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
1742 c->argc++;
1743 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
1744 } else {
1745 return 1;
1746 }
1747 }
10c43610 1748 /* Let's try to share objects on the command arguments vector */
1749 if (server.shareobjects) {
1750 int j;
1751 for(j = 1; j < c->argc; j++)
1752 c->argv[j] = tryObjectSharing(c->argv[j]);
1753 }
942a3961 1754 /* Let's try to encode the bulk object to save space. */
1755 if (cmd->flags & REDIS_CMD_BULK)
1756 tryObjectEncoding(c->argv[c->argc-1]);
1757
e63943a4 1758 /* Check if the user is authenticated */
1759 if (server.requirepass && !c->authenticated && cmd->proc != authCommand) {
1760 addReplySds(c,sdsnew("-ERR operation not permitted\r\n"));
1761 resetClient(c);
1762 return 1;
1763 }
1764
ed9b544e 1765 /* Exec the command */
1766 dirty = server.dirty;
1767 cmd->proc(c);
33ed1a42 1768 if (server.appendonly && server.dirty-dirty)
44b38ef4 1769 feedAppendOnlyFile(cmd,c->db->id,c->argv,c->argc);
33ed1a42 1770 if (server.dirty-dirty && listLength(server.slaves))
3305306f 1771 replicationFeedSlaves(server.slaves,cmd,c->db->id,c->argv,c->argc);
87eca727 1772 if (listLength(server.monitors))
3305306f 1773 replicationFeedSlaves(server.monitors,cmd,c->db->id,c->argv,c->argc);
ed9b544e 1774 server.stat_numcommands++;
1775
1776 /* Prepare the client for the next command */
1777 if (c->flags & REDIS_CLOSE) {
1778 freeClient(c);
1779 return 0;
1780 }
1781 resetClient(c);
1782 return 1;
1783}
1784
87eca727 1785static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc) {
6208b3a7 1786 listNode *ln;
ed9b544e 1787 int outc = 0, j;
93ea3759 1788 robj **outv;
1789 /* (args*2)+1 is enough room for args, spaces, newlines */
1790 robj *static_outv[REDIS_STATIC_ARGS*2+1];
1791
1792 if (argc <= REDIS_STATIC_ARGS) {
1793 outv = static_outv;
1794 } else {
1795 outv = zmalloc(sizeof(robj*)*(argc*2+1));
93ea3759 1796 }
ed9b544e 1797
1798 for (j = 0; j < argc; j++) {
1799 if (j != 0) outv[outc++] = shared.space;
1800 if ((cmd->flags & REDIS_CMD_BULK) && j == argc-1) {
1801 robj *lenobj;
1802
1803 lenobj = createObject(REDIS_STRING,
682ac724 1804 sdscatprintf(sdsempty(),"%lu\r\n",
0ea663ea 1805 stringObjectLen(argv[j])));
ed9b544e 1806 lenobj->refcount = 0;
1807 outv[outc++] = lenobj;
1808 }
1809 outv[outc++] = argv[j];
1810 }
1811 outv[outc++] = shared.crlf;
1812
40d224a9 1813 /* Increment all the refcounts at start and decrement at end in order to
1814 * be sure to free objects if there is no slave in a replication state
1815 * able to be feed with commands */
1816 for (j = 0; j < outc; j++) incrRefCount(outv[j]);
6208b3a7 1817 listRewind(slaves);
1818 while((ln = listYield(slaves))) {
ed9b544e 1819 redisClient *slave = ln->value;
40d224a9 1820
1821 /* Don't feed slaves that are still waiting for BGSAVE to start */
6208b3a7 1822 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) continue;
40d224a9 1823
1824 /* Feed all the other slaves, MONITORs and so on */
ed9b544e 1825 if (slave->slaveseldb != dictid) {
1826 robj *selectcmd;
1827
1828 switch(dictid) {
1829 case 0: selectcmd = shared.select0; break;
1830 case 1: selectcmd = shared.select1; break;
1831 case 2: selectcmd = shared.select2; break;
1832 case 3: selectcmd = shared.select3; break;
1833 case 4: selectcmd = shared.select4; break;
1834 case 5: selectcmd = shared.select5; break;
1835 case 6: selectcmd = shared.select6; break;
1836 case 7: selectcmd = shared.select7; break;
1837 case 8: selectcmd = shared.select8; break;
1838 case 9: selectcmd = shared.select9; break;
1839 default:
1840 selectcmd = createObject(REDIS_STRING,
1841 sdscatprintf(sdsempty(),"select %d\r\n",dictid));
1842 selectcmd->refcount = 0;
1843 break;
1844 }
1845 addReply(slave,selectcmd);
1846 slave->slaveseldb = dictid;
1847 }
1848 for (j = 0; j < outc; j++) addReply(slave,outv[j]);
ed9b544e 1849 }
40d224a9 1850 for (j = 0; j < outc; j++) decrRefCount(outv[j]);
93ea3759 1851 if (outv != static_outv) zfree(outv);
ed9b544e 1852}
1853
638e42ac 1854static void processInputBuffer(redisClient *c) {
ed9b544e 1855again:
1856 if (c->bulklen == -1) {
1857 /* Read the first line of the query */
1858 char *p = strchr(c->querybuf,'\n');
1859 size_t querylen;
644fafa3 1860
ed9b544e 1861 if (p) {
1862 sds query, *argv;
1863 int argc, j;
1864
1865 query = c->querybuf;
1866 c->querybuf = sdsempty();
1867 querylen = 1+(p-(query));
1868 if (sdslen(query) > querylen) {
1869 /* leave data after the first line of the query in the buffer */
1870 c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
1871 }
1872 *p = '\0'; /* remove "\n" */
1873 if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
1874 sdsupdatelen(query);
1875
1876 /* Now we can split the query in arguments */
1877 if (sdslen(query) == 0) {
1878 /* Ignore empty query */
1879 sdsfree(query);
1880 return;
1881 }
1882 argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
93ea3759 1883 sdsfree(query);
1884
1885 if (c->argv) zfree(c->argv);
1886 c->argv = zmalloc(sizeof(robj*)*argc);
93ea3759 1887
1888 for (j = 0; j < argc; j++) {
ed9b544e 1889 if (sdslen(argv[j])) {
1890 c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
1891 c->argc++;
1892 } else {
1893 sdsfree(argv[j]);
1894 }
1895 }
1896 zfree(argv);
1897 /* Execute the command. If the client is still valid
1898 * after processCommand() return and there is something
1899 * on the query buffer try to process the next command. */
af807d87 1900 if (c->argc && processCommand(c) && sdslen(c->querybuf)) goto again;
ed9b544e 1901 return;
644fafa3 1902 } else if (sdslen(c->querybuf) >= REDIS_REQUEST_MAX_SIZE) {
ed9b544e 1903 redisLog(REDIS_DEBUG, "Client protocol error");
1904 freeClient(c);
1905 return;
1906 }
1907 } else {
1908 /* Bulk read handling. Note that if we are at this point
1909 the client already sent a command terminated with a newline,
1910 we are reading the bulk data that is actually the last
1911 argument of the command. */
1912 int qbl = sdslen(c->querybuf);
1913
1914 if (c->bulklen <= qbl) {
1915 /* Copy everything but the final CRLF as final argument */
1916 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
1917 c->argc++;
1918 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
638e42ac 1919 /* Process the command. If the client is still valid after
1920 * the processing and there is more data in the buffer
1921 * try to parse it. */
1922 if (processCommand(c) && sdslen(c->querybuf)) goto again;
ed9b544e 1923 return;
1924 }
1925 }
1926}
1927
638e42ac 1928static void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
1929 redisClient *c = (redisClient*) privdata;
1930 char buf[REDIS_IOBUF_LEN];
1931 int nread;
1932 REDIS_NOTUSED(el);
1933 REDIS_NOTUSED(mask);
1934
1935 nread = read(fd, buf, REDIS_IOBUF_LEN);
1936 if (nread == -1) {
1937 if (errno == EAGAIN) {
1938 nread = 0;
1939 } else {
1940 redisLog(REDIS_DEBUG, "Reading from client: %s",strerror(errno));
1941 freeClient(c);
1942 return;
1943 }
1944 } else if (nread == 0) {
1945 redisLog(REDIS_DEBUG, "Client closed connection");
1946 freeClient(c);
1947 return;
1948 }
1949 if (nread) {
1950 c->querybuf = sdscatlen(c->querybuf, buf, nread);
1951 c->lastinteraction = time(NULL);
1952 } else {
1953 return;
1954 }
1955 processInputBuffer(c);
1956}
1957
ed9b544e 1958static int selectDb(redisClient *c, int id) {
1959 if (id < 0 || id >= server.dbnum)
1960 return REDIS_ERR;
3305306f 1961 c->db = &server.db[id];
ed9b544e 1962 return REDIS_OK;
1963}
1964
40d224a9 1965static void *dupClientReplyValue(void *o) {
1966 incrRefCount((robj*)o);
1967 return 0;
1968}
1969
ed9b544e 1970static redisClient *createClient(int fd) {
1971 redisClient *c = zmalloc(sizeof(*c));
1972
1973 anetNonBlock(NULL,fd);
1974 anetTcpNoDelay(NULL,fd);
1975 if (!c) return NULL;
1976 selectDb(c,0);
1977 c->fd = fd;
1978 c->querybuf = sdsempty();
1979 c->argc = 0;
93ea3759 1980 c->argv = NULL;
ed9b544e 1981 c->bulklen = -1;
e8a74421 1982 c->multibulk = 0;
1983 c->mbargc = 0;
1984 c->mbargv = NULL;
ed9b544e 1985 c->sentlen = 0;
1986 c->flags = 0;
1987 c->lastinteraction = time(NULL);
abcb223e 1988 c->authenticated = 0;
40d224a9 1989 c->replstate = REDIS_REPL_NONE;
6b47e12e 1990 c->reply = listCreate();
ed9b544e 1991 listSetFreeMethod(c->reply,decrRefCount);
40d224a9 1992 listSetDupMethod(c->reply,dupClientReplyValue);
ed9b544e 1993 if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
266373b2 1994 readQueryFromClient, c) == AE_ERR) {
ed9b544e 1995 freeClient(c);
1996 return NULL;
1997 }
6b47e12e 1998 listAddNodeTail(server.clients,c);
ed9b544e 1999 return c;
2000}
2001
2002static void addReply(redisClient *c, robj *obj) {
2003 if (listLength(c->reply) == 0 &&
6208b3a7 2004 (c->replstate == REDIS_REPL_NONE ||
2005 c->replstate == REDIS_REPL_ONLINE) &&
ed9b544e 2006 aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
266373b2 2007 sendReplyToClient, c) == AE_ERR) return;
9d65a1bb 2008 listAddNodeTail(c->reply,getDecodedObject(obj));
ed9b544e 2009}
2010
2011static void addReplySds(redisClient *c, sds s) {
2012 robj *o = createObject(REDIS_STRING,s);
2013 addReply(c,o);
2014 decrRefCount(o);
2015}
2016
e2665397 2017static void addReplyDouble(redisClient *c, double d) {
2018 char buf[128];
2019
2020 snprintf(buf,sizeof(buf),"%.17g",d);
682ac724 2021 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n%s\r\n",
e2665397 2022 strlen(buf),buf));
2023}
2024
942a3961 2025static void addReplyBulkLen(redisClient *c, robj *obj) {
2026 size_t len;
2027
2028 if (obj->encoding == REDIS_ENCODING_RAW) {
2029 len = sdslen(obj->ptr);
2030 } else {
2031 long n = (long)obj->ptr;
2032
2033 len = 1;
2034 if (n < 0) {
2035 len++;
2036 n = -n;
2037 }
2038 while((n = n/10) != 0) {
2039 len++;
2040 }
2041 }
682ac724 2042 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n",len));
942a3961 2043}
2044
ed9b544e 2045static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
2046 int cport, cfd;
2047 char cip[128];
285add55 2048 redisClient *c;
ed9b544e 2049 REDIS_NOTUSED(el);
2050 REDIS_NOTUSED(mask);
2051 REDIS_NOTUSED(privdata);
2052
2053 cfd = anetAccept(server.neterr, fd, cip, &cport);
2054 if (cfd == AE_ERR) {
2055 redisLog(REDIS_DEBUG,"Accepting client connection: %s", server.neterr);
2056 return;
2057 }
2058 redisLog(REDIS_DEBUG,"Accepted %s:%d", cip, cport);
285add55 2059 if ((c = createClient(cfd)) == NULL) {
ed9b544e 2060 redisLog(REDIS_WARNING,"Error allocating resoures for the client");
2061 close(cfd); /* May be already closed, just ingore errors */
2062 return;
2063 }
285add55 2064 /* If maxclient directive is set and this is one client more... close the
2065 * connection. Note that we create the client instead to check before
2066 * for this condition, since now the socket is already set in nonblocking
2067 * mode and we can send an error for free using the Kernel I/O */
2068 if (server.maxclients && listLength(server.clients) > server.maxclients) {
2069 char *err = "-ERR max number of clients reached\r\n";
2070
2071 /* That's a best effort error message, don't check write errors */
fee803ba 2072 if (write(c->fd,err,strlen(err)) == -1) {
2073 /* Nothing to do, Just to avoid the warning... */
2074 }
285add55 2075 freeClient(c);
2076 return;
2077 }
ed9b544e 2078 server.stat_numconnections++;
2079}
2080
2081/* ======================= Redis objects implementation ===================== */
2082
2083static robj *createObject(int type, void *ptr) {
2084 robj *o;
2085
2086 if (listLength(server.objfreelist)) {
2087 listNode *head = listFirst(server.objfreelist);
2088 o = listNodeValue(head);
2089 listDelNode(server.objfreelist,head);
2090 } else {
2091 o = zmalloc(sizeof(*o));
2092 }
ed9b544e 2093 o->type = type;
942a3961 2094 o->encoding = REDIS_ENCODING_RAW;
ed9b544e 2095 o->ptr = ptr;
2096 o->refcount = 1;
2097 return o;
2098}
2099
2100static robj *createStringObject(char *ptr, size_t len) {
2101 return createObject(REDIS_STRING,sdsnewlen(ptr,len));
2102}
2103
2104static robj *createListObject(void) {
2105 list *l = listCreate();
2106
ed9b544e 2107 listSetFreeMethod(l,decrRefCount);
2108 return createObject(REDIS_LIST,l);
2109}
2110
2111static robj *createSetObject(void) {
2112 dict *d = dictCreate(&setDictType,NULL);
ed9b544e 2113 return createObject(REDIS_SET,d);
2114}
2115
1812e024 2116static robj *createZsetObject(void) {
6b47e12e 2117 zset *zs = zmalloc(sizeof(*zs));
2118
2119 zs->dict = dictCreate(&zsetDictType,NULL);
2120 zs->zsl = zslCreate();
2121 return createObject(REDIS_ZSET,zs);
1812e024 2122}
2123
ed9b544e 2124static void freeStringObject(robj *o) {
942a3961 2125 if (o->encoding == REDIS_ENCODING_RAW) {
2126 sdsfree(o->ptr);
2127 }
ed9b544e 2128}
2129
2130static void freeListObject(robj *o) {
2131 listRelease((list*) o->ptr);
2132}
2133
2134static void freeSetObject(robj *o) {
2135 dictRelease((dict*) o->ptr);
2136}
2137
fd8ccf44 2138static void freeZsetObject(robj *o) {
2139 zset *zs = o->ptr;
2140
2141 dictRelease(zs->dict);
2142 zslFree(zs->zsl);
2143 zfree(zs);
2144}
2145
ed9b544e 2146static void freeHashObject(robj *o) {
2147 dictRelease((dict*) o->ptr);
2148}
2149
2150static void incrRefCount(robj *o) {
2151 o->refcount++;
94754ccc 2152#ifdef DEBUG_REFCOUNT
2153 if (o->type == REDIS_STRING)
2154 printf("Increment '%s'(%p), now is: %d\n",o->ptr,o,o->refcount);
2155#endif
ed9b544e 2156}
2157
2158static void decrRefCount(void *obj) {
2159 robj *o = obj;
94754ccc 2160
2161#ifdef DEBUG_REFCOUNT
2162 if (o->type == REDIS_STRING)
2163 printf("Decrement '%s'(%p), now is: %d\n",o->ptr,o,o->refcount-1);
2164#endif
ed9b544e 2165 if (--(o->refcount) == 0) {
2166 switch(o->type) {
2167 case REDIS_STRING: freeStringObject(o); break;
2168 case REDIS_LIST: freeListObject(o); break;
2169 case REDIS_SET: freeSetObject(o); break;
fd8ccf44 2170 case REDIS_ZSET: freeZsetObject(o); break;
ed9b544e 2171 case REDIS_HASH: freeHashObject(o); break;
dfc5e96c 2172 default: redisAssert(0 != 0); break;
ed9b544e 2173 }
2174 if (listLength(server.objfreelist) > REDIS_OBJFREELIST_MAX ||
2175 !listAddNodeHead(server.objfreelist,o))
2176 zfree(o);
2177 }
2178}
2179
942a3961 2180static robj *lookupKey(redisDb *db, robj *key) {
2181 dictEntry *de = dictFind(db->dict,key);
2182 return de ? dictGetEntryVal(de) : NULL;
2183}
2184
2185static robj *lookupKeyRead(redisDb *db, robj *key) {
2186 expireIfNeeded(db,key);
2187 return lookupKey(db,key);
2188}
2189
2190static robj *lookupKeyWrite(redisDb *db, robj *key) {
2191 deleteIfVolatile(db,key);
2192 return lookupKey(db,key);
2193}
2194
2195static int deleteKey(redisDb *db, robj *key) {
2196 int retval;
2197
2198 /* We need to protect key from destruction: after the first dictDelete()
2199 * it may happen that 'key' is no longer valid if we don't increment
2200 * it's count. This may happen when we get the object reference directly
2201 * from the hash table with dictRandomKey() or dict iterators */
2202 incrRefCount(key);
2203 if (dictSize(db->expires)) dictDelete(db->expires,key);
2204 retval = dictDelete(db->dict,key);
2205 decrRefCount(key);
2206
2207 return retval == DICT_OK;
2208}
2209
10c43610 2210/* Try to share an object against the shared objects pool */
2211static robj *tryObjectSharing(robj *o) {
2212 struct dictEntry *de;
2213 unsigned long c;
2214
3305306f 2215 if (o == NULL || server.shareobjects == 0) return o;
10c43610 2216
dfc5e96c 2217 redisAssert(o->type == REDIS_STRING);
10c43610 2218 de = dictFind(server.sharingpool,o);
2219 if (de) {
2220 robj *shared = dictGetEntryKey(de);
2221
2222 c = ((unsigned long) dictGetEntryVal(de))+1;
2223 dictGetEntryVal(de) = (void*) c;
2224 incrRefCount(shared);
2225 decrRefCount(o);
2226 return shared;
2227 } else {
2228 /* Here we are using a stream algorihtm: Every time an object is
2229 * shared we increment its count, everytime there is a miss we
2230 * recrement the counter of a random object. If this object reaches
2231 * zero we remove the object and put the current object instead. */
3305306f 2232 if (dictSize(server.sharingpool) >=
10c43610 2233 server.sharingpoolsize) {
2234 de = dictGetRandomKey(server.sharingpool);
dfc5e96c 2235 redisAssert(de != NULL);
10c43610 2236 c = ((unsigned long) dictGetEntryVal(de))-1;
2237 dictGetEntryVal(de) = (void*) c;
2238 if (c == 0) {
2239 dictDelete(server.sharingpool,de->key);
2240 }
2241 } else {
2242 c = 0; /* If the pool is empty we want to add this object */
2243 }
2244 if (c == 0) {
2245 int retval;
2246
2247 retval = dictAdd(server.sharingpool,o,(void*)1);
dfc5e96c 2248 redisAssert(retval == DICT_OK);
10c43610 2249 incrRefCount(o);
2250 }
2251 return o;
2252 }
2253}
2254
724a51b1 2255/* Check if the nul-terminated string 's' can be represented by a long
2256 * (that is, is a number that fits into long without any other space or
2257 * character before or after the digits).
2258 *
2259 * If so, the function returns REDIS_OK and *longval is set to the value
2260 * of the number. Otherwise REDIS_ERR is returned */
f69f2cba 2261static int isStringRepresentableAsLong(sds s, long *longval) {
724a51b1 2262 char buf[32], *endptr;
2263 long value;
2264 int slen;
2265
2266 value = strtol(s, &endptr, 10);
2267 if (endptr[0] != '\0') return REDIS_ERR;
2268 slen = snprintf(buf,32,"%ld",value);
2269
2270 /* If the number converted back into a string is not identical
2271 * then it's not possible to encode the string as integer */
f69f2cba 2272 if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR;
724a51b1 2273 if (longval) *longval = value;
2274 return REDIS_OK;
2275}
2276
942a3961 2277/* Try to encode a string object in order to save space */
2278static int tryObjectEncoding(robj *o) {
2279 long value;
942a3961 2280 sds s = o->ptr;
3305306f 2281
942a3961 2282 if (o->encoding != REDIS_ENCODING_RAW)
2283 return REDIS_ERR; /* Already encoded */
3305306f 2284
942a3961 2285 /* It's not save to encode shared objects: shared objects can be shared
2286 * everywhere in the "object space" of Redis. Encoded objects can only
2287 * appear as "values" (and not, for instance, as keys) */
2288 if (o->refcount > 1) return REDIS_ERR;
3305306f 2289
942a3961 2290 /* Currently we try to encode only strings */
dfc5e96c 2291 redisAssert(o->type == REDIS_STRING);
94754ccc 2292
724a51b1 2293 /* Check if we can represent this string as a long integer */
2294 if (isStringRepresentableAsLong(s,&value) == REDIS_ERR) return REDIS_ERR;
942a3961 2295
2296 /* Ok, this object can be encoded */
2297 o->encoding = REDIS_ENCODING_INT;
2298 sdsfree(o->ptr);
2299 o->ptr = (void*) value;
2300 return REDIS_OK;
2301}
2302
9d65a1bb 2303/* Get a decoded version of an encoded object (returned as a new object).
2304 * If the object is already raw-encoded just increment the ref count. */
2305static robj *getDecodedObject(robj *o) {
942a3961 2306 robj *dec;
2307
9d65a1bb 2308 if (o->encoding == REDIS_ENCODING_RAW) {
2309 incrRefCount(o);
2310 return o;
2311 }
942a3961 2312 if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) {
2313 char buf[32];
2314
2315 snprintf(buf,32,"%ld",(long)o->ptr);
2316 dec = createStringObject(buf,strlen(buf));
2317 return dec;
2318 } else {
dfc5e96c 2319 redisAssert(1 != 1);
942a3961 2320 }
3305306f 2321}
2322
d7f43c08 2323/* Compare two string objects via strcmp() or alike.
2324 * Note that the objects may be integer-encoded. In such a case we
2325 * use snprintf() to get a string representation of the numbers on the stack
1fd9bc8a 2326 * and compare the strings, it's much faster than calling getDecodedObject().
2327 *
2328 * Important note: if objects are not integer encoded, but binary-safe strings,
2329 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
2330 * binary safe. */
724a51b1 2331static int compareStringObjects(robj *a, robj *b) {
dfc5e96c 2332 redisAssert(a->type == REDIS_STRING && b->type == REDIS_STRING);
d7f43c08 2333 char bufa[128], bufb[128], *astr, *bstr;
2334 int bothsds = 1;
724a51b1 2335
e197b441 2336 if (a == b) return 0;
d7f43c08 2337 if (a->encoding != REDIS_ENCODING_RAW) {
2338 snprintf(bufa,sizeof(bufa),"%ld",(long) a->ptr);
2339 astr = bufa;
2340 bothsds = 0;
724a51b1 2341 } else {
d7f43c08 2342 astr = a->ptr;
724a51b1 2343 }
d7f43c08 2344 if (b->encoding != REDIS_ENCODING_RAW) {
2345 snprintf(bufb,sizeof(bufb),"%ld",(long) b->ptr);
2346 bstr = bufb;
2347 bothsds = 0;
2348 } else {
2349 bstr = b->ptr;
2350 }
2351 return bothsds ? sdscmp(astr,bstr) : strcmp(astr,bstr);
724a51b1 2352}
2353
0ea663ea 2354static size_t stringObjectLen(robj *o) {
dfc5e96c 2355 redisAssert(o->type == REDIS_STRING);
0ea663ea 2356 if (o->encoding == REDIS_ENCODING_RAW) {
2357 return sdslen(o->ptr);
2358 } else {
2359 char buf[32];
2360
2361 return snprintf(buf,32,"%ld",(long)o->ptr);
2362 }
2363}
2364
ed9b544e 2365/*============================ DB saving/loading ============================ */
2366
f78fd11b 2367static int rdbSaveType(FILE *fp, unsigned char type) {
2368 if (fwrite(&type,1,1,fp) == 0) return -1;
2369 return 0;
2370}
2371
bb32ede5 2372static int rdbSaveTime(FILE *fp, time_t t) {
2373 int32_t t32 = (int32_t) t;
2374 if (fwrite(&t32,4,1,fp) == 0) return -1;
2375 return 0;
2376}
2377
e3566d4b 2378/* check rdbLoadLen() comments for more info */
f78fd11b 2379static int rdbSaveLen(FILE *fp, uint32_t len) {
2380 unsigned char buf[2];
2381
2382 if (len < (1<<6)) {
2383 /* Save a 6 bit len */
10c43610 2384 buf[0] = (len&0xFF)|(REDIS_RDB_6BITLEN<<6);
f78fd11b 2385 if (fwrite(buf,1,1,fp) == 0) return -1;
2386 } else if (len < (1<<14)) {
2387 /* Save a 14 bit len */
10c43610 2388 buf[0] = ((len>>8)&0xFF)|(REDIS_RDB_14BITLEN<<6);
f78fd11b 2389 buf[1] = len&0xFF;
17be1a4a 2390 if (fwrite(buf,2,1,fp) == 0) return -1;
f78fd11b 2391 } else {
2392 /* Save a 32 bit len */
10c43610 2393 buf[0] = (REDIS_RDB_32BITLEN<<6);
f78fd11b 2394 if (fwrite(buf,1,1,fp) == 0) return -1;
2395 len = htonl(len);
2396 if (fwrite(&len,4,1,fp) == 0) return -1;
2397 }
2398 return 0;
2399}
2400
e3566d4b 2401/* String objects in the form "2391" "-100" without any space and with a
2402 * range of values that can fit in an 8, 16 or 32 bit signed value can be
2403 * encoded as integers to save space */
56906eef 2404static int rdbTryIntegerEncoding(sds s, unsigned char *enc) {
e3566d4b 2405 long long value;
2406 char *endptr, buf[32];
2407
2408 /* Check if it's possible to encode this value as a number */
2409 value = strtoll(s, &endptr, 10);
2410 if (endptr[0] != '\0') return 0;
2411 snprintf(buf,32,"%lld",value);
2412
2413 /* If the number converted back into a string is not identical
2414 * then it's not possible to encode the string as integer */
2415 if (strlen(buf) != sdslen(s) || memcmp(buf,s,sdslen(s))) return 0;
2416
2417 /* Finally check if it fits in our ranges */
2418 if (value >= -(1<<7) && value <= (1<<7)-1) {
2419 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT8;
2420 enc[1] = value&0xFF;
2421 return 2;
2422 } else if (value >= -(1<<15) && value <= (1<<15)-1) {
2423 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT16;
2424 enc[1] = value&0xFF;
2425 enc[2] = (value>>8)&0xFF;
2426 return 3;
2427 } else if (value >= -((long long)1<<31) && value <= ((long long)1<<31)-1) {
2428 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT32;
2429 enc[1] = value&0xFF;
2430 enc[2] = (value>>8)&0xFF;
2431 enc[3] = (value>>16)&0xFF;
2432 enc[4] = (value>>24)&0xFF;
2433 return 5;
2434 } else {
2435 return 0;
2436 }
2437}
2438
774e3047 2439static int rdbSaveLzfStringObject(FILE *fp, robj *obj) {
2440 unsigned int comprlen, outlen;
2441 unsigned char byte;
2442 void *out;
2443
2444 /* We require at least four bytes compression for this to be worth it */
2445 outlen = sdslen(obj->ptr)-4;
2446 if (outlen <= 0) return 0;
3a2694c4 2447 if ((out = zmalloc(outlen+1)) == NULL) return 0;
774e3047 2448 comprlen = lzf_compress(obj->ptr, sdslen(obj->ptr), out, outlen);
2449 if (comprlen == 0) {
88e85998 2450 zfree(out);
774e3047 2451 return 0;
2452 }
2453 /* Data compressed! Let's save it on disk */
2454 byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF;
2455 if (fwrite(&byte,1,1,fp) == 0) goto writeerr;
2456 if (rdbSaveLen(fp,comprlen) == -1) goto writeerr;
2457 if (rdbSaveLen(fp,sdslen(obj->ptr)) == -1) goto writeerr;
2458 if (fwrite(out,comprlen,1,fp) == 0) goto writeerr;
88e85998 2459 zfree(out);
774e3047 2460 return comprlen;
2461
2462writeerr:
88e85998 2463 zfree(out);
774e3047 2464 return -1;
2465}
2466
e3566d4b 2467/* Save a string objet as [len][data] on disk. If the object is a string
2468 * representation of an integer value we try to safe it in a special form */
942a3961 2469static int rdbSaveStringObjectRaw(FILE *fp, robj *obj) {
2470 size_t len;
e3566d4b 2471 int enclen;
10c43610 2472
942a3961 2473 len = sdslen(obj->ptr);
2474
774e3047 2475 /* Try integer encoding */
e3566d4b 2476 if (len <= 11) {
2477 unsigned char buf[5];
2478 if ((enclen = rdbTryIntegerEncoding(obj->ptr,buf)) > 0) {
2479 if (fwrite(buf,enclen,1,fp) == 0) return -1;
2480 return 0;
2481 }
2482 }
774e3047 2483
2484 /* Try LZF compression - under 20 bytes it's unable to compress even
88e85998 2485 * aaaaaaaaaaaaaaaaaa so skip it */
942a3961 2486 if (len > 20) {
774e3047 2487 int retval;
2488
2489 retval = rdbSaveLzfStringObject(fp,obj);
2490 if (retval == -1) return -1;
2491 if (retval > 0) return 0;
2492 /* retval == 0 means data can't be compressed, save the old way */
2493 }
2494
2495 /* Store verbatim */
10c43610 2496 if (rdbSaveLen(fp,len) == -1) return -1;
2497 if (len && fwrite(obj->ptr,len,1,fp) == 0) return -1;
2498 return 0;
2499}
2500
942a3961 2501/* Like rdbSaveStringObjectRaw() but handle encoded objects */
2502static int rdbSaveStringObject(FILE *fp, robj *obj) {
2503 int retval;
942a3961 2504
9d65a1bb 2505 obj = getDecodedObject(obj);
2506 retval = rdbSaveStringObjectRaw(fp,obj);
2507 decrRefCount(obj);
2508 return retval;
942a3961 2509}
2510
a7866db6 2511/* Save a double value. Doubles are saved as strings prefixed by an unsigned
2512 * 8 bit integer specifing the length of the representation.
2513 * This 8 bit integer has special values in order to specify the following
2514 * conditions:
2515 * 253: not a number
2516 * 254: + inf
2517 * 255: - inf
2518 */
2519static int rdbSaveDoubleValue(FILE *fp, double val) {
2520 unsigned char buf[128];
2521 int len;
2522
2523 if (isnan(val)) {
2524 buf[0] = 253;
2525 len = 1;
2526 } else if (!isfinite(val)) {
2527 len = 1;
2528 buf[0] = (val < 0) ? 255 : 254;
2529 } else {
eaa256ad 2530 snprintf((char*)buf+1,sizeof(buf)-1,"%.17g",val);
6c446631 2531 buf[0] = strlen((char*)buf+1);
a7866db6 2532 len = buf[0]+1;
2533 }
2534 if (fwrite(buf,len,1,fp) == 0) return -1;
2535 return 0;
2536}
2537
ed9b544e 2538/* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
f78fd11b 2539static int rdbSave(char *filename) {
ed9b544e 2540 dictIterator *di = NULL;
2541 dictEntry *de;
ed9b544e 2542 FILE *fp;
2543 char tmpfile[256];
2544 int j;
bb32ede5 2545 time_t now = time(NULL);
ed9b544e 2546
a3b21203 2547 snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
ed9b544e 2548 fp = fopen(tmpfile,"w");
2549 if (!fp) {
2550 redisLog(REDIS_WARNING, "Failed saving the DB: %s", strerror(errno));
2551 return REDIS_ERR;
2552 }
f78fd11b 2553 if (fwrite("REDIS0001",9,1,fp) == 0) goto werr;
ed9b544e 2554 for (j = 0; j < server.dbnum; j++) {
bb32ede5 2555 redisDb *db = server.db+j;
2556 dict *d = db->dict;
3305306f 2557 if (dictSize(d) == 0) continue;
ed9b544e 2558 di = dictGetIterator(d);
2559 if (!di) {
2560 fclose(fp);
2561 return REDIS_ERR;
2562 }
2563
2564 /* Write the SELECT DB opcode */
f78fd11b 2565 if (rdbSaveType(fp,REDIS_SELECTDB) == -1) goto werr;
2566 if (rdbSaveLen(fp,j) == -1) goto werr;
ed9b544e 2567
2568 /* Iterate this DB writing every entry */
2569 while((de = dictNext(di)) != NULL) {
2570 robj *key = dictGetEntryKey(de);
2571 robj *o = dictGetEntryVal(de);
bb32ede5 2572 time_t expiretime = getExpire(db,key);
2573
2574 /* Save the expire time */
2575 if (expiretime != -1) {
2576 /* If this key is already expired skip it */
2577 if (expiretime < now) continue;
2578 if (rdbSaveType(fp,REDIS_EXPIRETIME) == -1) goto werr;
2579 if (rdbSaveTime(fp,expiretime) == -1) goto werr;
2580 }
2581 /* Save the key and associated value */
f78fd11b 2582 if (rdbSaveType(fp,o->type) == -1) goto werr;
10c43610 2583 if (rdbSaveStringObject(fp,key) == -1) goto werr;
f78fd11b 2584 if (o->type == REDIS_STRING) {
ed9b544e 2585 /* Save a string value */
10c43610 2586 if (rdbSaveStringObject(fp,o) == -1) goto werr;
f78fd11b 2587 } else if (o->type == REDIS_LIST) {
ed9b544e 2588 /* Save a list value */
2589 list *list = o->ptr;
6208b3a7 2590 listNode *ln;
ed9b544e 2591
6208b3a7 2592 listRewind(list);
f78fd11b 2593 if (rdbSaveLen(fp,listLength(list)) == -1) goto werr;
6208b3a7 2594 while((ln = listYield(list))) {
ed9b544e 2595 robj *eleobj = listNodeValue(ln);
f78fd11b 2596
10c43610 2597 if (rdbSaveStringObject(fp,eleobj) == -1) goto werr;
ed9b544e 2598 }
f78fd11b 2599 } else if (o->type == REDIS_SET) {
ed9b544e 2600 /* Save a set value */
2601 dict *set = o->ptr;
2602 dictIterator *di = dictGetIterator(set);
2603 dictEntry *de;
2604
3305306f 2605 if (rdbSaveLen(fp,dictSize(set)) == -1) goto werr;
ed9b544e 2606 while((de = dictNext(di)) != NULL) {
10c43610 2607 robj *eleobj = dictGetEntryKey(de);
ed9b544e 2608
10c43610 2609 if (rdbSaveStringObject(fp,eleobj) == -1) goto werr;
ed9b544e 2610 }
2611 dictReleaseIterator(di);
2b59cfdf 2612 } else if (o->type == REDIS_ZSET) {
2613 /* Save a set value */
2614 zset *zs = o->ptr;
2615 dictIterator *di = dictGetIterator(zs->dict);
2616 dictEntry *de;
2617
2618 if (rdbSaveLen(fp,dictSize(zs->dict)) == -1) goto werr;
2619 while((de = dictNext(di)) != NULL) {
2620 robj *eleobj = dictGetEntryKey(de);
2621 double *score = dictGetEntryVal(de);
2622
2623 if (rdbSaveStringObject(fp,eleobj) == -1) goto werr;
2624 if (rdbSaveDoubleValue(fp,*score) == -1) goto werr;
2625 }
2626 dictReleaseIterator(di);
ed9b544e 2627 } else {
dfc5e96c 2628 redisAssert(0 != 0);
ed9b544e 2629 }
2630 }
2631 dictReleaseIterator(di);
2632 }
2633 /* EOF opcode */
f78fd11b 2634 if (rdbSaveType(fp,REDIS_EOF) == -1) goto werr;
2635
2636 /* Make sure data will not remain on the OS's output buffers */
ed9b544e 2637 fflush(fp);
2638 fsync(fileno(fp));
2639 fclose(fp);
2640
2641 /* Use RENAME to make sure the DB file is changed atomically only
2642 * if the generate DB file is ok. */
2643 if (rename(tmpfile,filename) == -1) {
325d1eb4 2644 redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
ed9b544e 2645 unlink(tmpfile);
2646 return REDIS_ERR;
2647 }
2648 redisLog(REDIS_NOTICE,"DB saved on disk");
2649 server.dirty = 0;
2650 server.lastsave = time(NULL);
2651 return REDIS_OK;
2652
2653werr:
2654 fclose(fp);
2655 unlink(tmpfile);
2656 redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
2657 if (di) dictReleaseIterator(di);
2658 return REDIS_ERR;
2659}
2660
f78fd11b 2661static int rdbSaveBackground(char *filename) {
ed9b544e 2662 pid_t childpid;
2663
9d65a1bb 2664 if (server.bgsavechildpid != -1) return REDIS_ERR;
ed9b544e 2665 if ((childpid = fork()) == 0) {
2666 /* Child */
2667 close(server.fd);
f78fd11b 2668 if (rdbSave(filename) == REDIS_OK) {
ed9b544e 2669 exit(0);
2670 } else {
2671 exit(1);
2672 }
2673 } else {
2674 /* Parent */
5a7c647e 2675 if (childpid == -1) {
2676 redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
2677 strerror(errno));
2678 return REDIS_ERR;
2679 }
ed9b544e 2680 redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
9f3c422c 2681 server.bgsavechildpid = childpid;
ed9b544e 2682 return REDIS_OK;
2683 }
2684 return REDIS_OK; /* unreached */
2685}
2686
a3b21203 2687static void rdbRemoveTempFile(pid_t childpid) {
2688 char tmpfile[256];
2689
2690 snprintf(tmpfile,256,"temp-%d.rdb", (int) childpid);
2691 unlink(tmpfile);
2692}
2693
f78fd11b 2694static int rdbLoadType(FILE *fp) {
2695 unsigned char type;
7b45bfb2 2696 if (fread(&type,1,1,fp) == 0) return -1;
2697 return type;
2698}
2699
bb32ede5 2700static time_t rdbLoadTime(FILE *fp) {
2701 int32_t t32;
2702 if (fread(&t32,4,1,fp) == 0) return -1;
2703 return (time_t) t32;
2704}
2705
e3566d4b 2706/* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
2707 * of this file for a description of how this are stored on disk.
2708 *
2709 * isencoded is set to 1 if the readed length is not actually a length but
2710 * an "encoding type", check the above comments for more info */
2711static uint32_t rdbLoadLen(FILE *fp, int rdbver, int *isencoded) {
f78fd11b 2712 unsigned char buf[2];
2713 uint32_t len;
2714
e3566d4b 2715 if (isencoded) *isencoded = 0;
f78fd11b 2716 if (rdbver == 0) {
2717 if (fread(&len,4,1,fp) == 0) return REDIS_RDB_LENERR;
2718 return ntohl(len);
2719 } else {
17be1a4a 2720 int type;
2721
f78fd11b 2722 if (fread(buf,1,1,fp) == 0) return REDIS_RDB_LENERR;
17be1a4a 2723 type = (buf[0]&0xC0)>>6;
2724 if (type == REDIS_RDB_6BITLEN) {
f78fd11b 2725 /* Read a 6 bit len */
e3566d4b 2726 return buf[0]&0x3F;
2727 } else if (type == REDIS_RDB_ENCVAL) {
2728 /* Read a 6 bit len encoding type */
2729 if (isencoded) *isencoded = 1;
2730 return buf[0]&0x3F;
17be1a4a 2731 } else if (type == REDIS_RDB_14BITLEN) {
f78fd11b 2732 /* Read a 14 bit len */
2733 if (fread(buf+1,1,1,fp) == 0) return REDIS_RDB_LENERR;
2734 return ((buf[0]&0x3F)<<8)|buf[1];
2735 } else {
2736 /* Read a 32 bit len */
2737 if (fread(&len,4,1,fp) == 0) return REDIS_RDB_LENERR;
2738 return ntohl(len);
2739 }
2740 }
f78fd11b 2741}
2742
e3566d4b 2743static robj *rdbLoadIntegerObject(FILE *fp, int enctype) {
2744 unsigned char enc[4];
2745 long long val;
2746
2747 if (enctype == REDIS_RDB_ENC_INT8) {
2748 if (fread(enc,1,1,fp) == 0) return NULL;
2749 val = (signed char)enc[0];
2750 } else if (enctype == REDIS_RDB_ENC_INT16) {
2751 uint16_t v;
2752 if (fread(enc,2,1,fp) == 0) return NULL;
2753 v = enc[0]|(enc[1]<<8);
2754 val = (int16_t)v;
2755 } else if (enctype == REDIS_RDB_ENC_INT32) {
2756 uint32_t v;
2757 if (fread(enc,4,1,fp) == 0) return NULL;
2758 v = enc[0]|(enc[1]<<8)|(enc[2]<<16)|(enc[3]<<24);
2759 val = (int32_t)v;
2760 } else {
2761 val = 0; /* anti-warning */
dfc5e96c 2762 redisAssert(0!=0);
e3566d4b 2763 }
2764 return createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",val));
2765}
2766
88e85998 2767static robj *rdbLoadLzfStringObject(FILE*fp, int rdbver) {
2768 unsigned int len, clen;
2769 unsigned char *c = NULL;
2770 sds val = NULL;
2771
2772 if ((clen = rdbLoadLen(fp,rdbver,NULL)) == REDIS_RDB_LENERR) return NULL;
2773 if ((len = rdbLoadLen(fp,rdbver,NULL)) == REDIS_RDB_LENERR) return NULL;
2774 if ((c = zmalloc(clen)) == NULL) goto err;
2775 if ((val = sdsnewlen(NULL,len)) == NULL) goto err;
2776 if (fread(c,clen,1,fp) == 0) goto err;
2777 if (lzf_decompress(c,clen,val,len) == 0) goto err;
5109cdff 2778 zfree(c);
88e85998 2779 return createObject(REDIS_STRING,val);
2780err:
2781 zfree(c);
2782 sdsfree(val);
2783 return NULL;
2784}
2785
e3566d4b 2786static robj *rdbLoadStringObject(FILE*fp, int rdbver) {
2787 int isencoded;
2788 uint32_t len;
f78fd11b 2789 sds val;
2790
e3566d4b 2791 len = rdbLoadLen(fp,rdbver,&isencoded);
2792 if (isencoded) {
2793 switch(len) {
2794 case REDIS_RDB_ENC_INT8:
2795 case REDIS_RDB_ENC_INT16:
2796 case REDIS_RDB_ENC_INT32:
3305306f 2797 return tryObjectSharing(rdbLoadIntegerObject(fp,len));
88e85998 2798 case REDIS_RDB_ENC_LZF:
2799 return tryObjectSharing(rdbLoadLzfStringObject(fp,rdbver));
e3566d4b 2800 default:
dfc5e96c 2801 redisAssert(0!=0);
e3566d4b 2802 }
2803 }
2804
f78fd11b 2805 if (len == REDIS_RDB_LENERR) return NULL;
2806 val = sdsnewlen(NULL,len);
2807 if (len && fread(val,len,1,fp) == 0) {
2808 sdsfree(val);
2809 return NULL;
2810 }
10c43610 2811 return tryObjectSharing(createObject(REDIS_STRING,val));
f78fd11b 2812}
2813
a7866db6 2814/* For information about double serialization check rdbSaveDoubleValue() */
2815static int rdbLoadDoubleValue(FILE *fp, double *val) {
2816 char buf[128];
2817 unsigned char len;
2818
2819 if (fread(&len,1,1,fp) == 0) return -1;
2820 switch(len) {
2821 case 255: *val = R_NegInf; return 0;
2822 case 254: *val = R_PosInf; return 0;
2823 case 253: *val = R_Nan; return 0;
2824 default:
2825 if (fread(buf,len,1,fp) == 0) return -1;
2826 sscanf(buf, "%lg", val);
2827 return 0;
2828 }
2829}
2830
f78fd11b 2831static int rdbLoad(char *filename) {
ed9b544e 2832 FILE *fp;
f78fd11b 2833 robj *keyobj = NULL;
2834 uint32_t dbid;
bb32ede5 2835 int type, retval, rdbver;
3305306f 2836 dict *d = server.db[0].dict;
bb32ede5 2837 redisDb *db = server.db+0;
f78fd11b 2838 char buf[1024];
bb32ede5 2839 time_t expiretime = -1, now = time(NULL);
2840
ed9b544e 2841 fp = fopen(filename,"r");
2842 if (!fp) return REDIS_ERR;
2843 if (fread(buf,9,1,fp) == 0) goto eoferr;
f78fd11b 2844 buf[9] = '\0';
2845 if (memcmp(buf,"REDIS",5) != 0) {
ed9b544e 2846 fclose(fp);
2847 redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
2848 return REDIS_ERR;
2849 }
f78fd11b 2850 rdbver = atoi(buf+5);
2851 if (rdbver > 1) {
2852 fclose(fp);
2853 redisLog(REDIS_WARNING,"Can't handle RDB format version %d",rdbver);
2854 return REDIS_ERR;
2855 }
ed9b544e 2856 while(1) {
2857 robj *o;
2858
2859 /* Read type. */
f78fd11b 2860 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
bb32ede5 2861 if (type == REDIS_EXPIRETIME) {
2862 if ((expiretime = rdbLoadTime(fp)) == -1) goto eoferr;
2863 /* We read the time so we need to read the object type again */
2864 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
2865 }
ed9b544e 2866 if (type == REDIS_EOF) break;
2867 /* Handle SELECT DB opcode as a special case */
2868 if (type == REDIS_SELECTDB) {
e3566d4b 2869 if ((dbid = rdbLoadLen(fp,rdbver,NULL)) == REDIS_RDB_LENERR)
2870 goto eoferr;
ed9b544e 2871 if (dbid >= (unsigned)server.dbnum) {
f78fd11b 2872 redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum);
ed9b544e 2873 exit(1);
2874 }
bb32ede5 2875 db = server.db+dbid;
2876 d = db->dict;
ed9b544e 2877 continue;
2878 }
2879 /* Read key */
f78fd11b 2880 if ((keyobj = rdbLoadStringObject(fp,rdbver)) == NULL) goto eoferr;
ed9b544e 2881
2882 if (type == REDIS_STRING) {
2883 /* Read string value */
f78fd11b 2884 if ((o = rdbLoadStringObject(fp,rdbver)) == NULL) goto eoferr;
942a3961 2885 tryObjectEncoding(o);
ed9b544e 2886 } else if (type == REDIS_LIST || type == REDIS_SET) {
2887 /* Read list/set value */
2888 uint32_t listlen;
f78fd11b 2889
e3566d4b 2890 if ((listlen = rdbLoadLen(fp,rdbver,NULL)) == REDIS_RDB_LENERR)
f78fd11b 2891 goto eoferr;
ed9b544e 2892 o = (type == REDIS_LIST) ? createListObject() : createSetObject();
2893 /* Load every single element of the list/set */
2894 while(listlen--) {
2895 robj *ele;
2896
f78fd11b 2897 if ((ele = rdbLoadStringObject(fp,rdbver)) == NULL) goto eoferr;
942a3961 2898 tryObjectEncoding(ele);
ed9b544e 2899 if (type == REDIS_LIST) {
6b47e12e 2900 listAddNodeTail((list*)o->ptr,ele);
ed9b544e 2901 } else {
6b47e12e 2902 dictAdd((dict*)o->ptr,ele,NULL);
ed9b544e 2903 }
ed9b544e 2904 }
2b59cfdf 2905 } else if (type == REDIS_ZSET) {
2906 /* Read list/set value */
2907 uint32_t zsetlen;
2908 zset *zs;
2909
2910 if ((zsetlen = rdbLoadLen(fp,rdbver,NULL)) == REDIS_RDB_LENERR)
2911 goto eoferr;
2912 o = createZsetObject();
2913 zs = o->ptr;
2914 /* Load every single element of the list/set */
2915 while(zsetlen--) {
2916 robj *ele;
2917 double *score = zmalloc(sizeof(double));
2918
2919 if ((ele = rdbLoadStringObject(fp,rdbver)) == NULL) goto eoferr;
2920 tryObjectEncoding(ele);
2921 if (rdbLoadDoubleValue(fp,score) == -1) goto eoferr;
2922 dictAdd(zs->dict,ele,score);
2923 zslInsert(zs->zsl,*score,ele);
2924 incrRefCount(ele); /* added to skiplist */
2925 }
ed9b544e 2926 } else {
dfc5e96c 2927 redisAssert(0 != 0);
ed9b544e 2928 }
2929 /* Add the new object in the hash table */
f78fd11b 2930 retval = dictAdd(d,keyobj,o);
ed9b544e 2931 if (retval == DICT_ERR) {
f78fd11b 2932 redisLog(REDIS_WARNING,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj->ptr);
ed9b544e 2933 exit(1);
2934 }
bb32ede5 2935 /* Set the expire time if needed */
2936 if (expiretime != -1) {
2937 setExpire(db,keyobj,expiretime);
2938 /* Delete this key if already expired */
2939 if (expiretime < now) deleteKey(db,keyobj);
2940 expiretime = -1;
2941 }
f78fd11b 2942 keyobj = o = NULL;
ed9b544e 2943 }
2944 fclose(fp);
2945 return REDIS_OK;
2946
2947eoferr: /* unexpected end of file is handled here with a fatal exit */
e3566d4b 2948 if (keyobj) decrRefCount(keyobj);
f80dff62 2949 redisLog(REDIS_WARNING,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
ed9b544e 2950 exit(1);
2951 return REDIS_ERR; /* Just to avoid warning */
2952}
2953
2954/*================================== Commands =============================== */
2955
abcb223e 2956static void authCommand(redisClient *c) {
2e77c2ee 2957 if (!server.requirepass || !strcmp(c->argv[1]->ptr, server.requirepass)) {
abcb223e
BH
2958 c->authenticated = 1;
2959 addReply(c,shared.ok);
2960 } else {
2961 c->authenticated = 0;
fa4c0aba 2962 addReplySds(c,sdscatprintf(sdsempty(),"-ERR invalid password\r\n"));
abcb223e
BH
2963 }
2964}
2965
ed9b544e 2966static void pingCommand(redisClient *c) {
2967 addReply(c,shared.pong);
2968}
2969
2970static void echoCommand(redisClient *c) {
942a3961 2971 addReplyBulkLen(c,c->argv[1]);
ed9b544e 2972 addReply(c,c->argv[1]);
2973 addReply(c,shared.crlf);
2974}
2975
2976/*=================================== Strings =============================== */
2977
2978static void setGenericCommand(redisClient *c, int nx) {
2979 int retval;
2980
3305306f 2981 retval = dictAdd(c->db->dict,c->argv[1],c->argv[2]);
ed9b544e 2982 if (retval == DICT_ERR) {
2983 if (!nx) {
3305306f 2984 dictReplace(c->db->dict,c->argv[1],c->argv[2]);
ed9b544e 2985 incrRefCount(c->argv[2]);
2986 } else {
c937aa89 2987 addReply(c,shared.czero);
ed9b544e 2988 return;
2989 }
2990 } else {
2991 incrRefCount(c->argv[1]);
2992 incrRefCount(c->argv[2]);
2993 }
2994 server.dirty++;
3305306f 2995 removeExpire(c->db,c->argv[1]);
c937aa89 2996 addReply(c, nx ? shared.cone : shared.ok);
ed9b544e 2997}
2998
2999static void setCommand(redisClient *c) {
a4d1ba9a 3000 setGenericCommand(c,0);
ed9b544e 3001}
3002
3003static void setnxCommand(redisClient *c) {
a4d1ba9a 3004 setGenericCommand(c,1);
ed9b544e 3005}
3006
3007static void getCommand(redisClient *c) {
3305306f 3008 robj *o = lookupKeyRead(c->db,c->argv[1]);
3009
3010 if (o == NULL) {
c937aa89 3011 addReply(c,shared.nullbulk);
ed9b544e 3012 } else {
ed9b544e 3013 if (o->type != REDIS_STRING) {
c937aa89 3014 addReply(c,shared.wrongtypeerr);
ed9b544e 3015 } else {
942a3961 3016 addReplyBulkLen(c,o);
ed9b544e 3017 addReply(c,o);
3018 addReply(c,shared.crlf);
3019 }
3020 }
3021}
3022
f6b141c5 3023static void getsetCommand(redisClient *c) {
a431eb74 3024 getCommand(c);
3025 if (dictAdd(c->db->dict,c->argv[1],c->argv[2]) == DICT_ERR) {
3026 dictReplace(c->db->dict,c->argv[1],c->argv[2]);
3027 } else {
3028 incrRefCount(c->argv[1]);
3029 }
3030 incrRefCount(c->argv[2]);
3031 server.dirty++;
3032 removeExpire(c->db,c->argv[1]);
3033}
3034
70003d28 3035static void mgetCommand(redisClient *c) {
70003d28 3036 int j;
3037
c937aa89 3038 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-1));
70003d28 3039 for (j = 1; j < c->argc; j++) {
3305306f 3040 robj *o = lookupKeyRead(c->db,c->argv[j]);
3041 if (o == NULL) {
c937aa89 3042 addReply(c,shared.nullbulk);
70003d28 3043 } else {
70003d28 3044 if (o->type != REDIS_STRING) {
c937aa89 3045 addReply(c,shared.nullbulk);
70003d28 3046 } else {
942a3961 3047 addReplyBulkLen(c,o);
70003d28 3048 addReply(c,o);
3049 addReply(c,shared.crlf);
3050 }
3051 }
3052 }
3053}
3054
6c446631 3055static void msetGenericCommand(redisClient *c, int nx) {
3056 int j;
3057
3058 if ((c->argc % 2) == 0) {
3059 addReplySds(c,sdsnew("-ERR wrong number of arguments\r\n"));
3060 return;
3061 }
3062 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
3063 * set nothing at all if at least one already key exists. */
3064 if (nx) {
3065 for (j = 1; j < c->argc; j += 2) {
3066 if (dictFind(c->db->dict,c->argv[j]) != NULL) {
3067 addReply(c, shared.czero);
3068 return;
3069 }
3070 }
3071 }
3072
3073 for (j = 1; j < c->argc; j += 2) {
3074 int retval;
3075
17511391 3076 tryObjectEncoding(c->argv[j+1]);
6c446631 3077 retval = dictAdd(c->db->dict,c->argv[j],c->argv[j+1]);
3078 if (retval == DICT_ERR) {
3079 dictReplace(c->db->dict,c->argv[j],c->argv[j+1]);
3080 incrRefCount(c->argv[j+1]);
3081 } else {
3082 incrRefCount(c->argv[j]);
3083 incrRefCount(c->argv[j+1]);
3084 }
3085 removeExpire(c->db,c->argv[j]);
3086 }
3087 server.dirty += (c->argc-1)/2;
3088 addReply(c, nx ? shared.cone : shared.ok);
3089}
3090
3091static void msetCommand(redisClient *c) {
3092 msetGenericCommand(c,0);
3093}
3094
3095static void msetnxCommand(redisClient *c) {
3096 msetGenericCommand(c,1);
3097}
3098
d68ed120 3099static void incrDecrCommand(redisClient *c, long long incr) {
ed9b544e 3100 long long value;
3101 int retval;
3102 robj *o;
3103
3305306f 3104 o = lookupKeyWrite(c->db,c->argv[1]);
3105 if (o == NULL) {
ed9b544e 3106 value = 0;
3107 } else {
ed9b544e 3108 if (o->type != REDIS_STRING) {
3109 value = 0;
3110 } else {
3111 char *eptr;
3112
942a3961 3113 if (o->encoding == REDIS_ENCODING_RAW)
3114 value = strtoll(o->ptr, &eptr, 10);
3115 else if (o->encoding == REDIS_ENCODING_INT)
3116 value = (long)o->ptr;
3117 else
dfc5e96c 3118 redisAssert(1 != 1);
ed9b544e 3119 }
3120 }
3121
3122 value += incr;
3123 o = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
942a3961 3124 tryObjectEncoding(o);
3305306f 3125 retval = dictAdd(c->db->dict,c->argv[1],o);
ed9b544e 3126 if (retval == DICT_ERR) {
3305306f 3127 dictReplace(c->db->dict,c->argv[1],o);
3128 removeExpire(c->db,c->argv[1]);
ed9b544e 3129 } else {
3130 incrRefCount(c->argv[1]);
3131 }
3132 server.dirty++;
c937aa89 3133 addReply(c,shared.colon);
ed9b544e 3134 addReply(c,o);
3135 addReply(c,shared.crlf);
3136}
3137
3138static void incrCommand(redisClient *c) {
a4d1ba9a 3139 incrDecrCommand(c,1);
ed9b544e 3140}
3141
3142static void decrCommand(redisClient *c) {
a4d1ba9a 3143 incrDecrCommand(c,-1);
ed9b544e 3144}
3145
3146static void incrbyCommand(redisClient *c) {
d68ed120 3147 long long incr = strtoll(c->argv[2]->ptr, NULL, 10);
a4d1ba9a 3148 incrDecrCommand(c,incr);
ed9b544e 3149}
3150
3151static void decrbyCommand(redisClient *c) {
d68ed120 3152 long long incr = strtoll(c->argv[2]->ptr, NULL, 10);
a4d1ba9a 3153 incrDecrCommand(c,-incr);
ed9b544e 3154}
3155
3156/* ========================= Type agnostic commands ========================= */
3157
3158static void delCommand(redisClient *c) {
5109cdff 3159 int deleted = 0, j;
3160
3161 for (j = 1; j < c->argc; j++) {
3162 if (deleteKey(c->db,c->argv[j])) {
3163 server.dirty++;
3164 deleted++;
3165 }
3166 }
3167 switch(deleted) {
3168 case 0:
c937aa89 3169 addReply(c,shared.czero);
5109cdff 3170 break;
3171 case 1:
3172 addReply(c,shared.cone);
3173 break;
3174 default:
3175 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",deleted));
3176 break;
ed9b544e 3177 }
3178}
3179
3180static void existsCommand(redisClient *c) {
3305306f 3181 addReply(c,lookupKeyRead(c->db,c->argv[1]) ? shared.cone : shared.czero);
ed9b544e 3182}
3183
3184static void selectCommand(redisClient *c) {
3185 int id = atoi(c->argv[1]->ptr);
3186
3187 if (selectDb(c,id) == REDIS_ERR) {
774e3047 3188 addReplySds(c,sdsnew("-ERR invalid DB index\r\n"));
ed9b544e 3189 } else {
3190 addReply(c,shared.ok);
3191 }
3192}
3193
3194static void randomkeyCommand(redisClient *c) {
3195 dictEntry *de;
3305306f 3196
3197 while(1) {
3198 de = dictGetRandomKey(c->db->dict);
ce7bef07 3199 if (!de || expireIfNeeded(c->db,dictGetEntryKey(de)) == 0) break;
3305306f 3200 }
ed9b544e 3201 if (de == NULL) {
ce7bef07 3202 addReply(c,shared.plus);
ed9b544e 3203 addReply(c,shared.crlf);
3204 } else {
c937aa89 3205 addReply(c,shared.plus);
ed9b544e 3206 addReply(c,dictGetEntryKey(de));
3207 addReply(c,shared.crlf);
3208 }
3209}
3210
3211static void keysCommand(redisClient *c) {
3212 dictIterator *di;
3213 dictEntry *de;
3214 sds pattern = c->argv[1]->ptr;
3215 int plen = sdslen(pattern);
682ac724 3216 unsigned long numkeys = 0, keyslen = 0;
ed9b544e 3217 robj *lenobj = createObject(REDIS_STRING,NULL);
3218
3305306f 3219 di = dictGetIterator(c->db->dict);
ed9b544e 3220 addReply(c,lenobj);
3221 decrRefCount(lenobj);
3222 while((de = dictNext(di)) != NULL) {
3223 robj *keyobj = dictGetEntryKey(de);
3305306f 3224
ed9b544e 3225 sds key = keyobj->ptr;
3226 if ((pattern[0] == '*' && pattern[1] == '\0') ||
3227 stringmatchlen(pattern,plen,key,sdslen(key),0)) {
3305306f 3228 if (expireIfNeeded(c->db,keyobj) == 0) {
3229 if (numkeys != 0)
3230 addReply(c,shared.space);
3231 addReply(c,keyobj);
3232 numkeys++;
3233 keyslen += sdslen(key);
3234 }
ed9b544e 3235 }
3236 }
3237 dictReleaseIterator(di);
c937aa89 3238 lenobj->ptr = sdscatprintf(sdsempty(),"$%lu\r\n",keyslen+(numkeys ? (numkeys-1) : 0));
ed9b544e 3239 addReply(c,shared.crlf);
3240}
3241
3242static void dbsizeCommand(redisClient *c) {
3243 addReplySds(c,
3305306f 3244 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c->db->dict)));
ed9b544e 3245}
3246
3247static void lastsaveCommand(redisClient *c) {
3248 addReplySds(c,
c937aa89 3249 sdscatprintf(sdsempty(),":%lu\r\n",server.lastsave));
ed9b544e 3250}
3251
3252static void typeCommand(redisClient *c) {
3305306f 3253 robj *o;
ed9b544e 3254 char *type;
3305306f 3255
3256 o = lookupKeyRead(c->db,c->argv[1]);
3257 if (o == NULL) {
c937aa89 3258 type = "+none";
ed9b544e 3259 } else {
ed9b544e 3260 switch(o->type) {
c937aa89 3261 case REDIS_STRING: type = "+string"; break;
3262 case REDIS_LIST: type = "+list"; break;
3263 case REDIS_SET: type = "+set"; break;
412a8bce 3264 case REDIS_ZSET: type = "+zset"; break;
ed9b544e 3265 default: type = "unknown"; break;
3266 }
3267 }
3268 addReplySds(c,sdsnew(type));
3269 addReply(c,shared.crlf);
3270}
3271
3272static void saveCommand(redisClient *c) {
9d65a1bb 3273 if (server.bgsavechildpid != -1) {
05557f6d 3274 addReplySds(c,sdsnew("-ERR background save in progress\r\n"));
3275 return;
3276 }
f78fd11b 3277 if (rdbSave(server.dbfilename) == REDIS_OK) {
ed9b544e 3278 addReply(c,shared.ok);
3279 } else {
3280 addReply(c,shared.err);
3281 }
3282}
3283
3284static void bgsaveCommand(redisClient *c) {
9d65a1bb 3285 if (server.bgsavechildpid != -1) {
ed9b544e 3286 addReplySds(c,sdsnew("-ERR background save already in progress\r\n"));
3287 return;
3288 }
f78fd11b 3289 if (rdbSaveBackground(server.dbfilename) == REDIS_OK) {
ed9b544e 3290 addReply(c,shared.ok);
3291 } else {
3292 addReply(c,shared.err);
3293 }
3294}
3295
3296static void shutdownCommand(redisClient *c) {
3297 redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
a3b21203 3298 /* Kill the saving child if there is a background saving in progress.
3299 We want to avoid race conditions, for instance our saving child may
3300 overwrite the synchronous saving did by SHUTDOWN. */
9d65a1bb 3301 if (server.bgsavechildpid != -1) {
9f3c422c 3302 redisLog(REDIS_WARNING,"There is a live saving child. Killing it!");
3303 kill(server.bgsavechildpid,SIGKILL);
a3b21203 3304 rdbRemoveTempFile(server.bgsavechildpid);
9f3c422c 3305 }
a3b21203 3306 /* SYNC SAVE */
f78fd11b 3307 if (rdbSave(server.dbfilename) == REDIS_OK) {
9f3c422c 3308 if (server.daemonize)
b284af55 3309 unlink(server.pidfile);
b284af55 3310 redisLog(REDIS_WARNING,"%zu bytes used at exit",zmalloc_used_memory());
ed9b544e 3311 redisLog(REDIS_WARNING,"Server exit now, bye bye...");
3312 exit(1);
3313 } else {
a3b21203 3314 /* Ooops.. error saving! The best we can do is to continue operating.
3315 * Note that if there was a background saving process, in the next
3316 * cron() Redis will be notified that the background saving aborted,
3317 * handling special stuff like slaves pending for synchronization... */
ed9b544e 3318 redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
3319 addReplySds(c,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
3320 }
3321}
3322
3323static void renameGenericCommand(redisClient *c, int nx) {
ed9b544e 3324 robj *o;
3325
3326 /* To use the same key as src and dst is probably an error */
3327 if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) {
c937aa89 3328 addReply(c,shared.sameobjecterr);
ed9b544e 3329 return;
3330 }
3331
3305306f 3332 o = lookupKeyWrite(c->db,c->argv[1]);
3333 if (o == NULL) {
c937aa89 3334 addReply(c,shared.nokeyerr);
ed9b544e 3335 return;
3336 }
ed9b544e 3337 incrRefCount(o);
3305306f 3338 deleteIfVolatile(c->db,c->argv[2]);
3339 if (dictAdd(c->db->dict,c->argv[2],o) == DICT_ERR) {
ed9b544e 3340 if (nx) {
3341 decrRefCount(o);
c937aa89 3342 addReply(c,shared.czero);
ed9b544e 3343 return;
3344 }
3305306f 3345 dictReplace(c->db->dict,c->argv[2],o);
ed9b544e 3346 } else {
3347 incrRefCount(c->argv[2]);
3348 }
3305306f 3349 deleteKey(c->db,c->argv[1]);
ed9b544e 3350 server.dirty++;
c937aa89 3351 addReply(c,nx ? shared.cone : shared.ok);
ed9b544e 3352}
3353
3354static void renameCommand(redisClient *c) {
3355 renameGenericCommand(c,0);
3356}
3357
3358static void renamenxCommand(redisClient *c) {
3359 renameGenericCommand(c,1);
3360}
3361
3362static void moveCommand(redisClient *c) {
3305306f 3363 robj *o;
3364 redisDb *src, *dst;
ed9b544e 3365 int srcid;
3366
3367 /* Obtain source and target DB pointers */
3305306f 3368 src = c->db;
3369 srcid = c->db->id;
ed9b544e 3370 if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) {
c937aa89 3371 addReply(c,shared.outofrangeerr);
ed9b544e 3372 return;
3373 }
3305306f 3374 dst = c->db;
3375 selectDb(c,srcid); /* Back to the source DB */
ed9b544e 3376
3377 /* If the user is moving using as target the same
3378 * DB as the source DB it is probably an error. */
3379 if (src == dst) {
c937aa89 3380 addReply(c,shared.sameobjecterr);
ed9b544e 3381 return;
3382 }
3383
3384 /* Check if the element exists and get a reference */
3305306f 3385 o = lookupKeyWrite(c->db,c->argv[1]);
3386 if (!o) {
c937aa89 3387 addReply(c,shared.czero);
ed9b544e 3388 return;
3389 }
3390
3391 /* Try to add the element to the target DB */
3305306f 3392 deleteIfVolatile(dst,c->argv[1]);
3393 if (dictAdd(dst->dict,c->argv[1],o) == DICT_ERR) {
c937aa89 3394 addReply(c,shared.czero);
ed9b544e 3395 return;
3396 }
3305306f 3397 incrRefCount(c->argv[1]);
ed9b544e 3398 incrRefCount(o);
3399
3400 /* OK! key moved, free the entry in the source DB */
3305306f 3401 deleteKey(src,c->argv[1]);
ed9b544e 3402 server.dirty++;
c937aa89 3403 addReply(c,shared.cone);
ed9b544e 3404}
3405
3406/* =================================== Lists ================================ */
3407static void pushGenericCommand(redisClient *c, int where) {
3408 robj *lobj;
ed9b544e 3409 list *list;
3305306f 3410
3411 lobj = lookupKeyWrite(c->db,c->argv[1]);
3412 if (lobj == NULL) {
ed9b544e 3413 lobj = createListObject();
3414 list = lobj->ptr;
3415 if (where == REDIS_HEAD) {
6b47e12e 3416 listAddNodeHead(list,c->argv[2]);
ed9b544e 3417 } else {
6b47e12e 3418 listAddNodeTail(list,c->argv[2]);
ed9b544e 3419 }
3305306f 3420 dictAdd(c->db->dict,c->argv[1],lobj);
ed9b544e 3421 incrRefCount(c->argv[1]);
3422 incrRefCount(c->argv[2]);
3423 } else {
ed9b544e 3424 if (lobj->type != REDIS_LIST) {
3425 addReply(c,shared.wrongtypeerr);
3426 return;
3427 }
3428 list = lobj->ptr;
3429 if (where == REDIS_HEAD) {
6b47e12e 3430 listAddNodeHead(list,c->argv[2]);
ed9b544e 3431 } else {
6b47e12e 3432 listAddNodeTail(list,c->argv[2]);
ed9b544e 3433 }
3434 incrRefCount(c->argv[2]);
3435 }
3436 server.dirty++;
3437 addReply(c,shared.ok);
3438}
3439
3440static void lpushCommand(redisClient *c) {
3441 pushGenericCommand(c,REDIS_HEAD);
3442}
3443
3444static void rpushCommand(redisClient *c) {
3445 pushGenericCommand(c,REDIS_TAIL);
3446}
3447
3448static void llenCommand(redisClient *c) {
3305306f 3449 robj *o;
ed9b544e 3450 list *l;
3451
3305306f 3452 o = lookupKeyRead(c->db,c->argv[1]);
3453 if (o == NULL) {
c937aa89 3454 addReply(c,shared.czero);
ed9b544e 3455 return;
3456 } else {
ed9b544e 3457 if (o->type != REDIS_LIST) {
c937aa89 3458 addReply(c,shared.wrongtypeerr);
ed9b544e 3459 } else {
3460 l = o->ptr;
c937aa89 3461 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",listLength(l)));
ed9b544e 3462 }
3463 }
3464}
3465
3466static void lindexCommand(redisClient *c) {
3305306f 3467 robj *o;
ed9b544e 3468 int index = atoi(c->argv[2]->ptr);
3469
3305306f 3470 o = lookupKeyRead(c->db,c->argv[1]);
3471 if (o == NULL) {
c937aa89 3472 addReply(c,shared.nullbulk);
ed9b544e 3473 } else {
ed9b544e 3474 if (o->type != REDIS_LIST) {
c937aa89 3475 addReply(c,shared.wrongtypeerr);
ed9b544e 3476 } else {
3477 list *list = o->ptr;
3478 listNode *ln;
3479
3480 ln = listIndex(list, index);
3481 if (ln == NULL) {
c937aa89 3482 addReply(c,shared.nullbulk);
ed9b544e 3483 } else {
3484 robj *ele = listNodeValue(ln);
942a3961 3485 addReplyBulkLen(c,ele);
ed9b544e 3486 addReply(c,ele);
3487 addReply(c,shared.crlf);
3488 }
3489 }
3490 }
3491}
3492
3493static void lsetCommand(redisClient *c) {
3305306f 3494 robj *o;
ed9b544e 3495 int index = atoi(c->argv[2]->ptr);
3496
3305306f 3497 o = lookupKeyWrite(c->db,c->argv[1]);
3498 if (o == NULL) {
ed9b544e 3499 addReply(c,shared.nokeyerr);
3500 } else {
ed9b544e 3501 if (o->type != REDIS_LIST) {
3502 addReply(c,shared.wrongtypeerr);
3503 } else {
3504 list *list = o->ptr;
3505 listNode *ln;
3506
3507 ln = listIndex(list, index);
3508 if (ln == NULL) {
c937aa89 3509 addReply(c,shared.outofrangeerr);
ed9b544e 3510 } else {
3511 robj *ele = listNodeValue(ln);
3512
3513 decrRefCount(ele);
3514 listNodeValue(ln) = c->argv[3];
3515 incrRefCount(c->argv[3]);
3516 addReply(c,shared.ok);
3517 server.dirty++;
3518 }
3519 }
3520 }
3521}
3522
3523static void popGenericCommand(redisClient *c, int where) {
3305306f 3524 robj *o;
3525
3526 o = lookupKeyWrite(c->db,c->argv[1]);
3527 if (o == NULL) {
c937aa89 3528 addReply(c,shared.nullbulk);
ed9b544e 3529 } else {
ed9b544e 3530 if (o->type != REDIS_LIST) {
c937aa89 3531 addReply(c,shared.wrongtypeerr);
ed9b544e 3532 } else {
3533 list *list = o->ptr;
3534 listNode *ln;
3535
3536 if (where == REDIS_HEAD)
3537 ln = listFirst(list);
3538 else
3539 ln = listLast(list);
3540
3541 if (ln == NULL) {
c937aa89 3542 addReply(c,shared.nullbulk);
ed9b544e 3543 } else {
3544 robj *ele = listNodeValue(ln);
942a3961 3545 addReplyBulkLen(c,ele);
ed9b544e 3546 addReply(c,ele);
3547 addReply(c,shared.crlf);
3548 listDelNode(list,ln);
3549 server.dirty++;
3550 }
3551 }
3552 }
3553}
3554
3555static void lpopCommand(redisClient *c) {
3556 popGenericCommand(c,REDIS_HEAD);
3557}
3558
3559static void rpopCommand(redisClient *c) {
3560 popGenericCommand(c,REDIS_TAIL);
3561}
3562
3563static void lrangeCommand(redisClient *c) {
3305306f 3564 robj *o;
ed9b544e 3565 int start = atoi(c->argv[2]->ptr);
3566 int end = atoi(c->argv[3]->ptr);
3305306f 3567
3568 o = lookupKeyRead(c->db,c->argv[1]);
3569 if (o == NULL) {
c937aa89 3570 addReply(c,shared.nullmultibulk);
ed9b544e 3571 } else {
ed9b544e 3572 if (o->type != REDIS_LIST) {
c937aa89 3573 addReply(c,shared.wrongtypeerr);
ed9b544e 3574 } else {
3575 list *list = o->ptr;
3576 listNode *ln;
3577 int llen = listLength(list);
3578 int rangelen, j;
3579 robj *ele;
3580
3581 /* convert negative indexes */
3582 if (start < 0) start = llen+start;
3583 if (end < 0) end = llen+end;
3584 if (start < 0) start = 0;
3585 if (end < 0) end = 0;
3586
3587 /* indexes sanity checks */
3588 if (start > end || start >= llen) {
3589 /* Out of range start or start > end result in empty list */
c937aa89 3590 addReply(c,shared.emptymultibulk);
ed9b544e 3591 return;
3592 }
3593 if (end >= llen) end = llen-1;
3594 rangelen = (end-start)+1;
3595
3596 /* Return the result in form of a multi-bulk reply */
3597 ln = listIndex(list, start);
c937aa89 3598 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen));
ed9b544e 3599 for (j = 0; j < rangelen; j++) {
3600 ele = listNodeValue(ln);
942a3961 3601 addReplyBulkLen(c,ele);
ed9b544e 3602 addReply(c,ele);
3603 addReply(c,shared.crlf);
3604 ln = ln->next;
3605 }
3606 }
3607 }
3608}
3609
3610static void ltrimCommand(redisClient *c) {
3305306f 3611 robj *o;
ed9b544e 3612 int start = atoi(c->argv[2]->ptr);
3613 int end = atoi(c->argv[3]->ptr);
3614
3305306f 3615 o = lookupKeyWrite(c->db,c->argv[1]);
3616 if (o == NULL) {
ed9b544e 3617 addReply(c,shared.nokeyerr);
3618 } else {
ed9b544e 3619 if (o->type != REDIS_LIST) {
3620 addReply(c,shared.wrongtypeerr);
3621 } else {
3622 list *list = o->ptr;
3623 listNode *ln;
3624 int llen = listLength(list);
3625 int j, ltrim, rtrim;
3626
3627 /* convert negative indexes */
3628 if (start < 0) start = llen+start;
3629 if (end < 0) end = llen+end;
3630 if (start < 0) start = 0;
3631 if (end < 0) end = 0;
3632
3633 /* indexes sanity checks */
3634 if (start > end || start >= llen) {
3635 /* Out of range start or start > end result in empty list */
3636 ltrim = llen;
3637 rtrim = 0;
3638 } else {
3639 if (end >= llen) end = llen-1;
3640 ltrim = start;
3641 rtrim = llen-end-1;
3642 }
3643
3644 /* Remove list elements to perform the trim */
3645 for (j = 0; j < ltrim; j++) {
3646 ln = listFirst(list);
3647 listDelNode(list,ln);
3648 }
3649 for (j = 0; j < rtrim; j++) {
3650 ln = listLast(list);
3651 listDelNode(list,ln);
3652 }
ed9b544e 3653 server.dirty++;
e59229a2 3654 addReply(c,shared.ok);
ed9b544e 3655 }
3656 }
3657}
3658
3659static void lremCommand(redisClient *c) {
3305306f 3660 robj *o;
ed9b544e 3661
3305306f 3662 o = lookupKeyWrite(c->db,c->argv[1]);
3663 if (o == NULL) {
33c08b39 3664 addReply(c,shared.czero);
ed9b544e 3665 } else {
ed9b544e 3666 if (o->type != REDIS_LIST) {
c937aa89 3667 addReply(c,shared.wrongtypeerr);
ed9b544e 3668 } else {
3669 list *list = o->ptr;
3670 listNode *ln, *next;
3671 int toremove = atoi(c->argv[2]->ptr);
3672 int removed = 0;
3673 int fromtail = 0;
3674
3675 if (toremove < 0) {
3676 toremove = -toremove;
3677 fromtail = 1;
3678 }
3679 ln = fromtail ? list->tail : list->head;
3680 while (ln) {
ed9b544e 3681 robj *ele = listNodeValue(ln);
a4d1ba9a 3682
3683 next = fromtail ? ln->prev : ln->next;
724a51b1 3684 if (compareStringObjects(ele,c->argv[3]) == 0) {
ed9b544e 3685 listDelNode(list,ln);
3686 server.dirty++;
3687 removed++;
3688 if (toremove && removed == toremove) break;
3689 }
3690 ln = next;
3691 }
c937aa89 3692 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",removed));
ed9b544e 3693 }
3694 }
3695}
3696
12f9d551 3697/* This is the semantic of this command:
0f5f7e9a 3698 * RPOPLPUSH srclist dstlist:
12f9d551 3699 * IF LLEN(srclist) > 0
3700 * element = RPOP srclist
3701 * LPUSH dstlist element
3702 * RETURN element
3703 * ELSE
3704 * RETURN nil
3705 * END
3706 * END
3707 *
3708 * The idea is to be able to get an element from a list in a reliable way
3709 * since the element is not just returned but pushed against another list
3710 * as well. This command was originally proposed by Ezra Zygmuntowicz.
3711 */
0f5f7e9a 3712static void rpoplpushcommand(redisClient *c) {
12f9d551 3713 robj *sobj;
3714
3715 sobj = lookupKeyWrite(c->db,c->argv[1]);
3716 if (sobj == NULL) {
3717 addReply(c,shared.nullbulk);
3718 } else {
3719 if (sobj->type != REDIS_LIST) {
3720 addReply(c,shared.wrongtypeerr);
3721 } else {
3722 list *srclist = sobj->ptr;
3723 listNode *ln = listLast(srclist);
3724
3725 if (ln == NULL) {
3726 addReply(c,shared.nullbulk);
3727 } else {
3728 robj *dobj = lookupKeyWrite(c->db,c->argv[2]);
3729 robj *ele = listNodeValue(ln);
3730 list *dstlist;
3731
3732 if (dobj == NULL) {
3733
3734 /* Create the list if the key does not exist */
3735 dobj = createListObject();
3736 dictAdd(c->db->dict,c->argv[2],dobj);
3737 incrRefCount(c->argv[2]);
3738 } else if (dobj->type != REDIS_LIST) {
3739 addReply(c,shared.wrongtypeerr);
3740 return;
3741 }
3742 /* Add the element to the target list */
3743 dstlist = dobj->ptr;
3744 listAddNodeHead(dstlist,ele);
3745 incrRefCount(ele);
3746
3747 /* Send the element to the client as reply as well */
3748 addReplyBulkLen(c,ele);
3749 addReply(c,ele);
3750 addReply(c,shared.crlf);
3751
3752 /* Finally remove the element from the source list */
3753 listDelNode(srclist,ln);
3754 server.dirty++;
3755 }
3756 }
3757 }
3758}
3759
3760
ed9b544e 3761/* ==================================== Sets ================================ */
3762
3763static void saddCommand(redisClient *c) {
ed9b544e 3764 robj *set;
3765
3305306f 3766 set = lookupKeyWrite(c->db,c->argv[1]);
3767 if (set == NULL) {
ed9b544e 3768 set = createSetObject();
3305306f 3769 dictAdd(c->db->dict,c->argv[1],set);
ed9b544e 3770 incrRefCount(c->argv[1]);
3771 } else {
ed9b544e 3772 if (set->type != REDIS_SET) {
c937aa89 3773 addReply(c,shared.wrongtypeerr);
ed9b544e 3774 return;
3775 }
3776 }
3777 if (dictAdd(set->ptr,c->argv[2],NULL) == DICT_OK) {
3778 incrRefCount(c->argv[2]);
3779 server.dirty++;
c937aa89 3780 addReply(c,shared.cone);
ed9b544e 3781 } else {
c937aa89 3782 addReply(c,shared.czero);
ed9b544e 3783 }
3784}
3785
3786static void sremCommand(redisClient *c) {
3305306f 3787 robj *set;
ed9b544e 3788
3305306f 3789 set = lookupKeyWrite(c->db,c->argv[1]);
3790 if (set == NULL) {
c937aa89 3791 addReply(c,shared.czero);
ed9b544e 3792 } else {
ed9b544e 3793 if (set->type != REDIS_SET) {
c937aa89 3794 addReply(c,shared.wrongtypeerr);
ed9b544e 3795 return;
3796 }
3797 if (dictDelete(set->ptr,c->argv[2]) == DICT_OK) {
3798 server.dirty++;
12fea928 3799 if (htNeedsResize(set->ptr)) dictResize(set->ptr);
c937aa89 3800 addReply(c,shared.cone);
ed9b544e 3801 } else {
c937aa89 3802 addReply(c,shared.czero);
ed9b544e 3803 }
3804 }
3805}
3806
a4460ef4 3807static void smoveCommand(redisClient *c) {
3808 robj *srcset, *dstset;
3809
3810 srcset = lookupKeyWrite(c->db,c->argv[1]);
3811 dstset = lookupKeyWrite(c->db,c->argv[2]);
3812
3813 /* If the source key does not exist return 0, if it's of the wrong type
3814 * raise an error */
3815 if (srcset == NULL || srcset->type != REDIS_SET) {
3816 addReply(c, srcset ? shared.wrongtypeerr : shared.czero);
3817 return;
3818 }
3819 /* Error if the destination key is not a set as well */
3820 if (dstset && dstset->type != REDIS_SET) {
3821 addReply(c,shared.wrongtypeerr);
3822 return;
3823 }
3824 /* Remove the element from the source set */
3825 if (dictDelete(srcset->ptr,c->argv[3]) == DICT_ERR) {
3826 /* Key not found in the src set! return zero */
3827 addReply(c,shared.czero);
3828 return;
3829 }
3830 server.dirty++;
3831 /* Add the element to the destination set */
3832 if (!dstset) {
3833 dstset = createSetObject();
3834 dictAdd(c->db->dict,c->argv[2],dstset);
3835 incrRefCount(c->argv[2]);
3836 }
3837 if (dictAdd(dstset->ptr,c->argv[3],NULL) == DICT_OK)
3838 incrRefCount(c->argv[3]);
3839 addReply(c,shared.cone);
3840}
3841
ed9b544e 3842static void sismemberCommand(redisClient *c) {
3305306f 3843 robj *set;
ed9b544e 3844
3305306f 3845 set = lookupKeyRead(c->db,c->argv[1]);
3846 if (set == NULL) {
c937aa89 3847 addReply(c,shared.czero);
ed9b544e 3848 } else {
ed9b544e 3849 if (set->type != REDIS_SET) {
c937aa89 3850 addReply(c,shared.wrongtypeerr);
ed9b544e 3851 return;
3852 }
3853 if (dictFind(set->ptr,c->argv[2]))
c937aa89 3854 addReply(c,shared.cone);
ed9b544e 3855 else
c937aa89 3856 addReply(c,shared.czero);
ed9b544e 3857 }
3858}
3859
3860static void scardCommand(redisClient *c) {
3305306f 3861 robj *o;
ed9b544e 3862 dict *s;
3863
3305306f 3864 o = lookupKeyRead(c->db,c->argv[1]);
3865 if (o == NULL) {
c937aa89 3866 addReply(c,shared.czero);
ed9b544e 3867 return;
3868 } else {
ed9b544e 3869 if (o->type != REDIS_SET) {
c937aa89 3870 addReply(c,shared.wrongtypeerr);
ed9b544e 3871 } else {
3872 s = o->ptr;
682ac724 3873 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",
3305306f 3874 dictSize(s)));
ed9b544e 3875 }
3876 }
3877}
3878
12fea928 3879static void spopCommand(redisClient *c) {
3880 robj *set;
3881 dictEntry *de;
3882
3883 set = lookupKeyWrite(c->db,c->argv[1]);
3884 if (set == NULL) {
3885 addReply(c,shared.nullbulk);
3886 } else {
3887 if (set->type != REDIS_SET) {
3888 addReply(c,shared.wrongtypeerr);
3889 return;
3890 }
3891 de = dictGetRandomKey(set->ptr);
3892 if (de == NULL) {
3893 addReply(c,shared.nullbulk);
3894 } else {
3895 robj *ele = dictGetEntryKey(de);
3896
942a3961 3897 addReplyBulkLen(c,ele);
12fea928 3898 addReply(c,ele);
3899 addReply(c,shared.crlf);
3900 dictDelete(set->ptr,ele);
3901 if (htNeedsResize(set->ptr)) dictResize(set->ptr);
3902 server.dirty++;
3903 }
3904 }
3905}
3906
2abb95a9 3907static void srandmemberCommand(redisClient *c) {
3908 robj *set;
3909 dictEntry *de;
3910
3911 set = lookupKeyRead(c->db,c->argv[1]);
3912 if (set == NULL) {
3913 addReply(c,shared.nullbulk);
3914 } else {
3915 if (set->type != REDIS_SET) {
3916 addReply(c,shared.wrongtypeerr);
3917 return;
3918 }
3919 de = dictGetRandomKey(set->ptr);
3920 if (de == NULL) {
3921 addReply(c,shared.nullbulk);
3922 } else {
3923 robj *ele = dictGetEntryKey(de);
3924
3925 addReplyBulkLen(c,ele);
3926 addReply(c,ele);
3927 addReply(c,shared.crlf);
3928 }
3929 }
3930}
3931
ed9b544e 3932static int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
3933 dict **d1 = (void*) s1, **d2 = (void*) s2;
3934
3305306f 3935 return dictSize(*d1)-dictSize(*d2);
ed9b544e 3936}
3937
682ac724 3938static void sinterGenericCommand(redisClient *c, robj **setskeys, unsigned long setsnum, robj *dstkey) {
ed9b544e 3939 dict **dv = zmalloc(sizeof(dict*)*setsnum);
3940 dictIterator *di;
3941 dictEntry *de;
3942 robj *lenobj = NULL, *dstset = NULL;
682ac724 3943 unsigned long j, cardinality = 0;
ed9b544e 3944
ed9b544e 3945 for (j = 0; j < setsnum; j++) {
3946 robj *setobj;
3305306f 3947
3948 setobj = dstkey ?
3949 lookupKeyWrite(c->db,setskeys[j]) :
3950 lookupKeyRead(c->db,setskeys[j]);
3951 if (!setobj) {
ed9b544e 3952 zfree(dv);
5faa6025 3953 if (dstkey) {
3954 deleteKey(c->db,dstkey);
3955 addReply(c,shared.ok);
3956 } else {
3957 addReply(c,shared.nullmultibulk);
3958 }
ed9b544e 3959 return;
3960 }
ed9b544e 3961 if (setobj->type != REDIS_SET) {
3962 zfree(dv);
c937aa89 3963 addReply(c,shared.wrongtypeerr);
ed9b544e 3964 return;
3965 }
3966 dv[j] = setobj->ptr;
3967 }
3968 /* Sort sets from the smallest to largest, this will improve our
3969 * algorithm's performace */
3970 qsort(dv,setsnum,sizeof(dict*),qsortCompareSetsByCardinality);
3971
3972 /* The first thing we should output is the total number of elements...
3973 * since this is a multi-bulk write, but at this stage we don't know
3974 * the intersection set size, so we use a trick, append an empty object
3975 * to the output list and save the pointer to later modify it with the
3976 * right length */
3977 if (!dstkey) {
3978 lenobj = createObject(REDIS_STRING,NULL);
3979 addReply(c,lenobj);
3980 decrRefCount(lenobj);
3981 } else {
3982 /* If we have a target key where to store the resulting set
3983 * create this key with an empty set inside */
3984 dstset = createSetObject();
ed9b544e 3985 }
3986
3987 /* Iterate all the elements of the first (smallest) set, and test
3988 * the element against all the other sets, if at least one set does
3989 * not include the element it is discarded */
3990 di = dictGetIterator(dv[0]);
ed9b544e 3991
3992 while((de = dictNext(di)) != NULL) {
3993 robj *ele;
3994
3995 for (j = 1; j < setsnum; j++)
3996 if (dictFind(dv[j],dictGetEntryKey(de)) == NULL) break;
3997 if (j != setsnum)
3998 continue; /* at least one set does not contain the member */
3999 ele = dictGetEntryKey(de);
4000 if (!dstkey) {
942a3961 4001 addReplyBulkLen(c,ele);
ed9b544e 4002 addReply(c,ele);
4003 addReply(c,shared.crlf);
4004 cardinality++;
4005 } else {
4006 dictAdd(dstset->ptr,ele,NULL);
4007 incrRefCount(ele);
4008 }
4009 }
4010 dictReleaseIterator(di);
4011
83cdfe18
AG
4012 if (dstkey) {
4013 /* Store the resulting set into the target */
4014 deleteKey(c->db,dstkey);
4015 dictAdd(c->db->dict,dstkey,dstset);
4016 incrRefCount(dstkey);
4017 }
4018
40d224a9 4019 if (!dstkey) {
682ac724 4020 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",cardinality);
40d224a9 4021 } else {
682ac724 4022 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",
03fd01c7 4023 dictSize((dict*)dstset->ptr)));
40d224a9 4024 server.dirty++;
4025 }
ed9b544e 4026 zfree(dv);
4027}
4028
4029static void sinterCommand(redisClient *c) {
4030 sinterGenericCommand(c,c->argv+1,c->argc-1,NULL);
4031}
4032
4033static void sinterstoreCommand(redisClient *c) {
4034 sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
4035}
4036
f4f56e1d 4037#define REDIS_OP_UNION 0
4038#define REDIS_OP_DIFF 1
4039
4040static void sunionDiffGenericCommand(redisClient *c, robj **setskeys, int setsnum, robj *dstkey, int op) {
40d224a9 4041 dict **dv = zmalloc(sizeof(dict*)*setsnum);
4042 dictIterator *di;
4043 dictEntry *de;
f4f56e1d 4044 robj *dstset = NULL;
40d224a9 4045 int j, cardinality = 0;
4046
40d224a9 4047 for (j = 0; j < setsnum; j++) {
4048 robj *setobj;
4049
4050 setobj = dstkey ?
4051 lookupKeyWrite(c->db,setskeys[j]) :
4052 lookupKeyRead(c->db,setskeys[j]);
4053 if (!setobj) {
4054 dv[j] = NULL;
4055 continue;
4056 }
4057 if (setobj->type != REDIS_SET) {
4058 zfree(dv);
4059 addReply(c,shared.wrongtypeerr);
4060 return;
4061 }
4062 dv[j] = setobj->ptr;
4063 }
4064
4065 /* We need a temp set object to store our union. If the dstkey
4066 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
4067 * this set object will be the resulting object to set into the target key*/
4068 dstset = createSetObject();
4069
40d224a9 4070 /* Iterate all the elements of all the sets, add every element a single
4071 * time to the result set */
4072 for (j = 0; j < setsnum; j++) {
51829ed3 4073 if (op == REDIS_OP_DIFF && j == 0 && !dv[j]) break; /* result set is empty */
40d224a9 4074 if (!dv[j]) continue; /* non existing keys are like empty sets */
4075
4076 di = dictGetIterator(dv[j]);
40d224a9 4077
4078 while((de = dictNext(di)) != NULL) {
4079 robj *ele;
4080
4081 /* dictAdd will not add the same element multiple times */
4082 ele = dictGetEntryKey(de);
f4f56e1d 4083 if (op == REDIS_OP_UNION || j == 0) {
4084 if (dictAdd(dstset->ptr,ele,NULL) == DICT_OK) {
4085 incrRefCount(ele);
40d224a9 4086 cardinality++;
4087 }
f4f56e1d 4088 } else if (op == REDIS_OP_DIFF) {
4089 if (dictDelete(dstset->ptr,ele) == DICT_OK) {
4090 cardinality--;
4091 }
40d224a9 4092 }
4093 }
4094 dictReleaseIterator(di);
51829ed3
AG
4095
4096 if (op == REDIS_OP_DIFF && cardinality == 0) break; /* result set is empty */
40d224a9 4097 }
4098
f4f56e1d 4099 /* Output the content of the resulting set, if not in STORE mode */
4100 if (!dstkey) {
4101 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",cardinality));
4102 di = dictGetIterator(dstset->ptr);
f4f56e1d 4103 while((de = dictNext(di)) != NULL) {
4104 robj *ele;
4105
4106 ele = dictGetEntryKey(de);
942a3961 4107 addReplyBulkLen(c,ele);
f4f56e1d 4108 addReply(c,ele);
4109 addReply(c,shared.crlf);
4110 }
4111 dictReleaseIterator(di);
83cdfe18
AG
4112 } else {
4113 /* If we have a target key where to store the resulting set
4114 * create this key with the result set inside */
4115 deleteKey(c->db,dstkey);
4116 dictAdd(c->db->dict,dstkey,dstset);
4117 incrRefCount(dstkey);
f4f56e1d 4118 }
4119
4120 /* Cleanup */
40d224a9 4121 if (!dstkey) {
40d224a9 4122 decrRefCount(dstset);
4123 } else {
682ac724 4124 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",
03fd01c7 4125 dictSize((dict*)dstset->ptr)));
40d224a9 4126 server.dirty++;
4127 }
4128 zfree(dv);
4129}
4130
4131static void sunionCommand(redisClient *c) {
f4f56e1d 4132 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_UNION);
40d224a9 4133}
4134
4135static void sunionstoreCommand(redisClient *c) {
f4f56e1d 4136 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_UNION);
4137}
4138
4139static void sdiffCommand(redisClient *c) {
4140 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_DIFF);
4141}
4142
4143static void sdiffstoreCommand(redisClient *c) {
4144 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_DIFF);
40d224a9 4145}
4146
6b47e12e 4147/* ==================================== ZSets =============================== */
4148
4149/* ZSETs are ordered sets using two data structures to hold the same elements
4150 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
4151 * data structure.
4152 *
4153 * The elements are added to an hash table mapping Redis objects to scores.
4154 * At the same time the elements are added to a skip list mapping scores
4155 * to Redis objects (so objects are sorted by scores in this "view"). */
4156
4157/* This skiplist implementation is almost a C translation of the original
4158 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
4159 * Alternative to Balanced Trees", modified in three ways:
4160 * a) this implementation allows for repeated values.
4161 * b) the comparison is not just by key (our 'score') but by satellite data.
4162 * c) there is a back pointer, so it's a doubly linked list with the back
4163 * pointers being only at "level 1". This allows to traverse the list
4164 * from tail to head, useful for ZREVRANGE. */
4165
4166static zskiplistNode *zslCreateNode(int level, double score, robj *obj) {
4167 zskiplistNode *zn = zmalloc(sizeof(*zn));
4168
4169 zn->forward = zmalloc(sizeof(zskiplistNode*) * level);
4170 zn->score = score;
4171 zn->obj = obj;
4172 return zn;
4173}
4174
4175static zskiplist *zslCreate(void) {
4176 int j;
4177 zskiplist *zsl;
4178
4179 zsl = zmalloc(sizeof(*zsl));
4180 zsl->level = 1;
cc812361 4181 zsl->length = 0;
6b47e12e 4182 zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
4183 for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++)
4184 zsl->header->forward[j] = NULL;
e3870fab 4185 zsl->header->backward = NULL;
4186 zsl->tail = NULL;
6b47e12e 4187 return zsl;
4188}
4189
fd8ccf44 4190static void zslFreeNode(zskiplistNode *node) {
4191 decrRefCount(node->obj);
ad807e6f 4192 zfree(node->forward);
fd8ccf44 4193 zfree(node);
4194}
4195
4196static void zslFree(zskiplist *zsl) {
ad807e6f 4197 zskiplistNode *node = zsl->header->forward[0], *next;
fd8ccf44 4198
ad807e6f 4199 zfree(zsl->header->forward);
4200 zfree(zsl->header);
fd8ccf44 4201 while(node) {
599379dd 4202 next = node->forward[0];
fd8ccf44 4203 zslFreeNode(node);
4204 node = next;
4205 }
ad807e6f 4206 zfree(zsl);
fd8ccf44 4207}
4208
6b47e12e 4209static int zslRandomLevel(void) {
4210 int level = 1;
4211 while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
4212 level += 1;
4213 return level;
4214}
4215
4216static void zslInsert(zskiplist *zsl, double score, robj *obj) {
4217 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
4218 int i, level;
4219
4220 x = zsl->header;
4221 for (i = zsl->level-1; i >= 0; i--) {
9d60e6e4 4222 while (x->forward[i] &&
4223 (x->forward[i]->score < score ||
4224 (x->forward[i]->score == score &&
4225 compareStringObjects(x->forward[i]->obj,obj) < 0)))
6b47e12e 4226 x = x->forward[i];
4227 update[i] = x;
4228 }
6b47e12e 4229 /* we assume the key is not already inside, since we allow duplicated
4230 * scores, and the re-insertion of score and redis object should never
4231 * happpen since the caller of zslInsert() should test in the hash table
4232 * if the element is already inside or not. */
4233 level = zslRandomLevel();
4234 if (level > zsl->level) {
4235 for (i = zsl->level; i < level; i++)
4236 update[i] = zsl->header;
4237 zsl->level = level;
4238 }
4239 x = zslCreateNode(level,score,obj);
4240 for (i = 0; i < level; i++) {
4241 x->forward[i] = update[i]->forward[i];
4242 update[i]->forward[i] = x;
4243 }
bb975144 4244 x->backward = (update[0] == zsl->header) ? NULL : update[0];
e3870fab 4245 if (x->forward[0])
4246 x->forward[0]->backward = x;
4247 else
4248 zsl->tail = x;
cc812361 4249 zsl->length++;
6b47e12e 4250}
4251
50c55df5 4252/* Delete an element with matching score/object from the skiplist. */
fd8ccf44 4253static int zslDelete(zskiplist *zsl, double score, robj *obj) {
e197b441 4254 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
4255 int i;
4256
4257 x = zsl->header;
4258 for (i = zsl->level-1; i >= 0; i--) {
9d60e6e4 4259 while (x->forward[i] &&
4260 (x->forward[i]->score < score ||
4261 (x->forward[i]->score == score &&
4262 compareStringObjects(x->forward[i]->obj,obj) < 0)))
e197b441 4263 x = x->forward[i];
4264 update[i] = x;
4265 }
4266 /* We may have multiple elements with the same score, what we need
4267 * is to find the element with both the right score and object. */
4268 x = x->forward[0];
50c55df5 4269 if (x && score == x->score && compareStringObjects(x->obj,obj) == 0) {
9d60e6e4 4270 for (i = 0; i < zsl->level; i++) {
4271 if (update[i]->forward[i] != x) break;
4272 update[i]->forward[i] = x->forward[i];
4273 }
4274 if (x->forward[0]) {
4275 x->forward[0]->backward = (x->backward == zsl->header) ?
4276 NULL : x->backward;
e197b441 4277 } else {
9d60e6e4 4278 zsl->tail = x->backward;
e197b441 4279 }
9d60e6e4 4280 zslFreeNode(x);
4281 while(zsl->level > 1 && zsl->header->forward[zsl->level-1] == NULL)
4282 zsl->level--;
4283 zsl->length--;
4284 return 1;
4285 } else {
4286 return 0; /* not found */
e197b441 4287 }
4288 return 0; /* not found */
fd8ccf44 4289}
4290
1807985b 4291/* Delete all the elements with score between min and max from the skiplist.
4292 * Min and mx are inclusive, so a score >= min || score <= max is deleted.
4293 * Note that this function takes the reference to the hash table view of the
4294 * sorted set, in order to remove the elements from the hash table too. */
4295static unsigned long zslDeleteRange(zskiplist *zsl, double min, double max, dict *dict) {
4296 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
4297 unsigned long removed = 0;
4298 int i;
4299
4300 x = zsl->header;
4301 for (i = zsl->level-1; i >= 0; i--) {
4302 while (x->forward[i] && x->forward[i]->score < min)
4303 x = x->forward[i];
4304 update[i] = x;
4305 }
4306 /* We may have multiple elements with the same score, what we need
4307 * is to find the element with both the right score and object. */
4308 x = x->forward[0];
4309 while (x && x->score <= max) {
4310 zskiplistNode *next;
4311
4312 for (i = 0; i < zsl->level; i++) {
4313 if (update[i]->forward[i] != x) break;
4314 update[i]->forward[i] = x->forward[i];
4315 }
4316 if (x->forward[0]) {
4317 x->forward[0]->backward = (x->backward == zsl->header) ?
4318 NULL : x->backward;
4319 } else {
4320 zsl->tail = x->backward;
4321 }
4322 next = x->forward[0];
4323 dictDelete(dict,x->obj);
4324 zslFreeNode(x);
4325 while(zsl->level > 1 && zsl->header->forward[zsl->level-1] == NULL)
4326 zsl->level--;
4327 zsl->length--;
4328 removed++;
4329 x = next;
4330 }
4331 return removed; /* not found */
4332}
4333
50c55df5 4334/* Find the first node having a score equal or greater than the specified one.
4335 * Returns NULL if there is no match. */
4336static zskiplistNode *zslFirstWithScore(zskiplist *zsl, double score) {
4337 zskiplistNode *x;
4338 int i;
4339
4340 x = zsl->header;
4341 for (i = zsl->level-1; i >= 0; i--) {
4342 while (x->forward[i] && x->forward[i]->score < score)
4343 x = x->forward[i];
4344 }
4345 /* We may have multiple elements with the same score, what we need
4346 * is to find the element with both the right score and object. */
4347 return x->forward[0];
4348}
4349
fd8ccf44 4350/* The actual Z-commands implementations */
4351
7db723ad 4352/* This generic command implements both ZADD and ZINCRBY.
e2665397 4353 * scoreval is the score if the operation is a ZADD (doincrement == 0) or
7db723ad 4354 * the increment if the operation is a ZINCRBY (doincrement == 1). */
e2665397 4355static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, int doincrement) {
fd8ccf44 4356 robj *zsetobj;
4357 zset *zs;
4358 double *score;
4359
e2665397 4360 zsetobj = lookupKeyWrite(c->db,key);
fd8ccf44 4361 if (zsetobj == NULL) {
4362 zsetobj = createZsetObject();
e2665397 4363 dictAdd(c->db->dict,key,zsetobj);
4364 incrRefCount(key);
fd8ccf44 4365 } else {
4366 if (zsetobj->type != REDIS_ZSET) {
4367 addReply(c,shared.wrongtypeerr);
4368 return;
4369 }
4370 }
fd8ccf44 4371 zs = zsetobj->ptr;
e2665397 4372
7db723ad 4373 /* Ok now since we implement both ZADD and ZINCRBY here the code
e2665397 4374 * needs to handle the two different conditions. It's all about setting
4375 * '*score', that is, the new score to set, to the right value. */
4376 score = zmalloc(sizeof(double));
4377 if (doincrement) {
4378 dictEntry *de;
4379
4380 /* Read the old score. If the element was not present starts from 0 */
4381 de = dictFind(zs->dict,ele);
4382 if (de) {
4383 double *oldscore = dictGetEntryVal(de);
4384 *score = *oldscore + scoreval;
4385 } else {
4386 *score = scoreval;
4387 }
4388 } else {
4389 *score = scoreval;
4390 }
4391
4392 /* What follows is a simple remove and re-insert operation that is common
7db723ad 4393 * to both ZADD and ZINCRBY... */
e2665397 4394 if (dictAdd(zs->dict,ele,score) == DICT_OK) {
fd8ccf44 4395 /* case 1: New element */
e2665397 4396 incrRefCount(ele); /* added to hash */
4397 zslInsert(zs->zsl,*score,ele);
4398 incrRefCount(ele); /* added to skiplist */
fd8ccf44 4399 server.dirty++;
e2665397 4400 if (doincrement)
e2665397 4401 addReplyDouble(c,*score);
91d71bfc 4402 else
4403 addReply(c,shared.cone);
fd8ccf44 4404 } else {
4405 dictEntry *de;
4406 double *oldscore;
4407
4408 /* case 2: Score update operation */
e2665397 4409 de = dictFind(zs->dict,ele);
dfc5e96c 4410 redisAssert(de != NULL);
fd8ccf44 4411 oldscore = dictGetEntryVal(de);
4412 if (*score != *oldscore) {
4413 int deleted;
4414
e2665397 4415 /* Remove and insert the element in the skip list with new score */
4416 deleted = zslDelete(zs->zsl,*oldscore,ele);
dfc5e96c 4417 redisAssert(deleted != 0);
e2665397 4418 zslInsert(zs->zsl,*score,ele);
4419 incrRefCount(ele);
4420 /* Update the score in the hash table */
4421 dictReplace(zs->dict,ele,score);
fd8ccf44 4422 server.dirty++;
2161a965 4423 } else {
4424 zfree(score);
fd8ccf44 4425 }
e2665397 4426 if (doincrement)
4427 addReplyDouble(c,*score);
4428 else
4429 addReply(c,shared.czero);
fd8ccf44 4430 }
4431}
4432
e2665397 4433static void zaddCommand(redisClient *c) {
4434 double scoreval;
4435
4436 scoreval = strtod(c->argv[2]->ptr,NULL);
4437 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,0);
4438}
4439
7db723ad 4440static void zincrbyCommand(redisClient *c) {
e2665397 4441 double scoreval;
4442
4443 scoreval = strtod(c->argv[2]->ptr,NULL);
4444 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1);
4445}
4446
1b7106e7 4447static void zremCommand(redisClient *c) {
4448 robj *zsetobj;
4449 zset *zs;
4450
4451 zsetobj = lookupKeyWrite(c->db,c->argv[1]);
4452 if (zsetobj == NULL) {
4453 addReply(c,shared.czero);
4454 } else {
4455 dictEntry *de;
4456 double *oldscore;
4457 int deleted;
4458
4459 if (zsetobj->type != REDIS_ZSET) {
4460 addReply(c,shared.wrongtypeerr);
4461 return;
4462 }
4463 zs = zsetobj->ptr;
4464 de = dictFind(zs->dict,c->argv[2]);
4465 if (de == NULL) {
4466 addReply(c,shared.czero);
4467 return;
4468 }
4469 /* Delete from the skiplist */
4470 oldscore = dictGetEntryVal(de);
4471 deleted = zslDelete(zs->zsl,*oldscore,c->argv[2]);
dfc5e96c 4472 redisAssert(deleted != 0);
1b7106e7 4473
4474 /* Delete from the hash table */
4475 dictDelete(zs->dict,c->argv[2]);
4476 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
4477 server.dirty++;
4478 addReply(c,shared.cone);
4479 }
4480}
4481
1807985b 4482static void zremrangebyscoreCommand(redisClient *c) {
4483 double min = strtod(c->argv[2]->ptr,NULL);
4484 double max = strtod(c->argv[3]->ptr,NULL);
4485 robj *zsetobj;
4486 zset *zs;
4487
4488 zsetobj = lookupKeyWrite(c->db,c->argv[1]);
4489 if (zsetobj == NULL) {
4490 addReply(c,shared.czero);
4491 } else {
4492 long deleted;
4493
4494 if (zsetobj->type != REDIS_ZSET) {
4495 addReply(c,shared.wrongtypeerr);
4496 return;
4497 }
4498 zs = zsetobj->ptr;
4499 deleted = zslDeleteRange(zs->zsl,min,max,zs->dict);
4500 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
4501 server.dirty += deleted;
4502 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",deleted));
4503 }
4504}
4505
e3870fab 4506static void zrangeGenericCommand(redisClient *c, int reverse) {
cc812361 4507 robj *o;
4508 int start = atoi(c->argv[2]->ptr);
4509 int end = atoi(c->argv[3]->ptr);
4510
4511 o = lookupKeyRead(c->db,c->argv[1]);
4512 if (o == NULL) {
4513 addReply(c,shared.nullmultibulk);
4514 } else {
4515 if (o->type != REDIS_ZSET) {
4516 addReply(c,shared.wrongtypeerr);
4517 } else {
4518 zset *zsetobj = o->ptr;
4519 zskiplist *zsl = zsetobj->zsl;
4520 zskiplistNode *ln;
4521
4522 int llen = zsl->length;
4523 int rangelen, j;
4524 robj *ele;
4525
4526 /* convert negative indexes */
4527 if (start < 0) start = llen+start;
4528 if (end < 0) end = llen+end;
4529 if (start < 0) start = 0;
4530 if (end < 0) end = 0;
4531
4532 /* indexes sanity checks */
4533 if (start > end || start >= llen) {
4534 /* Out of range start or start > end result in empty list */
4535 addReply(c,shared.emptymultibulk);
4536 return;
4537 }
4538 if (end >= llen) end = llen-1;
4539 rangelen = (end-start)+1;
4540
4541 /* Return the result in form of a multi-bulk reply */
e3870fab 4542 if (reverse) {
4543 ln = zsl->tail;
4544 while (start--)
4545 ln = ln->backward;
4546 } else {
4547 ln = zsl->header->forward[0];
4548 while (start--)
4549 ln = ln->forward[0];
4550 }
cc812361 4551
4552 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen));
4553 for (j = 0; j < rangelen; j++) {
0aad7a19 4554 ele = ln->obj;
cc812361 4555 addReplyBulkLen(c,ele);
4556 addReply(c,ele);
4557 addReply(c,shared.crlf);
e3870fab 4558 ln = reverse ? ln->backward : ln->forward[0];
cc812361 4559 }
4560 }
4561 }
4562}
4563
e3870fab 4564static void zrangeCommand(redisClient *c) {
4565 zrangeGenericCommand(c,0);
4566}
4567
4568static void zrevrangeCommand(redisClient *c) {
4569 zrangeGenericCommand(c,1);
4570}
4571
50c55df5 4572static void zrangebyscoreCommand(redisClient *c) {
4573 robj *o;
4574 double min = strtod(c->argv[2]->ptr,NULL);
4575 double max = strtod(c->argv[3]->ptr,NULL);
80181f78 4576 int offset = 0, limit = -1;
4577
4578 if (c->argc != 4 && c->argc != 7) {
4579 addReplySds(c,sdsnew("-ERR wrong number of arguments\r\n"));
4580 return;
4581 } else if (c->argc == 7 && strcasecmp(c->argv[4]->ptr,"limit")) {
4582 addReply(c,shared.syntaxerr);
4583 return;
4584 } else if (c->argc == 7) {
4585 offset = atoi(c->argv[5]->ptr);
4586 limit = atoi(c->argv[6]->ptr);
0b13687c 4587 if (offset < 0) offset = 0;
80181f78 4588 }
50c55df5 4589
4590 o = lookupKeyRead(c->db,c->argv[1]);
4591 if (o == NULL) {
4592 addReply(c,shared.nullmultibulk);
4593 } else {
4594 if (o->type != REDIS_ZSET) {
4595 addReply(c,shared.wrongtypeerr);
4596 } else {
4597 zset *zsetobj = o->ptr;
4598 zskiplist *zsl = zsetobj->zsl;
4599 zskiplistNode *ln;
4600 robj *ele, *lenobj;
4601 unsigned int rangelen = 0;
4602
4603 /* Get the first node with the score >= min */
4604 ln = zslFirstWithScore(zsl,min);
4605 if (ln == NULL) {
4606 /* No element matching the speciifed interval */
4607 addReply(c,shared.emptymultibulk);
4608 return;
4609 }
4610
4611 /* We don't know in advance how many matching elements there
4612 * are in the list, so we push this object that will represent
4613 * the multi-bulk length in the output buffer, and will "fix"
4614 * it later */
4615 lenobj = createObject(REDIS_STRING,NULL);
4616 addReply(c,lenobj);
c74e7c77 4617 decrRefCount(lenobj);
50c55df5 4618
dbbc7285 4619 while(ln && ln->score <= max) {
80181f78 4620 if (offset) {
4621 offset--;
4622 ln = ln->forward[0];
4623 continue;
4624 }
4625 if (limit == 0) break;
50c55df5 4626 ele = ln->obj;
4627 addReplyBulkLen(c,ele);
4628 addReply(c,ele);
4629 addReply(c,shared.crlf);
4630 ln = ln->forward[0];
4631 rangelen++;
80181f78 4632 if (limit > 0) limit--;
50c55df5 4633 }
4634 lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",rangelen);
4635 }
4636 }
4637}
4638
3c41331e 4639static void zcardCommand(redisClient *c) {
e197b441 4640 robj *o;
4641 zset *zs;
4642
4643 o = lookupKeyRead(c->db,c->argv[1]);
4644 if (o == NULL) {
4645 addReply(c,shared.czero);
4646 return;
4647 } else {
4648 if (o->type != REDIS_ZSET) {
4649 addReply(c,shared.wrongtypeerr);
4650 } else {
4651 zs = o->ptr;
682ac724 4652 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",zs->zsl->length));
e197b441 4653 }
4654 }
4655}
4656
6e333bbe 4657static void zscoreCommand(redisClient *c) {
4658 robj *o;
4659 zset *zs;
4660
4661 o = lookupKeyRead(c->db,c->argv[1]);
4662 if (o == NULL) {
96d8b4ee 4663 addReply(c,shared.nullbulk);
6e333bbe 4664 return;
4665 } else {
4666 if (o->type != REDIS_ZSET) {
4667 addReply(c,shared.wrongtypeerr);
4668 } else {
4669 dictEntry *de;
4670
4671 zs = o->ptr;
4672 de = dictFind(zs->dict,c->argv[2]);
4673 if (!de) {
4674 addReply(c,shared.nullbulk);
4675 } else {
6e333bbe 4676 double *score = dictGetEntryVal(de);
4677
e2665397 4678 addReplyDouble(c,*score);
6e333bbe 4679 }
4680 }
4681 }
4682}
4683
6b47e12e 4684/* ========================= Non type-specific commands ==================== */
4685
ed9b544e 4686static void flushdbCommand(redisClient *c) {
ca37e9cd 4687 server.dirty += dictSize(c->db->dict);
3305306f 4688 dictEmpty(c->db->dict);
4689 dictEmpty(c->db->expires);
ed9b544e 4690 addReply(c,shared.ok);
ed9b544e 4691}
4692
4693static void flushallCommand(redisClient *c) {
ca37e9cd 4694 server.dirty += emptyDb();
ed9b544e 4695 addReply(c,shared.ok);
f78fd11b 4696 rdbSave(server.dbfilename);
ca37e9cd 4697 server.dirty++;
ed9b544e 4698}
4699
56906eef 4700static redisSortOperation *createSortOperation(int type, robj *pattern) {
ed9b544e 4701 redisSortOperation *so = zmalloc(sizeof(*so));
ed9b544e 4702 so->type = type;
4703 so->pattern = pattern;
4704 return so;
4705}
4706
4707/* Return the value associated to the key with a name obtained
4708 * substituting the first occurence of '*' in 'pattern' with 'subst' */
56906eef 4709static robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
ed9b544e 4710 char *p;
4711 sds spat, ssub;
4712 robj keyobj;
4713 int prefixlen, sublen, postfixlen;
ed9b544e 4714 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
4715 struct {
f1017b3f 4716 long len;
4717 long free;
ed9b544e 4718 char buf[REDIS_SORTKEY_MAX+1];
4719 } keyname;
4720
28173a49 4721 /* If the pattern is "#" return the substitution object itself in order
4722 * to implement the "SORT ... GET #" feature. */
4723 spat = pattern->ptr;
4724 if (spat[0] == '#' && spat[1] == '\0') {
4725 return subst;
4726 }
4727
4728 /* The substitution object may be specially encoded. If so we create
9d65a1bb 4729 * a decoded object on the fly. Otherwise getDecodedObject will just
4730 * increment the ref count, that we'll decrement later. */
4731 subst = getDecodedObject(subst);
942a3961 4732
ed9b544e 4733 ssub = subst->ptr;
4734 if (sdslen(spat)+sdslen(ssub)-1 > REDIS_SORTKEY_MAX) return NULL;
4735 p = strchr(spat,'*');
ed5a857a 4736 if (!p) {
4737 decrRefCount(subst);
4738 return NULL;
4739 }
ed9b544e 4740
4741 prefixlen = p-spat;
4742 sublen = sdslen(ssub);
4743 postfixlen = sdslen(spat)-(prefixlen+1);
4744 memcpy(keyname.buf,spat,prefixlen);
4745 memcpy(keyname.buf+prefixlen,ssub,sublen);
4746 memcpy(keyname.buf+prefixlen+sublen,p+1,postfixlen);
4747 keyname.buf[prefixlen+sublen+postfixlen] = '\0';
4748 keyname.len = prefixlen+sublen+postfixlen;
4749
dfc5e96c 4750 initStaticStringObject(keyobj,((char*)&keyname)+(sizeof(long)*2))
942a3961 4751 decrRefCount(subst);
4752
a4d1ba9a 4753 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
3305306f 4754 return lookupKeyRead(db,&keyobj);
ed9b544e 4755}
4756
4757/* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
4758 * the additional parameter is not standard but a BSD-specific we have to
4759 * pass sorting parameters via the global 'server' structure */
4760static int sortCompare(const void *s1, const void *s2) {
4761 const redisSortObject *so1 = s1, *so2 = s2;
4762 int cmp;
4763
4764 if (!server.sort_alpha) {
4765 /* Numeric sorting. Here it's trivial as we precomputed scores */
4766 if (so1->u.score > so2->u.score) {
4767 cmp = 1;
4768 } else if (so1->u.score < so2->u.score) {
4769 cmp = -1;
4770 } else {
4771 cmp = 0;
4772 }
4773 } else {
4774 /* Alphanumeric sorting */
4775 if (server.sort_bypattern) {
4776 if (!so1->u.cmpobj || !so2->u.cmpobj) {
4777 /* At least one compare object is NULL */
4778 if (so1->u.cmpobj == so2->u.cmpobj)
4779 cmp = 0;
4780 else if (so1->u.cmpobj == NULL)
4781 cmp = -1;
4782 else
4783 cmp = 1;
4784 } else {
4785 /* We have both the objects, use strcoll */
4786 cmp = strcoll(so1->u.cmpobj->ptr,so2->u.cmpobj->ptr);
4787 }
4788 } else {
4789 /* Compare elements directly */
9d65a1bb 4790 robj *dec1, *dec2;
4791
4792 dec1 = getDecodedObject(so1->obj);
4793 dec2 = getDecodedObject(so2->obj);
4794 cmp = strcoll(dec1->ptr,dec2->ptr);
4795 decrRefCount(dec1);
4796 decrRefCount(dec2);
ed9b544e 4797 }
4798 }
4799 return server.sort_desc ? -cmp : cmp;
4800}
4801
4802/* The SORT command is the most complex command in Redis. Warning: this code
4803 * is optimized for speed and a bit less for readability */
4804static void sortCommand(redisClient *c) {
ed9b544e 4805 list *operations;
4806 int outputlen = 0;
4807 int desc = 0, alpha = 0;
4808 int limit_start = 0, limit_count = -1, start, end;
4809 int j, dontsort = 0, vectorlen;
4810 int getop = 0; /* GET operation counter */
443c6409 4811 robj *sortval, *sortby = NULL, *storekey = NULL;
ed9b544e 4812 redisSortObject *vector; /* Resulting vector to sort */
4813
4814 /* Lookup the key to sort. It must be of the right types */
3305306f 4815 sortval = lookupKeyRead(c->db,c->argv[1]);
4816 if (sortval == NULL) {
c937aa89 4817 addReply(c,shared.nokeyerr);
ed9b544e 4818 return;
4819 }
a5eb649b 4820 if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST &&
4821 sortval->type != REDIS_ZSET)
4822 {
c937aa89 4823 addReply(c,shared.wrongtypeerr);
ed9b544e 4824 return;
4825 }
4826
4827 /* Create a list of operations to perform for every sorted element.
4828 * Operations can be GET/DEL/INCR/DECR */
4829 operations = listCreate();
092dac2a 4830 listSetFreeMethod(operations,zfree);
ed9b544e 4831 j = 2;
4832
4833 /* Now we need to protect sortval incrementing its count, in the future
4834 * SORT may have options able to overwrite/delete keys during the sorting
4835 * and the sorted key itself may get destroied */
4836 incrRefCount(sortval);
4837
4838 /* The SORT command has an SQL-alike syntax, parse it */
4839 while(j < c->argc) {
4840 int leftargs = c->argc-j-1;
4841 if (!strcasecmp(c->argv[j]->ptr,"asc")) {
4842 desc = 0;
4843 } else if (!strcasecmp(c->argv[j]->ptr,"desc")) {
4844 desc = 1;
4845 } else if (!strcasecmp(c->argv[j]->ptr,"alpha")) {
4846 alpha = 1;
4847 } else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) {
4848 limit_start = atoi(c->argv[j+1]->ptr);
4849 limit_count = atoi(c->argv[j+2]->ptr);
4850 j+=2;
443c6409 4851 } else if (!strcasecmp(c->argv[j]->ptr,"store") && leftargs >= 1) {
4852 storekey = c->argv[j+1];
4853 j++;
ed9b544e 4854 } else if (!strcasecmp(c->argv[j]->ptr,"by") && leftargs >= 1) {
4855 sortby = c->argv[j+1];
4856 /* If the BY pattern does not contain '*', i.e. it is constant,
4857 * we don't need to sort nor to lookup the weight keys. */
4858 if (strchr(c->argv[j+1]->ptr,'*') == NULL) dontsort = 1;
4859 j++;
4860 } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
4861 listAddNodeTail(operations,createSortOperation(
4862 REDIS_SORT_GET,c->argv[j+1]));
4863 getop++;
4864 j++;
ed9b544e 4865 } else {
4866 decrRefCount(sortval);
4867 listRelease(operations);
c937aa89 4868 addReply(c,shared.syntaxerr);
ed9b544e 4869 return;
4870 }
4871 j++;
4872 }
4873
4874 /* Load the sorting vector with all the objects to sort */
a5eb649b 4875 switch(sortval->type) {
4876 case REDIS_LIST: vectorlen = listLength((list*)sortval->ptr); break;
4877 case REDIS_SET: vectorlen = dictSize((dict*)sortval->ptr); break;
4878 case REDIS_ZSET: vectorlen = dictSize(((zset*)sortval->ptr)->dict); break;
dfc5e96c 4879 default: vectorlen = 0; redisAssert(0); /* Avoid GCC warning */
a5eb649b 4880 }
ed9b544e 4881 vector = zmalloc(sizeof(redisSortObject)*vectorlen);
ed9b544e 4882 j = 0;
a5eb649b 4883
ed9b544e 4884 if (sortval->type == REDIS_LIST) {
4885 list *list = sortval->ptr;
6208b3a7 4886 listNode *ln;
4887
4888 listRewind(list);
4889 while((ln = listYield(list))) {
ed9b544e 4890 robj *ele = ln->value;
4891 vector[j].obj = ele;
4892 vector[j].u.score = 0;
4893 vector[j].u.cmpobj = NULL;
ed9b544e 4894 j++;
4895 }
4896 } else {
a5eb649b 4897 dict *set;
ed9b544e 4898 dictIterator *di;
4899 dictEntry *setele;
4900
a5eb649b 4901 if (sortval->type == REDIS_SET) {
4902 set = sortval->ptr;
4903 } else {
4904 zset *zs = sortval->ptr;
4905 set = zs->dict;
4906 }
4907
ed9b544e 4908 di = dictGetIterator(set);
ed9b544e 4909 while((setele = dictNext(di)) != NULL) {
4910 vector[j].obj = dictGetEntryKey(setele);
4911 vector[j].u.score = 0;
4912 vector[j].u.cmpobj = NULL;
4913 j++;
4914 }
4915 dictReleaseIterator(di);
4916 }
dfc5e96c 4917 redisAssert(j == vectorlen);
ed9b544e 4918
4919 /* Now it's time to load the right scores in the sorting vector */
4920 if (dontsort == 0) {
4921 for (j = 0; j < vectorlen; j++) {
4922 if (sortby) {
4923 robj *byval;
4924
3305306f 4925 byval = lookupKeyByPattern(c->db,sortby,vector[j].obj);
ed9b544e 4926 if (!byval || byval->type != REDIS_STRING) continue;
4927 if (alpha) {
9d65a1bb 4928 vector[j].u.cmpobj = getDecodedObject(byval);
ed9b544e 4929 } else {
942a3961 4930 if (byval->encoding == REDIS_ENCODING_RAW) {
4931 vector[j].u.score = strtod(byval->ptr,NULL);
4932 } else {
9d65a1bb 4933 /* Don't need to decode the object if it's
4934 * integer-encoded (the only encoding supported) so
4935 * far. We can just cast it */
f1017b3f 4936 if (byval->encoding == REDIS_ENCODING_INT) {
942a3961 4937 vector[j].u.score = (long)byval->ptr;
f1017b3f 4938 } else
dfc5e96c 4939 redisAssert(1 != 1);
942a3961 4940 }
ed9b544e 4941 }
4942 } else {
942a3961 4943 if (!alpha) {
4944 if (vector[j].obj->encoding == REDIS_ENCODING_RAW)
4945 vector[j].u.score = strtod(vector[j].obj->ptr,NULL);
4946 else {
4947 if (vector[j].obj->encoding == REDIS_ENCODING_INT)
4948 vector[j].u.score = (long) vector[j].obj->ptr;
4949 else
dfc5e96c 4950 redisAssert(1 != 1);
942a3961 4951 }
4952 }
ed9b544e 4953 }
4954 }
4955 }
4956
4957 /* We are ready to sort the vector... perform a bit of sanity check
4958 * on the LIMIT option too. We'll use a partial version of quicksort. */
4959 start = (limit_start < 0) ? 0 : limit_start;
4960 end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1;
4961 if (start >= vectorlen) {
4962 start = vectorlen-1;
4963 end = vectorlen-2;
4964 }
4965 if (end >= vectorlen) end = vectorlen-1;
4966
4967 if (dontsort == 0) {
4968 server.sort_desc = desc;
4969 server.sort_alpha = alpha;
4970 server.sort_bypattern = sortby ? 1 : 0;
5f5b9840 4971 if (sortby && (start != 0 || end != vectorlen-1))
4972 pqsort(vector,vectorlen,sizeof(redisSortObject),sortCompare, start,end);
4973 else
4974 qsort(vector,vectorlen,sizeof(redisSortObject),sortCompare);
ed9b544e 4975 }
4976
4977 /* Send command output to the output buffer, performing the specified
4978 * GET/DEL/INCR/DECR operations if any. */
4979 outputlen = getop ? getop*(end-start+1) : end-start+1;
443c6409 4980 if (storekey == NULL) {
4981 /* STORE option not specified, sent the sorting result to client */
4982 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",outputlen));
4983 for (j = start; j <= end; j++) {
4984 listNode *ln;
4985 if (!getop) {
4986 addReplyBulkLen(c,vector[j].obj);
4987 addReply(c,vector[j].obj);
4988 addReply(c,shared.crlf);
4989 }
4990 listRewind(operations);
4991 while((ln = listYield(operations))) {
4992 redisSortOperation *sop = ln->value;
4993 robj *val = lookupKeyByPattern(c->db,sop->pattern,
4994 vector[j].obj);
4995
4996 if (sop->type == REDIS_SORT_GET) {
4997 if (!val || val->type != REDIS_STRING) {
4998 addReply(c,shared.nullbulk);
4999 } else {
5000 addReplyBulkLen(c,val);
5001 addReply(c,val);
5002 addReply(c,shared.crlf);
5003 }
5004 } else {
dfc5e96c 5005 redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
443c6409 5006 }
5007 }
ed9b544e 5008 }
443c6409 5009 } else {
5010 robj *listObject = createListObject();
5011 list *listPtr = (list*) listObject->ptr;
5012
5013 /* STORE option specified, set the sorting result as a List object */
5014 for (j = start; j <= end; j++) {
5015 listNode *ln;
5016 if (!getop) {
5017 listAddNodeTail(listPtr,vector[j].obj);
5018 incrRefCount(vector[j].obj);
5019 }
5020 listRewind(operations);
5021 while((ln = listYield(operations))) {
5022 redisSortOperation *sop = ln->value;
5023 robj *val = lookupKeyByPattern(c->db,sop->pattern,
5024 vector[j].obj);
5025
5026 if (sop->type == REDIS_SORT_GET) {
5027 if (!val || val->type != REDIS_STRING) {
5028 listAddNodeTail(listPtr,createStringObject("",0));
5029 } else {
5030 listAddNodeTail(listPtr,val);
5031 incrRefCount(val);
5032 }
ed9b544e 5033 } else {
dfc5e96c 5034 redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
ed9b544e 5035 }
ed9b544e 5036 }
ed9b544e 5037 }
121796f7 5038 if (dictReplace(c->db->dict,storekey,listObject)) {
5039 incrRefCount(storekey);
5040 }
443c6409 5041 /* Note: we add 1 because the DB is dirty anyway since even if the
5042 * SORT result is empty a new key is set and maybe the old content
5043 * replaced. */
5044 server.dirty += 1+outputlen;
5045 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",outputlen));
ed9b544e 5046 }
5047
5048 /* Cleanup */
5049 decrRefCount(sortval);
5050 listRelease(operations);
5051 for (j = 0; j < vectorlen; j++) {
5052 if (sortby && alpha && vector[j].u.cmpobj)
5053 decrRefCount(vector[j].u.cmpobj);
5054 }
5055 zfree(vector);
5056}
5057
1c85b79f 5058/* Create the string returned by the INFO command. This is decoupled
5059 * by the INFO command itself as we need to report the same information
5060 * on memory corruption problems. */
5061static sds genRedisInfoString(void) {
ed9b544e 5062 sds info;
5063 time_t uptime = time(NULL)-server.stat_starttime;
c3cb078d 5064 int j;
ed9b544e 5065
5066 info = sdscatprintf(sdsempty(),
5067 "redis_version:%s\r\n"
f1017b3f 5068 "arch_bits:%s\r\n"
7a932b74 5069 "multiplexing_api:%s\r\n"
682ac724 5070 "uptime_in_seconds:%ld\r\n"
5071 "uptime_in_days:%ld\r\n"
ed9b544e 5072 "connected_clients:%d\r\n"
5073 "connected_slaves:%d\r\n"
5fba9f71 5074 "used_memory:%zu\r\n"
ed9b544e 5075 "changes_since_last_save:%lld\r\n"
be2bb6b0 5076 "bgsave_in_progress:%d\r\n"
682ac724 5077 "last_save_time:%ld\r\n"
ed9b544e 5078 "total_connections_received:%lld\r\n"
5079 "total_commands_processed:%lld\r\n"
a0f643ea 5080 "role:%s\r\n"
ed9b544e 5081 ,REDIS_VERSION,
f1017b3f 5082 (sizeof(long) == 8) ? "64" : "32",
7a932b74 5083 aeGetApiName(),
a0f643ea 5084 uptime,
5085 uptime/(3600*24),
ed9b544e 5086 listLength(server.clients)-listLength(server.slaves),
5087 listLength(server.slaves),
5088 server.usedmemory,
5089 server.dirty,
9d65a1bb 5090 server.bgsavechildpid != -1,
ed9b544e 5091 server.lastsave,
5092 server.stat_numconnections,
5093 server.stat_numcommands,
a0f643ea 5094 server.masterhost == NULL ? "master" : "slave"
ed9b544e 5095 );
a0f643ea 5096 if (server.masterhost) {
5097 info = sdscatprintf(info,
5098 "master_host:%s\r\n"
5099 "master_port:%d\r\n"
5100 "master_link_status:%s\r\n"
5101 "master_last_io_seconds_ago:%d\r\n"
5102 ,server.masterhost,
5103 server.masterport,
5104 (server.replstate == REDIS_REPL_CONNECTED) ?
5105 "up" : "down",
f72b934d 5106 server.master ? ((int)(time(NULL)-server.master->lastinteraction)) : -1
a0f643ea 5107 );
5108 }
c3cb078d 5109 for (j = 0; j < server.dbnum; j++) {
5110 long long keys, vkeys;
5111
5112 keys = dictSize(server.db[j].dict);
5113 vkeys = dictSize(server.db[j].expires);
5114 if (keys || vkeys) {
9d65a1bb 5115 info = sdscatprintf(info, "db%d:keys=%lld,expires=%lld\r\n",
c3cb078d 5116 j, keys, vkeys);
5117 }
5118 }
1c85b79f 5119 return info;
5120}
5121
5122static void infoCommand(redisClient *c) {
5123 sds info = genRedisInfoString();
682ac724 5124 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n",sdslen(info)));
ed9b544e 5125 addReplySds(c,info);
70003d28 5126 addReply(c,shared.crlf);
ed9b544e 5127}
5128
3305306f 5129static void monitorCommand(redisClient *c) {
5130 /* ignore MONITOR if aleady slave or in monitor mode */
5131 if (c->flags & REDIS_SLAVE) return;
5132
5133 c->flags |= (REDIS_SLAVE|REDIS_MONITOR);
5134 c->slaveseldb = 0;
6b47e12e 5135 listAddNodeTail(server.monitors,c);
3305306f 5136 addReply(c,shared.ok);
5137}
5138
5139/* ================================= Expire ================================= */
5140static int removeExpire(redisDb *db, robj *key) {
5141 if (dictDelete(db->expires,key) == DICT_OK) {
5142 return 1;
5143 } else {
5144 return 0;
5145 }
5146}
5147
5148static int setExpire(redisDb *db, robj *key, time_t when) {
5149 if (dictAdd(db->expires,key,(void*)when) == DICT_ERR) {
5150 return 0;
5151 } else {
5152 incrRefCount(key);
5153 return 1;
5154 }
5155}
5156
bb32ede5 5157/* Return the expire time of the specified key, or -1 if no expire
5158 * is associated with this key (i.e. the key is non volatile) */
5159static time_t getExpire(redisDb *db, robj *key) {
5160 dictEntry *de;
5161
5162 /* No expire? return ASAP */
5163 if (dictSize(db->expires) == 0 ||
5164 (de = dictFind(db->expires,key)) == NULL) return -1;
5165
5166 return (time_t) dictGetEntryVal(de);
5167}
5168
3305306f 5169static int expireIfNeeded(redisDb *db, robj *key) {
5170 time_t when;
5171 dictEntry *de;
5172
5173 /* No expire? return ASAP */
5174 if (dictSize(db->expires) == 0 ||
5175 (de = dictFind(db->expires,key)) == NULL) return 0;
5176
5177 /* Lookup the expire */
5178 when = (time_t) dictGetEntryVal(de);
5179 if (time(NULL) <= when) return 0;
5180
5181 /* Delete the key */
5182 dictDelete(db->expires,key);
5183 return dictDelete(db->dict,key) == DICT_OK;
5184}
5185
5186static int deleteIfVolatile(redisDb *db, robj *key) {
5187 dictEntry *de;
5188
5189 /* No expire? return ASAP */
5190 if (dictSize(db->expires) == 0 ||
5191 (de = dictFind(db->expires,key)) == NULL) return 0;
5192
5193 /* Delete the key */
0c66a471 5194 server.dirty++;
3305306f 5195 dictDelete(db->expires,key);
5196 return dictDelete(db->dict,key) == DICT_OK;
5197}
5198
802e8373 5199static void expireGenericCommand(redisClient *c, robj *key, time_t seconds) {
3305306f 5200 dictEntry *de;
3305306f 5201
802e8373 5202 de = dictFind(c->db->dict,key);
3305306f 5203 if (de == NULL) {
5204 addReply(c,shared.czero);
5205 return;
5206 }
43e5ccdf 5207 if (seconds < 0) {
5208 if (deleteKey(c->db,key)) server.dirty++;
5209 addReply(c, shared.cone);
3305306f 5210 return;
5211 } else {
5212 time_t when = time(NULL)+seconds;
802e8373 5213 if (setExpire(c->db,key,when)) {
3305306f 5214 addReply(c,shared.cone);
77423026 5215 server.dirty++;
5216 } else {
3305306f 5217 addReply(c,shared.czero);
77423026 5218 }
3305306f 5219 return;
5220 }
5221}
5222
802e8373 5223static void expireCommand(redisClient *c) {
5224 expireGenericCommand(c,c->argv[1],strtol(c->argv[2]->ptr,NULL,10));
5225}
5226
5227static void expireatCommand(redisClient *c) {
5228 expireGenericCommand(c,c->argv[1],strtol(c->argv[2]->ptr,NULL,10)-time(NULL));
5229}
5230
fd88489a 5231static void ttlCommand(redisClient *c) {
5232 time_t expire;
5233 int ttl = -1;
5234
5235 expire = getExpire(c->db,c->argv[1]);
5236 if (expire != -1) {
5237 ttl = (int) (expire-time(NULL));
5238 if (ttl < 0) ttl = -1;
5239 }
5240 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",ttl));
5241}
5242
ed9b544e 5243/* =============================== Replication ============================= */
5244
a4d1ba9a 5245static int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 5246 ssize_t nwritten, ret = size;
5247 time_t start = time(NULL);
5248
5249 timeout++;
5250 while(size) {
5251 if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
5252 nwritten = write(fd,ptr,size);
5253 if (nwritten == -1) return -1;
5254 ptr += nwritten;
5255 size -= nwritten;
5256 }
5257 if ((time(NULL)-start) > timeout) {
5258 errno = ETIMEDOUT;
5259 return -1;
5260 }
5261 }
5262 return ret;
5263}
5264
a4d1ba9a 5265static int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 5266 ssize_t nread, totread = 0;
5267 time_t start = time(NULL);
5268
5269 timeout++;
5270 while(size) {
5271 if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
5272 nread = read(fd,ptr,size);
5273 if (nread == -1) return -1;
5274 ptr += nread;
5275 size -= nread;
5276 totread += nread;
5277 }
5278 if ((time(NULL)-start) > timeout) {
5279 errno = ETIMEDOUT;
5280 return -1;
5281 }
5282 }
5283 return totread;
5284}
5285
5286static int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
5287 ssize_t nread = 0;
5288
5289 size--;
5290 while(size) {
5291 char c;
5292
5293 if (syncRead(fd,&c,1,timeout) == -1) return -1;
5294 if (c == '\n') {
5295 *ptr = '\0';
5296 if (nread && *(ptr-1) == '\r') *(ptr-1) = '\0';
5297 return nread;
5298 } else {
5299 *ptr++ = c;
5300 *ptr = '\0';
5301 nread++;
5302 }
5303 }
5304 return nread;
5305}
5306
5307static void syncCommand(redisClient *c) {
40d224a9 5308 /* ignore SYNC if aleady slave or in monitor mode */
5309 if (c->flags & REDIS_SLAVE) return;
5310
5311 /* SYNC can't be issued when the server has pending data to send to
5312 * the client about already issued commands. We need a fresh reply
5313 * buffer registering the differences between the BGSAVE and the current
5314 * dataset, so that we can copy to other slaves if needed. */
5315 if (listLength(c->reply) != 0) {
5316 addReplySds(c,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
5317 return;
5318 }
5319
5320 redisLog(REDIS_NOTICE,"Slave ask for synchronization");
5321 /* Here we need to check if there is a background saving operation
5322 * in progress, or if it is required to start one */
9d65a1bb 5323 if (server.bgsavechildpid != -1) {
40d224a9 5324 /* Ok a background save is in progress. Let's check if it is a good
5325 * one for replication, i.e. if there is another slave that is
5326 * registering differences since the server forked to save */
5327 redisClient *slave;
5328 listNode *ln;
5329
6208b3a7 5330 listRewind(server.slaves);
5331 while((ln = listYield(server.slaves))) {
40d224a9 5332 slave = ln->value;
5333 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break;
40d224a9 5334 }
5335 if (ln) {
5336 /* Perfect, the server is already registering differences for
5337 * another slave. Set the right state, and copy the buffer. */
5338 listRelease(c->reply);
5339 c->reply = listDup(slave->reply);
40d224a9 5340 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
5341 redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC");
5342 } else {
5343 /* No way, we need to wait for the next BGSAVE in order to
5344 * register differences */
5345 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
5346 redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
5347 }
5348 } else {
5349 /* Ok we don't have a BGSAVE in progress, let's start one */
5350 redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
5351 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
5352 redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE");
5353 addReplySds(c,sdsnew("-ERR Unalbe to perform background save\r\n"));
5354 return;
5355 }
5356 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
5357 }
6208b3a7 5358 c->repldbfd = -1;
40d224a9 5359 c->flags |= REDIS_SLAVE;
5360 c->slaveseldb = 0;
6b47e12e 5361 listAddNodeTail(server.slaves,c);
40d224a9 5362 return;
5363}
5364
6208b3a7 5365static void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
5366 redisClient *slave = privdata;
5367 REDIS_NOTUSED(el);
5368 REDIS_NOTUSED(mask);
5369 char buf[REDIS_IOBUF_LEN];
5370 ssize_t nwritten, buflen;
5371
5372 if (slave->repldboff == 0) {
5373 /* Write the bulk write count before to transfer the DB. In theory here
5374 * we don't know how much room there is in the output buffer of the
5375 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
5376 * operations) will never be smaller than the few bytes we need. */
5377 sds bulkcount;
5378
5379 bulkcount = sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
5380 slave->repldbsize);
5381 if (write(fd,bulkcount,sdslen(bulkcount)) != (signed)sdslen(bulkcount))
5382 {
5383 sdsfree(bulkcount);
5384 freeClient(slave);
5385 return;
5386 }
5387 sdsfree(bulkcount);
5388 }
5389 lseek(slave->repldbfd,slave->repldboff,SEEK_SET);
5390 buflen = read(slave->repldbfd,buf,REDIS_IOBUF_LEN);
5391 if (buflen <= 0) {
5392 redisLog(REDIS_WARNING,"Read error sending DB to slave: %s",
5393 (buflen == 0) ? "premature EOF" : strerror(errno));
5394 freeClient(slave);
5395 return;
5396 }
5397 if ((nwritten = write(fd,buf,buflen)) == -1) {
5398 redisLog(REDIS_DEBUG,"Write error sending DB to slave: %s",
5399 strerror(errno));
5400 freeClient(slave);
5401 return;
5402 }
5403 slave->repldboff += nwritten;
5404 if (slave->repldboff == slave->repldbsize) {
5405 close(slave->repldbfd);
5406 slave->repldbfd = -1;
5407 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
5408 slave->replstate = REDIS_REPL_ONLINE;
5409 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
266373b2 5410 sendReplyToClient, slave) == AE_ERR) {
6208b3a7 5411 freeClient(slave);
5412 return;
5413 }
5414 addReplySds(slave,sdsempty());
5415 redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
5416 }
5417}
ed9b544e 5418
a3b21203 5419/* This function is called at the end of every backgrond saving.
5420 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
5421 * otherwise REDIS_ERR is passed to the function.
5422 *
5423 * The goal of this function is to handle slaves waiting for a successful
5424 * background saving in order to perform non-blocking synchronization. */
5425static void updateSlavesWaitingBgsave(int bgsaveerr) {
6208b3a7 5426 listNode *ln;
5427 int startbgsave = 0;
ed9b544e 5428
6208b3a7 5429 listRewind(server.slaves);
5430 while((ln = listYield(server.slaves))) {
5431 redisClient *slave = ln->value;
ed9b544e 5432
6208b3a7 5433 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) {
5434 startbgsave = 1;
5435 slave->replstate = REDIS_REPL_WAIT_BGSAVE_END;
5436 } else if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
dde65f3f 5437 struct redis_stat buf;
6208b3a7 5438
5439 if (bgsaveerr != REDIS_OK) {
5440 freeClient(slave);
5441 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE child returned an error");
5442 continue;
5443 }
5444 if ((slave->repldbfd = open(server.dbfilename,O_RDONLY)) == -1 ||
dde65f3f 5445 redis_fstat(slave->repldbfd,&buf) == -1) {
6208b3a7 5446 freeClient(slave);
5447 redisLog(REDIS_WARNING,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno));
5448 continue;
5449 }
5450 slave->repldboff = 0;
5451 slave->repldbsize = buf.st_size;
5452 slave->replstate = REDIS_REPL_SEND_BULK;
5453 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
266373b2 5454 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE, sendBulkToSlave, slave) == AE_ERR) {
6208b3a7 5455 freeClient(slave);
5456 continue;
5457 }
5458 }
ed9b544e 5459 }
6208b3a7 5460 if (startbgsave) {
5461 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
5462 listRewind(server.slaves);
5463 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE failed");
5464 while((ln = listYield(server.slaves))) {
5465 redisClient *slave = ln->value;
ed9b544e 5466
6208b3a7 5467 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START)
5468 freeClient(slave);
5469 }
5470 }
5471 }
ed9b544e 5472}
5473
5474static int syncWithMaster(void) {
d0ccebcf 5475 char buf[1024], tmpfile[256], authcmd[1024];
ed9b544e 5476 int dumpsize;
5477 int fd = anetTcpConnect(NULL,server.masterhost,server.masterport);
5478 int dfd;
5479
5480 if (fd == -1) {
5481 redisLog(REDIS_WARNING,"Unable to connect to MASTER: %s",
5482 strerror(errno));
5483 return REDIS_ERR;
5484 }
d0ccebcf 5485
5486 /* AUTH with the master if required. */
5487 if(server.masterauth) {
5488 snprintf(authcmd, 1024, "AUTH %s\r\n", server.masterauth);
5489 if (syncWrite(fd, authcmd, strlen(server.masterauth)+7, 5) == -1) {
5490 close(fd);
5491 redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",
5492 strerror(errno));
5493 return REDIS_ERR;
5494 }
5495 /* Read the AUTH result. */
5496 if (syncReadLine(fd,buf,1024,3600) == -1) {
5497 close(fd);
5498 redisLog(REDIS_WARNING,"I/O error reading auth result from MASTER: %s",
5499 strerror(errno));
5500 return REDIS_ERR;
5501 }
5502 if (buf[0] != '+') {
5503 close(fd);
5504 redisLog(REDIS_WARNING,"Cannot AUTH to MASTER, is the masterauth password correct?");
5505 return REDIS_ERR;
5506 }
5507 }
5508
ed9b544e 5509 /* Issue the SYNC command */
5510 if (syncWrite(fd,"SYNC \r\n",7,5) == -1) {
5511 close(fd);
5512 redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
5513 strerror(errno));
5514 return REDIS_ERR;
5515 }
5516 /* Read the bulk write count */
8c4d91fc 5517 if (syncReadLine(fd,buf,1024,3600) == -1) {
ed9b544e 5518 close(fd);
5519 redisLog(REDIS_WARNING,"I/O error reading bulk count from MASTER: %s",
5520 strerror(errno));
5521 return REDIS_ERR;
5522 }
4aa701c1 5523 if (buf[0] != '$') {
5524 close(fd);
5525 redisLog(REDIS_WARNING,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
5526 return REDIS_ERR;
5527 }
c937aa89 5528 dumpsize = atoi(buf+1);
ed9b544e 5529 redisLog(REDIS_NOTICE,"Receiving %d bytes data dump from MASTER",dumpsize);
5530 /* Read the bulk write data on a temp file */
5531 snprintf(tmpfile,256,"temp-%d.%ld.rdb",(int)time(NULL),(long int)random());
5532 dfd = open(tmpfile,O_CREAT|O_WRONLY,0644);
5533 if (dfd == -1) {
5534 close(fd);
5535 redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
5536 return REDIS_ERR;
5537 }
5538 while(dumpsize) {
5539 int nread, nwritten;
5540
5541 nread = read(fd,buf,(dumpsize < 1024)?dumpsize:1024);
5542 if (nread == -1) {
5543 redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
5544 strerror(errno));
5545 close(fd);
5546 close(dfd);
5547 return REDIS_ERR;
5548 }
5549 nwritten = write(dfd,buf,nread);
5550 if (nwritten == -1) {
5551 redisLog(REDIS_WARNING,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
5552 close(fd);
5553 close(dfd);
5554 return REDIS_ERR;
5555 }
5556 dumpsize -= nread;
5557 }
5558 close(dfd);
5559 if (rename(tmpfile,server.dbfilename) == -1) {
5560 redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
5561 unlink(tmpfile);
5562 close(fd);
5563 return REDIS_ERR;
5564 }
5565 emptyDb();
f78fd11b 5566 if (rdbLoad(server.dbfilename) != REDIS_OK) {
ed9b544e 5567 redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
5568 close(fd);
5569 return REDIS_ERR;
5570 }
5571 server.master = createClient(fd);
5572 server.master->flags |= REDIS_MASTER;
5573 server.replstate = REDIS_REPL_CONNECTED;
5574 return REDIS_OK;
5575}
5576
321b0e13 5577static void slaveofCommand(redisClient *c) {
5578 if (!strcasecmp(c->argv[1]->ptr,"no") &&
5579 !strcasecmp(c->argv[2]->ptr,"one")) {
5580 if (server.masterhost) {
5581 sdsfree(server.masterhost);
5582 server.masterhost = NULL;
5583 if (server.master) freeClient(server.master);
5584 server.replstate = REDIS_REPL_NONE;
5585 redisLog(REDIS_NOTICE,"MASTER MODE enabled (user request)");
5586 }
5587 } else {
5588 sdsfree(server.masterhost);
5589 server.masterhost = sdsdup(c->argv[1]->ptr);
5590 server.masterport = atoi(c->argv[2]->ptr);
5591 if (server.master) freeClient(server.master);
5592 server.replstate = REDIS_REPL_CONNECT;
5593 redisLog(REDIS_NOTICE,"SLAVE OF %s:%d enabled (user request)",
5594 server.masterhost, server.masterport);
5595 }
5596 addReply(c,shared.ok);
5597}
5598
3fd78bcd 5599/* ============================ Maxmemory directive ======================== */
5600
5601/* This function gets called when 'maxmemory' is set on the config file to limit
5602 * the max memory used by the server, and we are out of memory.
5603 * This function will try to, in order:
5604 *
5605 * - Free objects from the free list
5606 * - Try to remove keys with an EXPIRE set
5607 *
5608 * It is not possible to free enough memory to reach used-memory < maxmemory
5609 * the server will start refusing commands that will enlarge even more the
5610 * memory usage.
5611 */
5612static void freeMemoryIfNeeded(void) {
5613 while (server.maxmemory && zmalloc_used_memory() > server.maxmemory) {
5614 if (listLength(server.objfreelist)) {
5615 robj *o;
5616
5617 listNode *head = listFirst(server.objfreelist);
5618 o = listNodeValue(head);
5619 listDelNode(server.objfreelist,head);
5620 zfree(o);
5621 } else {
5622 int j, k, freed = 0;
5623
5624 for (j = 0; j < server.dbnum; j++) {
5625 int minttl = -1;
5626 robj *minkey = NULL;
5627 struct dictEntry *de;
5628
5629 if (dictSize(server.db[j].expires)) {
5630 freed = 1;
5631 /* From a sample of three keys drop the one nearest to
5632 * the natural expire */
5633 for (k = 0; k < 3; k++) {
5634 time_t t;
5635
5636 de = dictGetRandomKey(server.db[j].expires);
5637 t = (time_t) dictGetEntryVal(de);
5638 if (minttl == -1 || t < minttl) {
5639 minkey = dictGetEntryKey(de);
5640 minttl = t;
5641 }
5642 }
5643 deleteKey(server.db+j,minkey);
5644 }
5645 }
5646 if (!freed) return; /* nothing to free... */
5647 }
5648 }
5649}
5650
f80dff62 5651/* ============================== Append Only file ========================== */
5652
5653static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {
5654 sds buf = sdsempty();
5655 int j;
5656 ssize_t nwritten;
5657 time_t now;
5658 robj *tmpargv[3];
5659
5660 /* The DB this command was targetting is not the same as the last command
5661 * we appendend. To issue a SELECT command is needed. */
5662 if (dictid != server.appendseldb) {
5663 char seldb[64];
5664
5665 snprintf(seldb,sizeof(seldb),"%d",dictid);
682ac724 5666 buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
f80dff62 5667 strlen(seldb),seldb);
5668 server.appendseldb = dictid;
5669 }
5670
5671 /* "Fix" the argv vector if the command is EXPIRE. We want to translate
5672 * EXPIREs into EXPIREATs calls */
5673 if (cmd->proc == expireCommand) {
5674 long when;
5675
5676 tmpargv[0] = createStringObject("EXPIREAT",8);
5677 tmpargv[1] = argv[1];
5678 incrRefCount(argv[1]);
5679 when = time(NULL)+strtol(argv[2]->ptr,NULL,10);
5680 tmpargv[2] = createObject(REDIS_STRING,
5681 sdscatprintf(sdsempty(),"%ld",when));
5682 argv = tmpargv;
5683 }
5684
5685 /* Append the actual command */
5686 buf = sdscatprintf(buf,"*%d\r\n",argc);
5687 for (j = 0; j < argc; j++) {
5688 robj *o = argv[j];
5689
9d65a1bb 5690 o = getDecodedObject(o);
682ac724 5691 buf = sdscatprintf(buf,"$%lu\r\n",sdslen(o->ptr));
f80dff62 5692 buf = sdscatlen(buf,o->ptr,sdslen(o->ptr));
5693 buf = sdscatlen(buf,"\r\n",2);
9d65a1bb 5694 decrRefCount(o);
f80dff62 5695 }
5696
5697 /* Free the objects from the modified argv for EXPIREAT */
5698 if (cmd->proc == expireCommand) {
5699 for (j = 0; j < 3; j++)
5700 decrRefCount(argv[j]);
5701 }
5702
5703 /* We want to perform a single write. This should be guaranteed atomic
5704 * at least if the filesystem we are writing is a real physical one.
5705 * While this will save us against the server being killed I don't think
5706 * there is much to do about the whole server stopping for power problems
5707 * or alike */
5708 nwritten = write(server.appendfd,buf,sdslen(buf));
5709 if (nwritten != (signed)sdslen(buf)) {
5710 /* Ooops, we are in troubles. The best thing to do for now is
5711 * to simply exit instead to give the illusion that everything is
5712 * working as expected. */
5713 if (nwritten == -1) {
5714 redisLog(REDIS_WARNING,"Exiting on error writing to the append-only file: %s",strerror(errno));
5715 } else {
5716 redisLog(REDIS_WARNING,"Exiting on short write while writing to the append-only file: %s",strerror(errno));
5717 }
5718 exit(1);
5719 }
85a83172 5720 /* If a background append only file rewriting is in progress we want to
5721 * accumulate the differences between the child DB and the current one
5722 * in a buffer, so that when the child process will do its work we
5723 * can append the differences to the new append only file. */
5724 if (server.bgrewritechildpid != -1)
5725 server.bgrewritebuf = sdscatlen(server.bgrewritebuf,buf,sdslen(buf));
5726
5727 sdsfree(buf);
f80dff62 5728 now = time(NULL);
5729 if (server.appendfsync == APPENDFSYNC_ALWAYS ||
5730 (server.appendfsync == APPENDFSYNC_EVERYSEC &&
5731 now-server.lastfsync > 1))
5732 {
5733 fsync(server.appendfd); /* Let's try to get this data on the disk */
5734 server.lastfsync = now;
5735 }
5736}
5737
5738/* In Redis commands are always executed in the context of a client, so in
5739 * order to load the append only file we need to create a fake client. */
5740static struct redisClient *createFakeClient(void) {
5741 struct redisClient *c = zmalloc(sizeof(*c));
5742
5743 selectDb(c,0);
5744 c->fd = -1;
5745 c->querybuf = sdsempty();
5746 c->argc = 0;
5747 c->argv = NULL;
5748 c->flags = 0;
9387d17d 5749 /* We set the fake client as a slave waiting for the synchronization
5750 * so that Redis will not try to send replies to this client. */
5751 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
f80dff62 5752 c->reply = listCreate();
5753 listSetFreeMethod(c->reply,decrRefCount);
5754 listSetDupMethod(c->reply,dupClientReplyValue);
5755 return c;
5756}
5757
5758static void freeFakeClient(struct redisClient *c) {
5759 sdsfree(c->querybuf);
5760 listRelease(c->reply);
5761 zfree(c);
5762}
5763
5764/* Replay the append log file. On error REDIS_OK is returned. On non fatal
5765 * error (the append only file is zero-length) REDIS_ERR is returned. On
5766 * fatal error an error message is logged and the program exists. */
5767int loadAppendOnlyFile(char *filename) {
5768 struct redisClient *fakeClient;
5769 FILE *fp = fopen(filename,"r");
5770 struct redis_stat sb;
5771
5772 if (redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0)
5773 return REDIS_ERR;
5774
5775 if (fp == NULL) {
5776 redisLog(REDIS_WARNING,"Fatal error: can't open the append log file for reading: %s",strerror(errno));
5777 exit(1);
5778 }
5779
5780 fakeClient = createFakeClient();
5781 while(1) {
5782 int argc, j;
5783 unsigned long len;
5784 robj **argv;
5785 char buf[128];
5786 sds argsds;
5787 struct redisCommand *cmd;
5788
5789 if (fgets(buf,sizeof(buf),fp) == NULL) {
5790 if (feof(fp))
5791 break;
5792 else
5793 goto readerr;
5794 }
5795 if (buf[0] != '*') goto fmterr;
5796 argc = atoi(buf+1);
5797 argv = zmalloc(sizeof(robj*)*argc);
5798 for (j = 0; j < argc; j++) {
5799 if (fgets(buf,sizeof(buf),fp) == NULL) goto readerr;
5800 if (buf[0] != '$') goto fmterr;
5801 len = strtol(buf+1,NULL,10);
5802 argsds = sdsnewlen(NULL,len);
0f151ef1 5803 if (len && fread(argsds,len,1,fp) == 0) goto fmterr;
f80dff62 5804 argv[j] = createObject(REDIS_STRING,argsds);
5805 if (fread(buf,2,1,fp) == 0) goto fmterr; /* discard CRLF */
5806 }
5807
5808 /* Command lookup */
5809 cmd = lookupCommand(argv[0]->ptr);
5810 if (!cmd) {
5811 redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", argv[0]->ptr);
5812 exit(1);
5813 }
5814 /* Try object sharing and encoding */
5815 if (server.shareobjects) {
5816 int j;
5817 for(j = 1; j < argc; j++)
5818 argv[j] = tryObjectSharing(argv[j]);
5819 }
5820 if (cmd->flags & REDIS_CMD_BULK)
5821 tryObjectEncoding(argv[argc-1]);
5822 /* Run the command in the context of a fake client */
5823 fakeClient->argc = argc;
5824 fakeClient->argv = argv;
5825 cmd->proc(fakeClient);
5826 /* Discard the reply objects list from the fake client */
5827 while(listLength(fakeClient->reply))
5828 listDelNode(fakeClient->reply,listFirst(fakeClient->reply));
5829 /* Clean up, ready for the next command */
5830 for (j = 0; j < argc; j++) decrRefCount(argv[j]);
5831 zfree(argv);
5832 }
5833 fclose(fp);
5834 freeFakeClient(fakeClient);
5835 return REDIS_OK;
5836
5837readerr:
5838 if (feof(fp)) {
5839 redisLog(REDIS_WARNING,"Unexpected end of file reading the append only file");
5840 } else {
5841 redisLog(REDIS_WARNING,"Unrecoverable error reading the append only file: %s", strerror(errno));
5842 }
5843 exit(1);
5844fmterr:
5845 redisLog(REDIS_WARNING,"Bad file format reading the append only file");
5846 exit(1);
5847}
5848
9d65a1bb 5849/* Write an object into a file in the bulk format $<count>\r\n<payload>\r\n */
5850static int fwriteBulk(FILE *fp, robj *obj) {
5851 char buf[128];
5852 obj = getDecodedObject(obj);
5853 snprintf(buf,sizeof(buf),"$%ld\r\n",(long)sdslen(obj->ptr));
5854 if (fwrite(buf,strlen(buf),1,fp) == 0) goto err;
5855 if (fwrite(obj->ptr,sdslen(obj->ptr),1,fp) == 0) goto err;
5856 if (fwrite("\r\n",2,1,fp) == 0) goto err;
5857 decrRefCount(obj);
5858 return 1;
5859err:
5860 decrRefCount(obj);
5861 return 0;
5862}
5863
5864/* Write a double value in bulk format $<count>\r\n<payload>\r\n */
5865static int fwriteBulkDouble(FILE *fp, double d) {
5866 char buf[128], dbuf[128];
5867
5868 snprintf(dbuf,sizeof(dbuf),"%.17g\r\n",d);
5869 snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(dbuf)-2);
5870 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
5871 if (fwrite(dbuf,strlen(dbuf),1,fp) == 0) return 0;
5872 return 1;
5873}
5874
5875/* Write a long value in bulk format $<count>\r\n<payload>\r\n */
5876static int fwriteBulkLong(FILE *fp, long l) {
5877 char buf[128], lbuf[128];
5878
5879 snprintf(lbuf,sizeof(lbuf),"%ld\r\n",l);
5880 snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(lbuf)-2);
5881 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
5882 if (fwrite(lbuf,strlen(lbuf),1,fp) == 0) return 0;
5883 return 1;
5884}
5885
5886/* Write a sequence of commands able to fully rebuild the dataset into
5887 * "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
5888static int rewriteAppendOnlyFile(char *filename) {
5889 dictIterator *di = NULL;
5890 dictEntry *de;
5891 FILE *fp;
5892 char tmpfile[256];
5893 int j;
5894 time_t now = time(NULL);
5895
5896 /* Note that we have to use a different temp name here compared to the
5897 * one used by rewriteAppendOnlyFileBackground() function. */
5898 snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid());
5899 fp = fopen(tmpfile,"w");
5900 if (!fp) {
5901 redisLog(REDIS_WARNING, "Failed rewriting the append only file: %s", strerror(errno));
5902 return REDIS_ERR;
5903 }
5904 for (j = 0; j < server.dbnum; j++) {
5905 char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n";
5906 redisDb *db = server.db+j;
5907 dict *d = db->dict;
5908 if (dictSize(d) == 0) continue;
5909 di = dictGetIterator(d);
5910 if (!di) {
5911 fclose(fp);
5912 return REDIS_ERR;
5913 }
5914
5915 /* SELECT the new DB */
5916 if (fwrite(selectcmd,sizeof(selectcmd)-1,1,fp) == 0) goto werr;
85a83172 5917 if (fwriteBulkLong(fp,j) == 0) goto werr;
9d65a1bb 5918
5919 /* Iterate this DB writing every entry */
5920 while((de = dictNext(di)) != NULL) {
5921 robj *key = dictGetEntryKey(de);
5922 robj *o = dictGetEntryVal(de);
5923 time_t expiretime = getExpire(db,key);
5924
5925 /* Save the key and associated value */
9d65a1bb 5926 if (o->type == REDIS_STRING) {
5927 /* Emit a SET command */
5928 char cmd[]="*3\r\n$3\r\nSET\r\n";
5929 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
5930 /* Key and value */
5931 if (fwriteBulk(fp,key) == 0) goto werr;
5932 if (fwriteBulk(fp,o) == 0) goto werr;
5933 } else if (o->type == REDIS_LIST) {
5934 /* Emit the RPUSHes needed to rebuild the list */
5935 list *list = o->ptr;
5936 listNode *ln;
5937
5938 listRewind(list);
5939 while((ln = listYield(list))) {
5940 char cmd[]="*3\r\n$5\r\nRPUSH\r\n";
5941 robj *eleobj = listNodeValue(ln);
5942
5943 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
5944 if (fwriteBulk(fp,key) == 0) goto werr;
5945 if (fwriteBulk(fp,eleobj) == 0) goto werr;
5946 }
5947 } else if (o->type == REDIS_SET) {
5948 /* Emit the SADDs needed to rebuild the set */
5949 dict *set = o->ptr;
5950 dictIterator *di = dictGetIterator(set);
5951 dictEntry *de;
5952
5953 while((de = dictNext(di)) != NULL) {
5954 char cmd[]="*3\r\n$4\r\nSADD\r\n";
5955 robj *eleobj = dictGetEntryKey(de);
5956
5957 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
5958 if (fwriteBulk(fp,key) == 0) goto werr;
5959 if (fwriteBulk(fp,eleobj) == 0) goto werr;
5960 }
5961 dictReleaseIterator(di);
5962 } else if (o->type == REDIS_ZSET) {
5963 /* Emit the ZADDs needed to rebuild the sorted set */
5964 zset *zs = o->ptr;
5965 dictIterator *di = dictGetIterator(zs->dict);
5966 dictEntry *de;
5967
5968 while((de = dictNext(di)) != NULL) {
5969 char cmd[]="*4\r\n$4\r\nZADD\r\n";
5970 robj *eleobj = dictGetEntryKey(de);
5971 double *score = dictGetEntryVal(de);
5972
5973 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
5974 if (fwriteBulk(fp,key) == 0) goto werr;
5975 if (fwriteBulkDouble(fp,*score) == 0) goto werr;
5976 if (fwriteBulk(fp,eleobj) == 0) goto werr;
5977 }
5978 dictReleaseIterator(di);
5979 } else {
dfc5e96c 5980 redisAssert(0 != 0);
9d65a1bb 5981 }
5982 /* Save the expire time */
5983 if (expiretime != -1) {
5984 char cmd[]="*3\r\n$6\r\nEXPIRE\r\n";
5985 /* If this key is already expired skip it */
5986 if (expiretime < now) continue;
5987 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
5988 if (fwriteBulk(fp,key) == 0) goto werr;
5989 if (fwriteBulkLong(fp,expiretime) == 0) goto werr;
5990 }
5991 }
5992 dictReleaseIterator(di);
5993 }
5994
5995 /* Make sure data will not remain on the OS's output buffers */
5996 fflush(fp);
5997 fsync(fileno(fp));
5998 fclose(fp);
5999
6000 /* Use RENAME to make sure the DB file is changed atomically only
6001 * if the generate DB file is ok. */
6002 if (rename(tmpfile,filename) == -1) {
6003 redisLog(REDIS_WARNING,"Error moving temp append only file on the final destination: %s", strerror(errno));
6004 unlink(tmpfile);
6005 return REDIS_ERR;
6006 }
6007 redisLog(REDIS_NOTICE,"SYNC append only file rewrite performed");
6008 return REDIS_OK;
6009
6010werr:
6011 fclose(fp);
6012 unlink(tmpfile);
6013 redisLog(REDIS_WARNING,"Write error writing append only fileon disk: %s", strerror(errno));
6014 if (di) dictReleaseIterator(di);
6015 return REDIS_ERR;
6016}
6017
6018/* This is how rewriting of the append only file in background works:
6019 *
6020 * 1) The user calls BGREWRITEAOF
6021 * 2) Redis calls this function, that forks():
6022 * 2a) the child rewrite the append only file in a temp file.
6023 * 2b) the parent accumulates differences in server.bgrewritebuf.
6024 * 3) When the child finished '2a' exists.
6025 * 4) The parent will trap the exit code, if it's OK, will append the
6026 * data accumulated into server.bgrewritebuf into the temp file, and
6027 * finally will rename(2) the temp file in the actual file name.
6028 * The the new file is reopened as the new append only file. Profit!
6029 */
6030static int rewriteAppendOnlyFileBackground(void) {
6031 pid_t childpid;
6032
6033 if (server.bgrewritechildpid != -1) return REDIS_ERR;
6034 if ((childpid = fork()) == 0) {
6035 /* Child */
6036 char tmpfile[256];
6037 close(server.fd);
6038
6039 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
6040 if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
6041 exit(0);
6042 } else {
6043 exit(1);
6044 }
6045 } else {
6046 /* Parent */
6047 if (childpid == -1) {
6048 redisLog(REDIS_WARNING,
6049 "Can't rewrite append only file in background: fork: %s",
6050 strerror(errno));
6051 return REDIS_ERR;
6052 }
6053 redisLog(REDIS_NOTICE,
6054 "Background append only file rewriting started by pid %d",childpid);
6055 server.bgrewritechildpid = childpid;
85a83172 6056 /* We set appendseldb to -1 in order to force the next call to the
6057 * feedAppendOnlyFile() to issue a SELECT command, so the differences
6058 * accumulated by the parent into server.bgrewritebuf will start
6059 * with a SELECT statement and it will be safe to merge. */
6060 server.appendseldb = -1;
9d65a1bb 6061 return REDIS_OK;
6062 }
6063 return REDIS_OK; /* unreached */
6064}
6065
6066static void bgrewriteaofCommand(redisClient *c) {
6067 if (server.bgrewritechildpid != -1) {
6068 addReplySds(c,sdsnew("-ERR background append only file rewriting already in progress\r\n"));
6069 return;
6070 }
6071 if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
6072 addReply(c,shared.ok);
6073 } else {
6074 addReply(c,shared.err);
6075 }
6076}
6077
6078static void aofRemoveTempFile(pid_t childpid) {
6079 char tmpfile[256];
6080
6081 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) childpid);
6082 unlink(tmpfile);
6083}
6084
7f957c92 6085/* ================================= Debugging ============================== */
6086
6087static void debugCommand(redisClient *c) {
6088 if (!strcasecmp(c->argv[1]->ptr,"segfault")) {
6089 *((char*)-1) = 'x';
210e29f7 6090 } else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
6091 if (rdbSave(server.dbfilename) != REDIS_OK) {
6092 addReply(c,shared.err);
6093 return;
6094 }
6095 emptyDb();
6096 if (rdbLoad(server.dbfilename) != REDIS_OK) {
6097 addReply(c,shared.err);
6098 return;
6099 }
6100 redisLog(REDIS_WARNING,"DB reloaded by DEBUG RELOAD");
6101 addReply(c,shared.ok);
333298da 6102 } else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
6103 dictEntry *de = dictFind(c->db->dict,c->argv[2]);
6104 robj *key, *val;
6105
6106 if (!de) {
6107 addReply(c,shared.nokeyerr);
6108 return;
6109 }
6110 key = dictGetEntryKey(de);
6111 val = dictGetEntryVal(de);
6112 addReplySds(c,sdscatprintf(sdsempty(),
942a3961 6113 "+Key at:%p refcount:%d, value at:%p refcount:%d encoding:%d\r\n",
682ac724 6114 (void*)key, key->refcount, (void*)val, val->refcount,
6115 val->encoding));
7f957c92 6116 } else {
333298da 6117 addReplySds(c,sdsnew(
210e29f7 6118 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|RELOAD]\r\n"));
7f957c92 6119 }
6120}
56906eef 6121
dfc5e96c 6122static void _redisAssert(char *estr) {
6123 redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
6124 redisLog(REDIS_WARNING,"==> %s\n",estr);
6125#ifdef HAVE_BACKTRACE
6126 redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
6127 *((char*)-1) = 'x';
6128#endif
6129}
6130
bcfc686d 6131/* =================================== Main! ================================ */
56906eef 6132
bcfc686d 6133#ifdef __linux__
6134int linuxOvercommitMemoryValue(void) {
6135 FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
6136 char buf[64];
56906eef 6137
bcfc686d 6138 if (!fp) return -1;
6139 if (fgets(buf,64,fp) == NULL) {
6140 fclose(fp);
6141 return -1;
6142 }
6143 fclose(fp);
56906eef 6144
bcfc686d 6145 return atoi(buf);
6146}
6147
6148void linuxOvercommitMemoryWarning(void) {
6149 if (linuxOvercommitMemoryValue() == 0) {
6150 redisLog(REDIS_WARNING,"WARNING overcommit_memory is set to 0! Background save may fail under low condition memory. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.");
6151 }
6152}
6153#endif /* __linux__ */
6154
6155static void daemonize(void) {
6156 int fd;
6157 FILE *fp;
6158
6159 if (fork() != 0) exit(0); /* parent exits */
71c54b21 6160 printf("New pid: %d\n", getpid());
bcfc686d 6161 setsid(); /* create a new session */
6162
6163 /* Every output goes to /dev/null. If Redis is daemonized but
6164 * the 'logfile' is set to 'stdout' in the configuration file
6165 * it will not log at all. */
6166 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
6167 dup2(fd, STDIN_FILENO);
6168 dup2(fd, STDOUT_FILENO);
6169 dup2(fd, STDERR_FILENO);
6170 if (fd > STDERR_FILENO) close(fd);
6171 }
6172 /* Try to write the pid file */
6173 fp = fopen(server.pidfile,"w");
6174 if (fp) {
6175 fprintf(fp,"%d\n",getpid());
6176 fclose(fp);
56906eef 6177 }
56906eef 6178}
6179
bcfc686d 6180int main(int argc, char **argv) {
6181 initServerConfig();
6182 if (argc == 2) {
6183 resetServerSaveParams();
6184 loadServerConfig(argv[1]);
6185 } else if (argc > 2) {
6186 fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
6187 exit(1);
6188 } else {
6189 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'");
6190 }
bcfc686d 6191 if (server.daemonize) daemonize();
71c54b21 6192 initServer();
bcfc686d 6193 redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
6194#ifdef __linux__
6195 linuxOvercommitMemoryWarning();
6196#endif
6197 if (server.appendonly) {
6198 if (loadAppendOnlyFile(server.appendfilename) == REDIS_OK)
6199 redisLog(REDIS_NOTICE,"DB loaded from append only file");
6200 } else {
6201 if (rdbLoad(server.dbfilename) == REDIS_OK)
6202 redisLog(REDIS_NOTICE,"DB loaded from disk");
6203 }
6204 if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,
266373b2 6205 acceptHandler, NULL) == AE_ERR) oom("creating file event");
bcfc686d 6206 redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
6207 aeMain(server.el);
6208 aeDeleteEventLoop(server.el);
6209 return 0;
6210}
6211
6212/* ============================= Backtrace support ========================= */
6213
6214#ifdef HAVE_BACKTRACE
6215static char *findFuncName(void *pointer, unsigned long *offset);
6216
56906eef 6217static void *getMcontextEip(ucontext_t *uc) {
6218#if defined(__FreeBSD__)
6219 return (void*) uc->uc_mcontext.mc_eip;
6220#elif defined(__dietlibc__)
6221 return (void*) uc->uc_mcontext.eip;
06db1f50 6222#elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
da0a1620 6223 #if __x86_64__
6224 return (void*) uc->uc_mcontext->__ss.__rip;
6225 #else
56906eef 6226 return (void*) uc->uc_mcontext->__ss.__eip;
da0a1620 6227 #endif
06db1f50 6228#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
cb7e07cc 6229 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
06db1f50 6230 return (void*) uc->uc_mcontext->__ss.__rip;
cbc59b38 6231 #else
6232 return (void*) uc->uc_mcontext->__ss.__eip;
6233 #endif
b91cf5ef 6234#elif defined(__i386__) || defined(__X86_64__) /* Linux x86 */
56906eef 6235 return (void*) uc->uc_mcontext.gregs[REG_EIP];
b91cf5ef 6236#elif defined(__ia64__) /* Linux IA64 */
6237 return (void*) uc->uc_mcontext.sc_ip;
6238#else
6239 return NULL;
56906eef 6240#endif
6241}
6242
6243static void segvHandler(int sig, siginfo_t *info, void *secret) {
6244 void *trace[100];
6245 char **messages = NULL;
6246 int i, trace_size = 0;
6247 unsigned long offset=0;
56906eef 6248 ucontext_t *uc = (ucontext_t*) secret;
1c85b79f 6249 sds infostring;
56906eef 6250 REDIS_NOTUSED(info);
6251
6252 redisLog(REDIS_WARNING,
6253 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION, sig);
1c85b79f 6254 infostring = genRedisInfoString();
6255 redisLog(REDIS_WARNING, "%s",infostring);
6256 /* It's not safe to sdsfree() the returned string under memory
6257 * corruption conditions. Let it leak as we are going to abort */
56906eef 6258
6259 trace_size = backtrace(trace, 100);
de96dbfe 6260 /* overwrite sigaction with caller's address */
b91cf5ef 6261 if (getMcontextEip(uc) != NULL) {
6262 trace[1] = getMcontextEip(uc);
6263 }
56906eef 6264 messages = backtrace_symbols(trace, trace_size);
fe3bbfbe 6265
d76412d1 6266 for (i=1; i<trace_size; ++i) {
56906eef 6267 char *fn = findFuncName(trace[i], &offset), *p;
6268
6269 p = strchr(messages[i],'+');
6270 if (!fn || (p && ((unsigned long)strtol(p+1,NULL,10)) < offset)) {
6271 redisLog(REDIS_WARNING,"%s", messages[i]);
6272 } else {
6273 redisLog(REDIS_WARNING,"%d redis-server %p %s + %d", i, trace[i], fn, (unsigned int)offset);
6274 }
6275 }
1c85b79f 6276 // free(messages); Don't call free() with possibly corrupted memory.
56906eef 6277 exit(0);
fe3bbfbe 6278}
56906eef 6279
6280static void setupSigSegvAction(void) {
6281 struct sigaction act;
6282
6283 sigemptyset (&act.sa_mask);
6284 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
6285 * is used. Otherwise, sa_handler is used */
6286 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
6287 act.sa_sigaction = segvHandler;
6288 sigaction (SIGSEGV, &act, NULL);
6289 sigaction (SIGBUS, &act, NULL);
12fea928 6290 sigaction (SIGFPE, &act, NULL);
6291 sigaction (SIGILL, &act, NULL);
6292 sigaction (SIGBUS, &act, NULL);
e65fdc78 6293 return;
56906eef 6294}
e65fdc78 6295
bcfc686d 6296#include "staticsymbols.h"
6297/* This function try to convert a pointer into a function name. It's used in
6298 * oreder to provide a backtrace under segmentation fault that's able to
6299 * display functions declared as static (otherwise the backtrace is useless). */
6300static char *findFuncName(void *pointer, unsigned long *offset){
6301 int i, ret = -1;
6302 unsigned long off, minoff = 0;
ed9b544e 6303
bcfc686d 6304 /* Try to match against the Symbol with the smallest offset */
6305 for (i=0; symsTable[i].pointer; i++) {
6306 unsigned long lp = (unsigned long) pointer;
0bc03378 6307
bcfc686d 6308 if (lp != (unsigned long)-1 && lp >= symsTable[i].pointer) {
6309 off=lp-symsTable[i].pointer;
6310 if (ret < 0 || off < minoff) {
6311 minoff=off;
6312 ret=i;
6313 }
6314 }
0bc03378 6315 }
bcfc686d 6316 if (ret == -1) return NULL;
6317 *offset = minoff;
6318 return symsTable[ret].name;
0bc03378 6319}
bcfc686d 6320#else /* HAVE_BACKTRACE */
6321static void setupSigSegvAction(void) {
0bc03378 6322}
bcfc686d 6323#endif /* HAVE_BACKTRACE */
0bc03378 6324
ed9b544e 6325
ed9b544e 6326
bcfc686d 6327/* The End */
6328
6329
ed9b544e 6330