2 * Copyright (c) 2006-2009, Salvatore Sanfilippo <antirez at gmail dot com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
30 #define REDIS_VERSION "1.050"
40 #define __USE_POSIX199309
46 #endif /* HAVE_BACKTRACE */
54 #include <arpa/inet.h>
58 #include <sys/resource.h>
63 #include "ae.h" /* Event driven programming library */
64 #include "sds.h" /* Dynamic safe strings */
65 #include "anet.h" /* Networking the easy way */
66 #include "dict.h" /* Hash tables */
67 #include "adlist.h" /* Linked lists */
68 #include "zmalloc.h" /* total memory usage aware version of malloc/free */
69 #include "lzf.h" /* LZF compression library */
70 #include "pqsort.h" /* Partial qsort for SORT+LIMIT */
76 /* Static server configuration */
77 #define REDIS_SERVERPORT 6379 /* TCP port */
78 #define REDIS_MAXIDLETIME (60*5) /* default client timeout */
79 #define REDIS_IOBUF_LEN 1024
80 #define REDIS_LOADBUF_LEN 1024
81 #define REDIS_STATIC_ARGS 4
82 #define REDIS_DEFAULT_DBNUM 16
83 #define REDIS_CONFIGLINE_MAX 1024
84 #define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
85 #define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
86 #define REDIS_EXPIRELOOKUPS_PER_CRON 100 /* try to expire 100 keys/second */
87 #define REDIS_MAX_WRITE_PER_EVENT (1024*64)
88 #define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
90 /* Hash table parameters */
91 #define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
94 #define REDIS_CMD_BULK 1 /* Bulk write command */
95 #define REDIS_CMD_INLINE 2 /* Inline command */
96 /* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
97 this flags will return an error when the 'maxmemory' option is set in the
98 config file and the server is using more than maxmemory bytes of memory.
99 In short this commands are denied on low memory conditions. */
100 #define REDIS_CMD_DENYOOM 4
103 #define REDIS_STRING 0
109 /* Objects encoding */
110 #define REDIS_ENCODING_RAW 0 /* Raw representation */
111 #define REDIS_ENCODING_INT 1 /* Encoded as integer */
113 /* Object types only used for dumping to disk */
114 #define REDIS_EXPIRETIME 253
115 #define REDIS_SELECTDB 254
116 #define REDIS_EOF 255
118 /* Defines related to the dump file format. To store 32 bits lengths for short
119 * keys requires a lot of space, so we check the most significant 2 bits of
120 * the first byte to interpreter the length:
122 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
123 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
124 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
125 * 11|000000 this means: specially encoded object will follow. The six bits
126 * number specify the kind of object that follows.
127 * See the REDIS_RDB_ENC_* defines.
129 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
130 * values, will fit inside. */
131 #define REDIS_RDB_6BITLEN 0
132 #define REDIS_RDB_14BITLEN 1
133 #define REDIS_RDB_32BITLEN 2
134 #define REDIS_RDB_ENCVAL 3
135 #define REDIS_RDB_LENERR UINT_MAX
137 /* When a length of a string object stored on disk has the first two bits
138 * set, the remaining two bits specify a special encoding for the object
139 * accordingly to the following defines: */
140 #define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
141 #define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
142 #define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
143 #define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
146 #define REDIS_CLOSE 1 /* This client connection should be closed ASAP */
147 #define REDIS_SLAVE 2 /* This client is a slave server */
148 #define REDIS_MASTER 4 /* This client is a master server */
149 #define REDIS_MONITOR 8 /* This client is a slave monitor, see MONITOR */
151 /* Slave replication state - slave side */
152 #define REDIS_REPL_NONE 0 /* No active replication */
153 #define REDIS_REPL_CONNECT 1 /* Must connect to master */
154 #define REDIS_REPL_CONNECTED 2 /* Connected to master */
156 /* Slave replication state - from the point of view of master
157 * Note that in SEND_BULK and ONLINE state the slave receives new updates
158 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
159 * to start the next background saving in order to send updates to it. */
160 #define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
161 #define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
162 #define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
163 #define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
165 /* List related stuff */
169 /* Sort operations */
170 #define REDIS_SORT_GET 0
171 #define REDIS_SORT_DEL 1
172 #define REDIS_SORT_INCR 2
173 #define REDIS_SORT_DECR 3
174 #define REDIS_SORT_ASC 4
175 #define REDIS_SORT_DESC 5
176 #define REDIS_SORTKEY_MAX 1024
179 #define REDIS_DEBUG 0
180 #define REDIS_NOTICE 1
181 #define REDIS_WARNING 2
183 /* Anti-warning macro... */
184 #define REDIS_NOTUSED(V) ((void) V)
186 #define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
187 #define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
189 /*================================= Data types ============================== */
191 /* A redis object, that is a type able to hold a string / list / set */
192 typedef struct redisObject
{
195 unsigned char encoding
;
196 unsigned char notused
[2];
200 typedef struct redisDb
{
206 /* With multiplexing we need to take per-clinet state.
207 * Clients are taken in a liked list. */
208 typedef struct redisClient
{
213 robj
**argv
, **mbargv
;
215 int bulklen
; /* bulk read len. -1 if not in bulk read mode */
216 int multibulk
; /* multi bulk command format active */
219 time_t lastinteraction
; /* time of the last interaction, used for timeout */
220 int flags
; /* REDIS_CLOSE | REDIS_SLAVE | REDIS_MONITOR */
221 int slaveseldb
; /* slave selected db, if this client is a slave */
222 int authenticated
; /* when requirepass is non-NULL */
223 int replstate
; /* replication state if this is a slave */
224 int repldbfd
; /* replication DB file descriptor */
225 long repldboff
; /* replication DB file offset */
226 off_t repldbsize
; /* replication DB file size */
234 /* Global server state structure */
240 unsigned int sharingpoolsize
;
241 long long dirty
; /* changes to DB from the last save */
243 list
*slaves
, *monitors
;
244 char neterr
[ANET_ERR_LEN
];
246 int cronloops
; /* number of times the cron function run */
247 list
*objfreelist
; /* A list of freed objects to avoid malloc() */
248 time_t lastsave
; /* Unix time of last save succeeede */
249 size_t usedmemory
; /* Used memory in megabytes */
250 /* Fields used only for stats */
251 time_t stat_starttime
; /* server start time */
252 long long stat_numcommands
; /* number of processed commands */
253 long long stat_numconnections
; /* number of connections received */
261 int bgsaveinprogress
;
262 pid_t bgsavechildpid
;
263 struct saveparam
*saveparams
;
270 /* Replication related */
274 redisClient
*master
; /* client that is master for this slave */
276 unsigned int maxclients
;
277 unsigned long maxmemory
;
278 /* Sort parameters - qsort_r() is only available under BSD so we
279 * have to take this state global, in order to pass it to sortCompare() */
285 typedef void redisCommandProc(redisClient
*c
);
286 struct redisCommand
{
288 redisCommandProc
*proc
;
293 struct redisFunctionSym
{
295 unsigned long pointer
;
298 typedef struct _redisSortObject
{
306 typedef struct _redisSortOperation
{
309 } redisSortOperation
;
311 /* ZSETs use a specialized version of Skiplists */
313 typedef struct zskiplistNode
{
314 struct zskiplistNode
**forward
;
315 struct zskiplistNode
*backward
;
320 typedef struct zskiplist
{
321 struct zskiplistNode
*header
, *tail
;
326 typedef struct zset
{
331 /* Our shared "common" objects */
333 struct sharedObjectsStruct
{
334 robj
*crlf
, *ok
, *err
, *emptybulk
, *czero
, *cone
, *pong
, *space
,
335 *colon
, *nullbulk
, *nullmultibulk
,
336 *emptymultibulk
, *wrongtypeerr
, *nokeyerr
, *syntaxerr
, *sameobjecterr
,
337 *outofrangeerr
, *plus
,
338 *select0
, *select1
, *select2
, *select3
, *select4
,
339 *select5
, *select6
, *select7
, *select8
, *select9
;
342 /* Global vars that are actally used as constants. The following double
343 * values are used for double on-disk serialization, and are initialized
344 * at runtime to avoid strange compiler optimizations. */
346 static double R_Zero
, R_PosInf
, R_NegInf
, R_Nan
;
348 /*================================ Prototypes =============================== */
350 static void freeStringObject(robj
*o
);
351 static void freeListObject(robj
*o
);
352 static void freeSetObject(robj
*o
);
353 static void decrRefCount(void *o
);
354 static robj
*createObject(int type
, void *ptr
);
355 static void freeClient(redisClient
*c
);
356 static int rdbLoad(char *filename
);
357 static void addReply(redisClient
*c
, robj
*obj
);
358 static void addReplySds(redisClient
*c
, sds s
);
359 static void incrRefCount(robj
*o
);
360 static int rdbSaveBackground(char *filename
);
361 static robj
*createStringObject(char *ptr
, size_t len
);
362 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
);
363 static int syncWithMaster(void);
364 static robj
*tryObjectSharing(robj
*o
);
365 static int tryObjectEncoding(robj
*o
);
366 static robj
*getDecodedObject(const robj
*o
);
367 static int removeExpire(redisDb
*db
, robj
*key
);
368 static int expireIfNeeded(redisDb
*db
, robj
*key
);
369 static int deleteIfVolatile(redisDb
*db
, robj
*key
);
370 static int deleteKey(redisDb
*db
, robj
*key
);
371 static time_t getExpire(redisDb
*db
, robj
*key
);
372 static int setExpire(redisDb
*db
, robj
*key
, time_t when
);
373 static void updateSlavesWaitingBgsave(int bgsaveerr
);
374 static void freeMemoryIfNeeded(void);
375 static int processCommand(redisClient
*c
);
376 static void setupSigSegvAction(void);
377 static void rdbRemoveTempFile(pid_t childpid
);
378 static size_t stringObjectLen(robj
*o
);
379 static void processInputBuffer(redisClient
*c
);
380 static zskiplist
*zslCreate(void);
381 static void zslFree(zskiplist
*zsl
);
382 static void zslInsert(zskiplist
*zsl
, double score
, robj
*obj
);
384 static void authCommand(redisClient
*c
);
385 static void pingCommand(redisClient
*c
);
386 static void echoCommand(redisClient
*c
);
387 static void setCommand(redisClient
*c
);
388 static void setnxCommand(redisClient
*c
);
389 static void getCommand(redisClient
*c
);
390 static void delCommand(redisClient
*c
);
391 static void existsCommand(redisClient
*c
);
392 static void incrCommand(redisClient
*c
);
393 static void decrCommand(redisClient
*c
);
394 static void incrbyCommand(redisClient
*c
);
395 static void decrbyCommand(redisClient
*c
);
396 static void selectCommand(redisClient
*c
);
397 static void randomkeyCommand(redisClient
*c
);
398 static void keysCommand(redisClient
*c
);
399 static void dbsizeCommand(redisClient
*c
);
400 static void lastsaveCommand(redisClient
*c
);
401 static void saveCommand(redisClient
*c
);
402 static void bgsaveCommand(redisClient
*c
);
403 static void shutdownCommand(redisClient
*c
);
404 static void moveCommand(redisClient
*c
);
405 static void renameCommand(redisClient
*c
);
406 static void renamenxCommand(redisClient
*c
);
407 static void lpushCommand(redisClient
*c
);
408 static void rpushCommand(redisClient
*c
);
409 static void lpopCommand(redisClient
*c
);
410 static void rpopCommand(redisClient
*c
);
411 static void llenCommand(redisClient
*c
);
412 static void lindexCommand(redisClient
*c
);
413 static void lrangeCommand(redisClient
*c
);
414 static void ltrimCommand(redisClient
*c
);
415 static void typeCommand(redisClient
*c
);
416 static void lsetCommand(redisClient
*c
);
417 static void saddCommand(redisClient
*c
);
418 static void sremCommand(redisClient
*c
);
419 static void smoveCommand(redisClient
*c
);
420 static void sismemberCommand(redisClient
*c
);
421 static void scardCommand(redisClient
*c
);
422 static void spopCommand(redisClient
*c
);
423 static void srandmemberCommand(redisClient
*c
);
424 static void sinterCommand(redisClient
*c
);
425 static void sinterstoreCommand(redisClient
*c
);
426 static void sunionCommand(redisClient
*c
);
427 static void sunionstoreCommand(redisClient
*c
);
428 static void sdiffCommand(redisClient
*c
);
429 static void sdiffstoreCommand(redisClient
*c
);
430 static void syncCommand(redisClient
*c
);
431 static void flushdbCommand(redisClient
*c
);
432 static void flushallCommand(redisClient
*c
);
433 static void sortCommand(redisClient
*c
);
434 static void lremCommand(redisClient
*c
);
435 static void infoCommand(redisClient
*c
);
436 static void mgetCommand(redisClient
*c
);
437 static void monitorCommand(redisClient
*c
);
438 static void expireCommand(redisClient
*c
);
439 static void getsetCommand(redisClient
*c
);
440 static void ttlCommand(redisClient
*c
);
441 static void slaveofCommand(redisClient
*c
);
442 static void debugCommand(redisClient
*c
);
443 static void msetCommand(redisClient
*c
);
444 static void msetnxCommand(redisClient
*c
);
445 static void zaddCommand(redisClient
*c
);
446 static void zrangeCommand(redisClient
*c
);
447 static void zrevrangeCommand(redisClient
*c
);
448 static void zlenCommand(redisClient
*c
);
449 static void zremCommand(redisClient
*c
);
451 /*================================= Globals ================================= */
454 static struct redisServer server
; /* server global state */
455 static struct redisCommand cmdTable
[] = {
456 {"get",getCommand
,2,REDIS_CMD_INLINE
},
457 {"set",setCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
458 {"setnx",setnxCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
459 {"del",delCommand
,-2,REDIS_CMD_INLINE
},
460 {"exists",existsCommand
,2,REDIS_CMD_INLINE
},
461 {"incr",incrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
462 {"decr",decrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
463 {"mget",mgetCommand
,-2,REDIS_CMD_INLINE
},
464 {"rpush",rpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
465 {"lpush",lpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
466 {"rpop",rpopCommand
,2,REDIS_CMD_INLINE
},
467 {"lpop",lpopCommand
,2,REDIS_CMD_INLINE
},
468 {"llen",llenCommand
,2,REDIS_CMD_INLINE
},
469 {"lindex",lindexCommand
,3,REDIS_CMD_INLINE
},
470 {"lset",lsetCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
471 {"lrange",lrangeCommand
,4,REDIS_CMD_INLINE
},
472 {"ltrim",ltrimCommand
,4,REDIS_CMD_INLINE
},
473 {"lrem",lremCommand
,4,REDIS_CMD_BULK
},
474 {"sadd",saddCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
475 {"srem",sremCommand
,3,REDIS_CMD_BULK
},
476 {"smove",smoveCommand
,4,REDIS_CMD_BULK
},
477 {"sismember",sismemberCommand
,3,REDIS_CMD_BULK
},
478 {"scard",scardCommand
,2,REDIS_CMD_INLINE
},
479 {"spop",spopCommand
,2,REDIS_CMD_INLINE
},
480 {"srandmember",srandmemberCommand
,2,REDIS_CMD_INLINE
},
481 {"sinter",sinterCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
482 {"sinterstore",sinterstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
483 {"sunion",sunionCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
484 {"sunionstore",sunionstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
485 {"sdiff",sdiffCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
486 {"sdiffstore",sdiffstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
487 {"smembers",sinterCommand
,2,REDIS_CMD_INLINE
},
488 {"zadd",zaddCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
489 {"zrem",zremCommand
,3,REDIS_CMD_BULK
},
490 {"zrange",zrangeCommand
,4,REDIS_CMD_INLINE
},
491 {"zrevrange",zrevrangeCommand
,4,REDIS_CMD_INLINE
},
492 {"zlen",zlenCommand
,2,REDIS_CMD_INLINE
},
493 {"incrby",incrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
494 {"decrby",decrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
495 {"getset",getsetCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
496 {"mset",msetCommand
,-3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
497 {"msetnx",msetnxCommand
,-3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
498 {"randomkey",randomkeyCommand
,1,REDIS_CMD_INLINE
},
499 {"select",selectCommand
,2,REDIS_CMD_INLINE
},
500 {"move",moveCommand
,3,REDIS_CMD_INLINE
},
501 {"rename",renameCommand
,3,REDIS_CMD_INLINE
},
502 {"renamenx",renamenxCommand
,3,REDIS_CMD_INLINE
},
503 {"expire",expireCommand
,3,REDIS_CMD_INLINE
},
504 {"keys",keysCommand
,2,REDIS_CMD_INLINE
},
505 {"dbsize",dbsizeCommand
,1,REDIS_CMD_INLINE
},
506 {"auth",authCommand
,2,REDIS_CMD_INLINE
},
507 {"ping",pingCommand
,1,REDIS_CMD_INLINE
},
508 {"echo",echoCommand
,2,REDIS_CMD_BULK
},
509 {"save",saveCommand
,1,REDIS_CMD_INLINE
},
510 {"bgsave",bgsaveCommand
,1,REDIS_CMD_INLINE
},
511 {"shutdown",shutdownCommand
,1,REDIS_CMD_INLINE
},
512 {"lastsave",lastsaveCommand
,1,REDIS_CMD_INLINE
},
513 {"type",typeCommand
,2,REDIS_CMD_INLINE
},
514 {"sync",syncCommand
,1,REDIS_CMD_INLINE
},
515 {"flushdb",flushdbCommand
,1,REDIS_CMD_INLINE
},
516 {"flushall",flushallCommand
,1,REDIS_CMD_INLINE
},
517 {"sort",sortCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
518 {"info",infoCommand
,1,REDIS_CMD_INLINE
},
519 {"monitor",monitorCommand
,1,REDIS_CMD_INLINE
},
520 {"ttl",ttlCommand
,2,REDIS_CMD_INLINE
},
521 {"slaveof",slaveofCommand
,3,REDIS_CMD_INLINE
},
522 {"debug",debugCommand
,-2,REDIS_CMD_INLINE
},
525 /*============================ Utility functions ============================ */
527 /* Glob-style pattern matching. */
528 int stringmatchlen(const char *pattern
, int patternLen
,
529 const char *string
, int stringLen
, int nocase
)
534 while (pattern
[1] == '*') {
539 return 1; /* match */
541 if (stringmatchlen(pattern
+1, patternLen
-1,
542 string
, stringLen
, nocase
))
543 return 1; /* match */
547 return 0; /* no match */
551 return 0; /* no match */
561 not = pattern
[0] == '^';
568 if (pattern
[0] == '\\') {
571 if (pattern
[0] == string
[0])
573 } else if (pattern
[0] == ']') {
575 } else if (patternLen
== 0) {
579 } else if (pattern
[1] == '-' && patternLen
>= 3) {
580 int start
= pattern
[0];
581 int end
= pattern
[2];
589 start
= tolower(start
);
595 if (c
>= start
&& c
<= end
)
599 if (pattern
[0] == string
[0])
602 if (tolower((int)pattern
[0]) == tolower((int)string
[0]))
612 return 0; /* no match */
618 if (patternLen
>= 2) {
625 if (pattern
[0] != string
[0])
626 return 0; /* no match */
628 if (tolower((int)pattern
[0]) != tolower((int)string
[0]))
629 return 0; /* no match */
637 if (stringLen
== 0) {
638 while(*pattern
== '*') {
645 if (patternLen
== 0 && stringLen
== 0)
650 static void redisLog(int level
, const char *fmt
, ...) {
654 fp
= (server
.logfile
== NULL
) ? stdout
: fopen(server
.logfile
,"a");
658 if (level
>= server
.verbosity
) {
664 strftime(buf
,64,"%d %b %H:%M:%S",gmtime(&now
));
665 fprintf(fp
,"%s %c ",buf
,c
[level
]);
666 vfprintf(fp
, fmt
, ap
);
672 if (server
.logfile
) fclose(fp
);
675 /*====================== Hash table type implementation ==================== */
677 /* This is an hash table type that uses the SDS dynamic strings libary as
678 * keys and radis objects as values (objects can hold SDS strings,
681 static void dictVanillaFree(void *privdata
, void *val
)
683 DICT_NOTUSED(privdata
);
687 static int sdsDictKeyCompare(void *privdata
, const void *key1
,
691 DICT_NOTUSED(privdata
);
693 l1
= sdslen((sds
)key1
);
694 l2
= sdslen((sds
)key2
);
695 if (l1
!= l2
) return 0;
696 return memcmp(key1
, key2
, l1
) == 0;
699 static void dictRedisObjectDestructor(void *privdata
, void *val
)
701 DICT_NOTUSED(privdata
);
706 static int dictObjKeyCompare(void *privdata
, const void *key1
,
709 const robj
*o1
= key1
, *o2
= key2
;
710 return sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
713 static unsigned int dictObjHash(const void *key
) {
715 return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
718 static int dictEncObjKeyCompare(void *privdata
, const void *key1
,
721 const robj
*o1
= key1
, *o2
= key2
;
723 if (o1
->encoding
== REDIS_ENCODING_RAW
&&
724 o2
->encoding
== REDIS_ENCODING_RAW
)
725 return sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
730 dec1
= o1
->encoding
!= REDIS_ENCODING_RAW
?
731 getDecodedObject(o1
) : (robj
*)o1
;
732 dec2
= o2
->encoding
!= REDIS_ENCODING_RAW
?
733 getDecodedObject(o2
) : (robj
*)o2
;
734 cmp
= sdsDictKeyCompare(privdata
,dec1
->ptr
,dec2
->ptr
);
735 if (dec1
!= o1
) decrRefCount(dec1
);
736 if (dec2
!= o2
) decrRefCount(dec2
);
741 static unsigned int dictEncObjHash(const void *key
) {
744 if (o
->encoding
== REDIS_ENCODING_RAW
)
745 return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
747 robj
*dec
= getDecodedObject(o
);
748 unsigned int hash
= dictGenHashFunction(dec
->ptr
, sdslen((sds
)dec
->ptr
));
754 static dictType setDictType
= {
755 dictEncObjHash
, /* hash function */
758 dictEncObjKeyCompare
, /* key compare */
759 dictRedisObjectDestructor
, /* key destructor */
760 NULL
/* val destructor */
763 static dictType zsetDictType
= {
764 dictEncObjHash
, /* hash function */
767 dictEncObjKeyCompare
, /* key compare */
768 dictRedisObjectDestructor
, /* key destructor */
769 dictVanillaFree
/* val destructor */
772 static dictType hashDictType
= {
773 dictObjHash
, /* hash function */
776 dictObjKeyCompare
, /* key compare */
777 dictRedisObjectDestructor
, /* key destructor */
778 dictRedisObjectDestructor
/* val destructor */
781 /* ========================= Random utility functions ======================= */
783 /* Redis generally does not try to recover from out of memory conditions
784 * when allocating objects or strings, it is not clear if it will be possible
785 * to report this condition to the client since the networking layer itself
786 * is based on heap allocation for send buffers, so we simply abort.
787 * At least the code will be simpler to read... */
788 static void oom(const char *msg
) {
789 fprintf(stderr
, "%s: Out of memory\n",msg
);
795 /* ====================== Redis server networking stuff ===================== */
796 static void closeTimedoutClients(void) {
799 time_t now
= time(NULL
);
801 listRewind(server
.clients
);
802 while ((ln
= listYield(server
.clients
)) != NULL
) {
803 c
= listNodeValue(ln
);
804 if (!(c
->flags
& REDIS_SLAVE
) && /* no timeout for slaves */
805 !(c
->flags
& REDIS_MASTER
) && /* no timeout for masters */
806 (now
- c
->lastinteraction
> server
.maxidletime
)) {
807 redisLog(REDIS_DEBUG
,"Closing idle client");
813 static int htNeedsResize(dict
*dict
) {
814 long long size
, used
;
816 size
= dictSlots(dict
);
817 used
= dictSize(dict
);
818 return (size
&& used
&& size
> DICT_HT_INITIAL_SIZE
&&
819 (used
*100/size
< REDIS_HT_MINFILL
));
822 /* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
823 * we resize the hash table to save memory */
824 static void tryResizeHashTables(void) {
827 for (j
= 0; j
< server
.dbnum
; j
++) {
828 if (htNeedsResize(server
.db
[j
].dict
)) {
829 redisLog(REDIS_DEBUG
,"The hash table %d is too sparse, resize it...",j
);
830 dictResize(server
.db
[j
].dict
);
831 redisLog(REDIS_DEBUG
,"Hash table %d resized.",j
);
833 if (htNeedsResize(server
.db
[j
].expires
))
834 dictResize(server
.db
[j
].expires
);
838 static int serverCron(struct aeEventLoop
*eventLoop
, long long id
, void *clientData
) {
839 int j
, loops
= server
.cronloops
++;
840 REDIS_NOTUSED(eventLoop
);
842 REDIS_NOTUSED(clientData
);
844 /* Update the global state with the amount of used memory */
845 server
.usedmemory
= zmalloc_used_memory();
847 /* Show some info about non-empty databases */
848 for (j
= 0; j
< server
.dbnum
; j
++) {
849 long long size
, used
, vkeys
;
851 size
= dictSlots(server
.db
[j
].dict
);
852 used
= dictSize(server
.db
[j
].dict
);
853 vkeys
= dictSize(server
.db
[j
].expires
);
854 if (!(loops
% 5) && (used
|| vkeys
)) {
855 redisLog(REDIS_DEBUG
,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j
,used
,vkeys
,size
);
856 /* dictPrintStats(server.dict); */
860 /* We don't want to resize the hash tables while a bacground saving
861 * is in progress: the saving child is created using fork() that is
862 * implemented with a copy-on-write semantic in most modern systems, so
863 * if we resize the HT while there is the saving child at work actually
864 * a lot of memory movements in the parent will cause a lot of pages
866 if (!server
.bgsaveinprogress
) tryResizeHashTables();
868 /* Show information about connected clients */
870 redisLog(REDIS_DEBUG
,"%d clients connected (%d slaves), %zu bytes in use, %d shared objects",
871 listLength(server
.clients
)-listLength(server
.slaves
),
872 listLength(server
.slaves
),
874 dictSize(server
.sharingpool
));
877 /* Close connections of timedout clients */
878 if (server
.maxidletime
&& !(loops
% 10))
879 closeTimedoutClients();
881 /* Check if a background saving in progress terminated */
882 if (server
.bgsaveinprogress
) {
884 if (wait4(-1,&statloc
,WNOHANG
,NULL
)) {
885 int exitcode
= WEXITSTATUS(statloc
);
886 int bysignal
= WIFSIGNALED(statloc
);
888 if (!bysignal
&& exitcode
== 0) {
889 redisLog(REDIS_NOTICE
,
890 "Background saving terminated with success");
892 server
.lastsave
= time(NULL
);
893 } else if (!bysignal
&& exitcode
!= 0) {
894 redisLog(REDIS_WARNING
, "Background saving error");
896 redisLog(REDIS_WARNING
,
897 "Background saving terminated by signal");
898 rdbRemoveTempFile(server
.bgsavechildpid
);
900 server
.bgsaveinprogress
= 0;
901 server
.bgsavechildpid
= -1;
902 updateSlavesWaitingBgsave(exitcode
== 0 ? REDIS_OK
: REDIS_ERR
);
905 /* If there is not a background saving in progress check if
906 * we have to save now */
907 time_t now
= time(NULL
);
908 for (j
= 0; j
< server
.saveparamslen
; j
++) {
909 struct saveparam
*sp
= server
.saveparams
+j
;
911 if (server
.dirty
>= sp
->changes
&&
912 now
-server
.lastsave
> sp
->seconds
) {
913 redisLog(REDIS_NOTICE
,"%d changes in %d seconds. Saving...",
914 sp
->changes
, sp
->seconds
);
915 rdbSaveBackground(server
.dbfilename
);
921 /* Try to expire a few timed out keys */
922 for (j
= 0; j
< server
.dbnum
; j
++) {
923 redisDb
*db
= server
.db
+j
;
924 int num
= dictSize(db
->expires
);
927 time_t now
= time(NULL
);
929 if (num
> REDIS_EXPIRELOOKUPS_PER_CRON
)
930 num
= REDIS_EXPIRELOOKUPS_PER_CRON
;
935 if ((de
= dictGetRandomKey(db
->expires
)) == NULL
) break;
936 t
= (time_t) dictGetEntryVal(de
);
938 deleteKey(db
,dictGetEntryKey(de
));
944 /* Check if we should connect to a MASTER */
945 if (server
.replstate
== REDIS_REPL_CONNECT
) {
946 redisLog(REDIS_NOTICE
,"Connecting to MASTER...");
947 if (syncWithMaster() == REDIS_OK
) {
948 redisLog(REDIS_NOTICE
,"MASTER <-> SLAVE sync succeeded");
954 static void createSharedObjects(void) {
955 shared
.crlf
= createObject(REDIS_STRING
,sdsnew("\r\n"));
956 shared
.ok
= createObject(REDIS_STRING
,sdsnew("+OK\r\n"));
957 shared
.err
= createObject(REDIS_STRING
,sdsnew("-ERR\r\n"));
958 shared
.emptybulk
= createObject(REDIS_STRING
,sdsnew("$0\r\n\r\n"));
959 shared
.czero
= createObject(REDIS_STRING
,sdsnew(":0\r\n"));
960 shared
.cone
= createObject(REDIS_STRING
,sdsnew(":1\r\n"));
961 shared
.nullbulk
= createObject(REDIS_STRING
,sdsnew("$-1\r\n"));
962 shared
.nullmultibulk
= createObject(REDIS_STRING
,sdsnew("*-1\r\n"));
963 shared
.emptymultibulk
= createObject(REDIS_STRING
,sdsnew("*0\r\n"));
965 shared
.pong
= createObject(REDIS_STRING
,sdsnew("+PONG\r\n"));
966 shared
.wrongtypeerr
= createObject(REDIS_STRING
,sdsnew(
967 "-ERR Operation against a key holding the wrong kind of value\r\n"));
968 shared
.nokeyerr
= createObject(REDIS_STRING
,sdsnew(
969 "-ERR no such key\r\n"));
970 shared
.syntaxerr
= createObject(REDIS_STRING
,sdsnew(
971 "-ERR syntax error\r\n"));
972 shared
.sameobjecterr
= createObject(REDIS_STRING
,sdsnew(
973 "-ERR source and destination objects are the same\r\n"));
974 shared
.outofrangeerr
= createObject(REDIS_STRING
,sdsnew(
975 "-ERR index out of range\r\n"));
976 shared
.space
= createObject(REDIS_STRING
,sdsnew(" "));
977 shared
.colon
= createObject(REDIS_STRING
,sdsnew(":"));
978 shared
.plus
= createObject(REDIS_STRING
,sdsnew("+"));
979 shared
.select0
= createStringObject("select 0\r\n",10);
980 shared
.select1
= createStringObject("select 1\r\n",10);
981 shared
.select2
= createStringObject("select 2\r\n",10);
982 shared
.select3
= createStringObject("select 3\r\n",10);
983 shared
.select4
= createStringObject("select 4\r\n",10);
984 shared
.select5
= createStringObject("select 5\r\n",10);
985 shared
.select6
= createStringObject("select 6\r\n",10);
986 shared
.select7
= createStringObject("select 7\r\n",10);
987 shared
.select8
= createStringObject("select 8\r\n",10);
988 shared
.select9
= createStringObject("select 9\r\n",10);
991 static void appendServerSaveParams(time_t seconds
, int changes
) {
992 server
.saveparams
= zrealloc(server
.saveparams
,sizeof(struct saveparam
)*(server
.saveparamslen
+1));
993 server
.saveparams
[server
.saveparamslen
].seconds
= seconds
;
994 server
.saveparams
[server
.saveparamslen
].changes
= changes
;
995 server
.saveparamslen
++;
998 static void ResetServerSaveParams() {
999 zfree(server
.saveparams
);
1000 server
.saveparams
= NULL
;
1001 server
.saveparamslen
= 0;
1004 static void initServerConfig() {
1005 server
.dbnum
= REDIS_DEFAULT_DBNUM
;
1006 server
.port
= REDIS_SERVERPORT
;
1007 server
.verbosity
= REDIS_DEBUG
;
1008 server
.maxidletime
= REDIS_MAXIDLETIME
;
1009 server
.saveparams
= NULL
;
1010 server
.logfile
= NULL
; /* NULL = log on standard output */
1011 server
.bindaddr
= NULL
;
1012 server
.glueoutputbuf
= 1;
1013 server
.daemonize
= 0;
1014 server
.pidfile
= "/var/run/redis.pid";
1015 server
.dbfilename
= "dump.rdb";
1016 server
.requirepass
= NULL
;
1017 server
.shareobjects
= 0;
1018 server
.sharingpoolsize
= 1024;
1019 server
.maxclients
= 0;
1020 server
.maxmemory
= 0;
1021 ResetServerSaveParams();
1023 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
1024 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
1025 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1026 /* Replication related */
1028 server
.masterhost
= NULL
;
1029 server
.masterport
= 6379;
1030 server
.master
= NULL
;
1031 server
.replstate
= REDIS_REPL_NONE
;
1033 /* Double constants initialization */
1035 R_PosInf
= 1.0/R_Zero
;
1036 R_NegInf
= -1.0/R_Zero
;
1037 R_Nan
= R_Zero
/R_Zero
;
1040 static void initServer() {
1043 signal(SIGHUP
, SIG_IGN
);
1044 signal(SIGPIPE
, SIG_IGN
);
1045 setupSigSegvAction();
1047 server
.clients
= listCreate();
1048 server
.slaves
= listCreate();
1049 server
.monitors
= listCreate();
1050 server
.objfreelist
= listCreate();
1051 createSharedObjects();
1052 server
.el
= aeCreateEventLoop();
1053 server
.db
= zmalloc(sizeof(redisDb
)*server
.dbnum
);
1054 server
.sharingpool
= dictCreate(&setDictType
,NULL
);
1055 server
.fd
= anetTcpServer(server
.neterr
, server
.port
, server
.bindaddr
);
1056 if (server
.fd
== -1) {
1057 redisLog(REDIS_WARNING
, "Opening TCP port: %s", server
.neterr
);
1060 for (j
= 0; j
< server
.dbnum
; j
++) {
1061 server
.db
[j
].dict
= dictCreate(&hashDictType
,NULL
);
1062 server
.db
[j
].expires
= dictCreate(&setDictType
,NULL
);
1063 server
.db
[j
].id
= j
;
1065 server
.cronloops
= 0;
1066 server
.bgsaveinprogress
= 0;
1067 server
.bgsavechildpid
= -1;
1068 server
.lastsave
= time(NULL
);
1070 server
.usedmemory
= 0;
1071 server
.stat_numcommands
= 0;
1072 server
.stat_numconnections
= 0;
1073 server
.stat_starttime
= time(NULL
);
1074 aeCreateTimeEvent(server
.el
, 1000, serverCron
, NULL
, NULL
);
1077 /* Empty the whole database */
1078 static long long emptyDb() {
1080 long long removed
= 0;
1082 for (j
= 0; j
< server
.dbnum
; j
++) {
1083 removed
+= dictSize(server
.db
[j
].dict
);
1084 dictEmpty(server
.db
[j
].dict
);
1085 dictEmpty(server
.db
[j
].expires
);
1090 static int yesnotoi(char *s
) {
1091 if (!strcasecmp(s
,"yes")) return 1;
1092 else if (!strcasecmp(s
,"no")) return 0;
1096 /* I agree, this is a very rudimental way to load a configuration...
1097 will improve later if the config gets more complex */
1098 static void loadServerConfig(char *filename
) {
1100 char buf
[REDIS_CONFIGLINE_MAX
+1], *err
= NULL
;
1104 if (filename
[0] == '-' && filename
[1] == '\0')
1107 if ((fp
= fopen(filename
,"r")) == NULL
) {
1108 redisLog(REDIS_WARNING
,"Fatal error, can't open config file");
1113 while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) {
1119 line
= sdstrim(line
," \t\r\n");
1121 /* Skip comments and blank lines*/
1122 if (line
[0] == '#' || line
[0] == '\0') {
1127 /* Split into arguments */
1128 argv
= sdssplitlen(line
,sdslen(line
)," ",1,&argc
);
1129 sdstolower(argv
[0]);
1131 /* Execute config directives */
1132 if (!strcasecmp(argv
[0],"timeout") && argc
== 2) {
1133 server
.maxidletime
= atoi(argv
[1]);
1134 if (server
.maxidletime
< 0) {
1135 err
= "Invalid timeout value"; goto loaderr
;
1137 } else if (!strcasecmp(argv
[0],"port") && argc
== 2) {
1138 server
.port
= atoi(argv
[1]);
1139 if (server
.port
< 1 || server
.port
> 65535) {
1140 err
= "Invalid port"; goto loaderr
;
1142 } else if (!strcasecmp(argv
[0],"bind") && argc
== 2) {
1143 server
.bindaddr
= zstrdup(argv
[1]);
1144 } else if (!strcasecmp(argv
[0],"save") && argc
== 3) {
1145 int seconds
= atoi(argv
[1]);
1146 int changes
= atoi(argv
[2]);
1147 if (seconds
< 1 || changes
< 0) {
1148 err
= "Invalid save parameters"; goto loaderr
;
1150 appendServerSaveParams(seconds
,changes
);
1151 } else if (!strcasecmp(argv
[0],"dir") && argc
== 2) {
1152 if (chdir(argv
[1]) == -1) {
1153 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s",
1154 argv
[1], strerror(errno
));
1157 } else if (!strcasecmp(argv
[0],"loglevel") && argc
== 2) {
1158 if (!strcasecmp(argv
[1],"debug")) server
.verbosity
= REDIS_DEBUG
;
1159 else if (!strcasecmp(argv
[1],"notice")) server
.verbosity
= REDIS_NOTICE
;
1160 else if (!strcasecmp(argv
[1],"warning")) server
.verbosity
= REDIS_WARNING
;
1162 err
= "Invalid log level. Must be one of debug, notice, warning";
1165 } else if (!strcasecmp(argv
[0],"logfile") && argc
== 2) {
1168 server
.logfile
= zstrdup(argv
[1]);
1169 if (!strcasecmp(server
.logfile
,"stdout")) {
1170 zfree(server
.logfile
);
1171 server
.logfile
= NULL
;
1173 if (server
.logfile
) {
1174 /* Test if we are able to open the file. The server will not
1175 * be able to abort just for this problem later... */
1176 logfp
= fopen(server
.logfile
,"a");
1177 if (logfp
== NULL
) {
1178 err
= sdscatprintf(sdsempty(),
1179 "Can't open the log file: %s", strerror(errno
));
1184 } else if (!strcasecmp(argv
[0],"databases") && argc
== 2) {
1185 server
.dbnum
= atoi(argv
[1]);
1186 if (server
.dbnum
< 1) {
1187 err
= "Invalid number of databases"; goto loaderr
;
1189 } else if (!strcasecmp(argv
[0],"maxclients") && argc
== 2) {
1190 server
.maxclients
= atoi(argv
[1]);
1191 } else if (!strcasecmp(argv
[0],"maxmemory") && argc
== 2) {
1192 server
.maxmemory
= strtoll(argv
[1], NULL
, 10);
1193 } else if (!strcasecmp(argv
[0],"slaveof") && argc
== 3) {
1194 server
.masterhost
= sdsnew(argv
[1]);
1195 server
.masterport
= atoi(argv
[2]);
1196 server
.replstate
= REDIS_REPL_CONNECT
;
1197 } else if (!strcasecmp(argv
[0],"glueoutputbuf") && argc
== 2) {
1198 if ((server
.glueoutputbuf
= yesnotoi(argv
[1])) == -1) {
1199 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1201 } else if (!strcasecmp(argv
[0],"shareobjects") && argc
== 2) {
1202 if ((server
.shareobjects
= yesnotoi(argv
[1])) == -1) {
1203 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1205 } else if (!strcasecmp(argv
[0],"shareobjectspoolsize") && argc
== 2) {
1206 server
.sharingpoolsize
= atoi(argv
[1]);
1207 if (server
.sharingpoolsize
< 1) {
1208 err
= "invalid object sharing pool size"; goto loaderr
;
1210 } else if (!strcasecmp(argv
[0],"daemonize") && argc
== 2) {
1211 if ((server
.daemonize
= yesnotoi(argv
[1])) == -1) {
1212 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1214 } else if (!strcasecmp(argv
[0],"requirepass") && argc
== 2) {
1215 server
.requirepass
= zstrdup(argv
[1]);
1216 } else if (!strcasecmp(argv
[0],"pidfile") && argc
== 2) {
1217 server
.pidfile
= zstrdup(argv
[1]);
1218 } else if (!strcasecmp(argv
[0],"dbfilename") && argc
== 2) {
1219 server
.dbfilename
= zstrdup(argv
[1]);
1221 err
= "Bad directive or wrong number of arguments"; goto loaderr
;
1223 for (j
= 0; j
< argc
; j
++)
1228 if (fp
!= stdin
) fclose(fp
);
1232 fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n");
1233 fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
);
1234 fprintf(stderr
, ">>> '%s'\n", line
);
1235 fprintf(stderr
, "%s\n", err
);
1239 static void freeClientArgv(redisClient
*c
) {
1242 for (j
= 0; j
< c
->argc
; j
++)
1243 decrRefCount(c
->argv
[j
]);
1244 for (j
= 0; j
< c
->mbargc
; j
++)
1245 decrRefCount(c
->mbargv
[j
]);
1250 static void freeClient(redisClient
*c
) {
1253 aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
);
1254 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1255 sdsfree(c
->querybuf
);
1256 listRelease(c
->reply
);
1259 ln
= listSearchKey(server
.clients
,c
);
1261 listDelNode(server
.clients
,ln
);
1262 if (c
->flags
& REDIS_SLAVE
) {
1263 if (c
->replstate
== REDIS_REPL_SEND_BULK
&& c
->repldbfd
!= -1)
1265 list
*l
= (c
->flags
& REDIS_MONITOR
) ? server
.monitors
: server
.slaves
;
1266 ln
= listSearchKey(l
,c
);
1270 if (c
->flags
& REDIS_MASTER
) {
1271 server
.master
= NULL
;
1272 server
.replstate
= REDIS_REPL_CONNECT
;
1279 static void glueReplyBuffersIfNeeded(redisClient
*c
) {
1284 listRewind(c
->reply
);
1285 while((ln
= listYield(c
->reply
))) {
1287 totlen
+= sdslen(o
->ptr
);
1288 /* This optimization makes more sense if we don't have to copy
1290 if (totlen
> 1024) return;
1296 listRewind(c
->reply
);
1297 while((ln
= listYield(c
->reply
))) {
1299 memcpy(buf
+copylen
,o
->ptr
,sdslen(o
->ptr
));
1300 copylen
+= sdslen(o
->ptr
);
1301 listDelNode(c
->reply
,ln
);
1303 /* Now the output buffer is empty, add the new single element */
1304 o
= createObject(REDIS_STRING
,sdsnewlen(buf
,totlen
));
1305 listAddNodeTail(c
->reply
,o
);
1309 static void sendReplyToClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1310 redisClient
*c
= privdata
;
1311 int nwritten
= 0, totwritten
= 0, objlen
;
1314 REDIS_NOTUSED(mask
);
1316 if (server
.glueoutputbuf
&& listLength(c
->reply
) > 1)
1317 glueReplyBuffersIfNeeded(c
);
1318 while(listLength(c
->reply
)) {
1319 o
= listNodeValue(listFirst(c
->reply
));
1320 objlen
= sdslen(o
->ptr
);
1323 listDelNode(c
->reply
,listFirst(c
->reply
));
1327 if (c
->flags
& REDIS_MASTER
) {
1328 /* Don't reply to a master */
1329 nwritten
= objlen
- c
->sentlen
;
1331 nwritten
= write(fd
, ((char*)o
->ptr
)+c
->sentlen
, objlen
- c
->sentlen
);
1332 if (nwritten
<= 0) break;
1334 c
->sentlen
+= nwritten
;
1335 totwritten
+= nwritten
;
1336 /* If we fully sent the object on head go to the next one */
1337 if (c
->sentlen
== objlen
) {
1338 listDelNode(c
->reply
,listFirst(c
->reply
));
1341 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
1342 * bytes, in a single threaded server it's a good idea to server
1343 * other clients as well, even if a very large request comes from
1344 * super fast link that is always able to accept data (in real world
1345 * terms think to 'KEYS *' against the loopback interfae) */
1346 if (totwritten
> REDIS_MAX_WRITE_PER_EVENT
) break;
1348 if (nwritten
== -1) {
1349 if (errno
== EAGAIN
) {
1352 redisLog(REDIS_DEBUG
,
1353 "Error writing to client: %s", strerror(errno
));
1358 if (totwritten
> 0) c
->lastinteraction
= time(NULL
);
1359 if (listLength(c
->reply
) == 0) {
1361 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1365 static struct redisCommand
*lookupCommand(char *name
) {
1367 while(cmdTable
[j
].name
!= NULL
) {
1368 if (!strcasecmp(name
,cmdTable
[j
].name
)) return &cmdTable
[j
];
1374 /* resetClient prepare the client to process the next command */
1375 static void resetClient(redisClient
*c
) {
1381 /* If this function gets called we already read a whole
1382 * command, argments are in the client argv/argc fields.
1383 * processCommand() execute the command or prepare the
1384 * server for a bulk read from the client.
1386 * If 1 is returned the client is still alive and valid and
1387 * and other operations can be performed by the caller. Otherwise
1388 * if 0 is returned the client was destroied (i.e. after QUIT). */
1389 static int processCommand(redisClient
*c
) {
1390 struct redisCommand
*cmd
;
1393 /* Free some memory if needed (maxmemory setting) */
1394 if (server
.maxmemory
) freeMemoryIfNeeded();
1396 /* Handle the multi bulk command type. This is an alternative protocol
1397 * supported by Redis in order to receive commands that are composed of
1398 * multiple binary-safe "bulk" arguments. The latency of processing is
1399 * a bit higher but this allows things like multi-sets, so if this
1400 * protocol is used only for MSET and similar commands this is a big win. */
1401 if (c
->multibulk
== 0 && c
->argc
== 1 && ((char*)(c
->argv
[0]->ptr
))[0] == '*') {
1402 c
->multibulk
= atoi(((char*)c
->argv
[0]->ptr
)+1);
1403 if (c
->multibulk
<= 0) {
1407 decrRefCount(c
->argv
[c
->argc
-1]);
1411 } else if (c
->multibulk
) {
1412 if (c
->bulklen
== -1) {
1413 if (((char*)c
->argv
[0]->ptr
)[0] != '$') {
1414 addReplySds(c
,sdsnew("-ERR multi bulk protocol error\r\n"));
1418 int bulklen
= atoi(((char*)c
->argv
[0]->ptr
)+1);
1419 decrRefCount(c
->argv
[0]);
1420 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
1422 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
1427 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
1431 c
->mbargv
= zrealloc(c
->mbargv
,(sizeof(robj
*))*(c
->mbargc
+1));
1432 c
->mbargv
[c
->mbargc
] = c
->argv
[0];
1436 if (c
->multibulk
== 0) {
1440 /* Here we need to swap the multi-bulk argc/argv with the
1441 * normal argc/argv of the client structure. */
1443 c
->argv
= c
->mbargv
;
1444 c
->mbargv
= auxargv
;
1447 c
->argc
= c
->mbargc
;
1448 c
->mbargc
= auxargc
;
1450 /* We need to set bulklen to something different than -1
1451 * in order for the code below to process the command without
1452 * to try to read the last argument of a bulk command as
1453 * a special argument. */
1455 /* continue below and process the command */
1462 /* -- end of multi bulk commands processing -- */
1464 /* The QUIT command is handled as a special case. Normal command
1465 * procs are unable to close the client connection safely */
1466 if (!strcasecmp(c
->argv
[0]->ptr
,"quit")) {
1470 cmd
= lookupCommand(c
->argv
[0]->ptr
);
1472 addReplySds(c
,sdsnew("-ERR unknown command\r\n"));
1475 } else if ((cmd
->arity
> 0 && cmd
->arity
!= c
->argc
) ||
1476 (c
->argc
< -cmd
->arity
)) {
1477 addReplySds(c
,sdsnew("-ERR wrong number of arguments\r\n"));
1480 } else if (server
.maxmemory
&& cmd
->flags
& REDIS_CMD_DENYOOM
&& zmalloc_used_memory() > server
.maxmemory
) {
1481 addReplySds(c
,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
1484 } else if (cmd
->flags
& REDIS_CMD_BULK
&& c
->bulklen
== -1) {
1485 int bulklen
= atoi(c
->argv
[c
->argc
-1]->ptr
);
1487 decrRefCount(c
->argv
[c
->argc
-1]);
1488 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
1490 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
1495 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
1496 /* It is possible that the bulk read is already in the
1497 * buffer. Check this condition and handle it accordingly.
1498 * This is just a fast path, alternative to call processInputBuffer().
1499 * It's a good idea since the code is small and this condition
1500 * happens most of the times. */
1501 if ((signed)sdslen(c
->querybuf
) >= c
->bulklen
) {
1502 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
1504 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
1509 /* Let's try to share objects on the command arguments vector */
1510 if (server
.shareobjects
) {
1512 for(j
= 1; j
< c
->argc
; j
++)
1513 c
->argv
[j
] = tryObjectSharing(c
->argv
[j
]);
1515 /* Let's try to encode the bulk object to save space. */
1516 if (cmd
->flags
& REDIS_CMD_BULK
)
1517 tryObjectEncoding(c
->argv
[c
->argc
-1]);
1519 /* Check if the user is authenticated */
1520 if (server
.requirepass
&& !c
->authenticated
&& cmd
->proc
!= authCommand
) {
1521 addReplySds(c
,sdsnew("-ERR operation not permitted\r\n"));
1526 /* Exec the command */
1527 dirty
= server
.dirty
;
1529 if (server
.dirty
-dirty
!= 0 && listLength(server
.slaves
))
1530 replicationFeedSlaves(server
.slaves
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1531 if (listLength(server
.monitors
))
1532 replicationFeedSlaves(server
.monitors
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1533 server
.stat_numcommands
++;
1535 /* Prepare the client for the next command */
1536 if (c
->flags
& REDIS_CLOSE
) {
1544 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
) {
1548 /* (args*2)+1 is enough room for args, spaces, newlines */
1549 robj
*static_outv
[REDIS_STATIC_ARGS
*2+1];
1551 if (argc
<= REDIS_STATIC_ARGS
) {
1554 outv
= zmalloc(sizeof(robj
*)*(argc
*2+1));
1557 for (j
= 0; j
< argc
; j
++) {
1558 if (j
!= 0) outv
[outc
++] = shared
.space
;
1559 if ((cmd
->flags
& REDIS_CMD_BULK
) && j
== argc
-1) {
1562 lenobj
= createObject(REDIS_STRING
,
1563 sdscatprintf(sdsempty(),"%d\r\n",
1564 stringObjectLen(argv
[j
])));
1565 lenobj
->refcount
= 0;
1566 outv
[outc
++] = lenobj
;
1568 outv
[outc
++] = argv
[j
];
1570 outv
[outc
++] = shared
.crlf
;
1572 /* Increment all the refcounts at start and decrement at end in order to
1573 * be sure to free objects if there is no slave in a replication state
1574 * able to be feed with commands */
1575 for (j
= 0; j
< outc
; j
++) incrRefCount(outv
[j
]);
1577 while((ln
= listYield(slaves
))) {
1578 redisClient
*slave
= ln
->value
;
1580 /* Don't feed slaves that are still waiting for BGSAVE to start */
1581 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) continue;
1583 /* Feed all the other slaves, MONITORs and so on */
1584 if (slave
->slaveseldb
!= dictid
) {
1588 case 0: selectcmd
= shared
.select0
; break;
1589 case 1: selectcmd
= shared
.select1
; break;
1590 case 2: selectcmd
= shared
.select2
; break;
1591 case 3: selectcmd
= shared
.select3
; break;
1592 case 4: selectcmd
= shared
.select4
; break;
1593 case 5: selectcmd
= shared
.select5
; break;
1594 case 6: selectcmd
= shared
.select6
; break;
1595 case 7: selectcmd
= shared
.select7
; break;
1596 case 8: selectcmd
= shared
.select8
; break;
1597 case 9: selectcmd
= shared
.select9
; break;
1599 selectcmd
= createObject(REDIS_STRING
,
1600 sdscatprintf(sdsempty(),"select %d\r\n",dictid
));
1601 selectcmd
->refcount
= 0;
1604 addReply(slave
,selectcmd
);
1605 slave
->slaveseldb
= dictid
;
1607 for (j
= 0; j
< outc
; j
++) addReply(slave
,outv
[j
]);
1609 for (j
= 0; j
< outc
; j
++) decrRefCount(outv
[j
]);
1610 if (outv
!= static_outv
) zfree(outv
);
1613 static void processInputBuffer(redisClient
*c
) {
1615 if (c
->bulklen
== -1) {
1616 /* Read the first line of the query */
1617 char *p
= strchr(c
->querybuf
,'\n');
1624 query
= c
->querybuf
;
1625 c
->querybuf
= sdsempty();
1626 querylen
= 1+(p
-(query
));
1627 if (sdslen(query
) > querylen
) {
1628 /* leave data after the first line of the query in the buffer */
1629 c
->querybuf
= sdscatlen(c
->querybuf
,query
+querylen
,sdslen(query
)-querylen
);
1631 *p
= '\0'; /* remove "\n" */
1632 if (*(p
-1) == '\r') *(p
-1) = '\0'; /* and "\r" if any */
1633 sdsupdatelen(query
);
1635 /* Now we can split the query in arguments */
1636 if (sdslen(query
) == 0) {
1637 /* Ignore empty query */
1641 argv
= sdssplitlen(query
,sdslen(query
)," ",1,&argc
);
1644 if (c
->argv
) zfree(c
->argv
);
1645 c
->argv
= zmalloc(sizeof(robj
*)*argc
);
1647 for (j
= 0; j
< argc
; j
++) {
1648 if (sdslen(argv
[j
])) {
1649 c
->argv
[c
->argc
] = createObject(REDIS_STRING
,argv
[j
]);
1656 /* Execute the command. If the client is still valid
1657 * after processCommand() return and there is something
1658 * on the query buffer try to process the next command. */
1659 if (c
->argc
&& processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
1661 } else if (sdslen(c
->querybuf
) >= REDIS_REQUEST_MAX_SIZE
) {
1662 redisLog(REDIS_DEBUG
, "Client protocol error");
1667 /* Bulk read handling. Note that if we are at this point
1668 the client already sent a command terminated with a newline,
1669 we are reading the bulk data that is actually the last
1670 argument of the command. */
1671 int qbl
= sdslen(c
->querybuf
);
1673 if (c
->bulklen
<= qbl
) {
1674 /* Copy everything but the final CRLF as final argument */
1675 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
1677 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
1678 /* Process the command. If the client is still valid after
1679 * the processing and there is more data in the buffer
1680 * try to parse it. */
1681 if (processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
1687 static void readQueryFromClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1688 redisClient
*c
= (redisClient
*) privdata
;
1689 char buf
[REDIS_IOBUF_LEN
];
1692 REDIS_NOTUSED(mask
);
1694 nread
= read(fd
, buf
, REDIS_IOBUF_LEN
);
1696 if (errno
== EAGAIN
) {
1699 redisLog(REDIS_DEBUG
, "Reading from client: %s",strerror(errno
));
1703 } else if (nread
== 0) {
1704 redisLog(REDIS_DEBUG
, "Client closed connection");
1709 c
->querybuf
= sdscatlen(c
->querybuf
, buf
, nread
);
1710 c
->lastinteraction
= time(NULL
);
1714 processInputBuffer(c
);
1717 static int selectDb(redisClient
*c
, int id
) {
1718 if (id
< 0 || id
>= server
.dbnum
)
1720 c
->db
= &server
.db
[id
];
1724 static void *dupClientReplyValue(void *o
) {
1725 incrRefCount((robj
*)o
);
1729 static redisClient
*createClient(int fd
) {
1730 redisClient
*c
= zmalloc(sizeof(*c
));
1732 anetNonBlock(NULL
,fd
);
1733 anetTcpNoDelay(NULL
,fd
);
1734 if (!c
) return NULL
;
1737 c
->querybuf
= sdsempty();
1746 c
->lastinteraction
= time(NULL
);
1747 c
->authenticated
= 0;
1748 c
->replstate
= REDIS_REPL_NONE
;
1749 c
->reply
= listCreate();
1750 listSetFreeMethod(c
->reply
,decrRefCount
);
1751 listSetDupMethod(c
->reply
,dupClientReplyValue
);
1752 if (aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
,
1753 readQueryFromClient
, c
, NULL
) == AE_ERR
) {
1757 listAddNodeTail(server
.clients
,c
);
1761 static void addReply(redisClient
*c
, robj
*obj
) {
1762 if (listLength(c
->reply
) == 0 &&
1763 (c
->replstate
== REDIS_REPL_NONE
||
1764 c
->replstate
== REDIS_REPL_ONLINE
) &&
1765 aeCreateFileEvent(server
.el
, c
->fd
, AE_WRITABLE
,
1766 sendReplyToClient
, c
, NULL
) == AE_ERR
) return;
1767 if (obj
->encoding
!= REDIS_ENCODING_RAW
) {
1768 obj
= getDecodedObject(obj
);
1772 listAddNodeTail(c
->reply
,obj
);
1775 static void addReplySds(redisClient
*c
, sds s
) {
1776 robj
*o
= createObject(REDIS_STRING
,s
);
1781 static void addReplyBulkLen(redisClient
*c
, robj
*obj
) {
1784 if (obj
->encoding
== REDIS_ENCODING_RAW
) {
1785 len
= sdslen(obj
->ptr
);
1787 long n
= (long)obj
->ptr
;
1794 while((n
= n
/10) != 0) {
1798 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",len
));
1801 static void acceptHandler(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1806 REDIS_NOTUSED(mask
);
1807 REDIS_NOTUSED(privdata
);
1809 cfd
= anetAccept(server
.neterr
, fd
, cip
, &cport
);
1810 if (cfd
== AE_ERR
) {
1811 redisLog(REDIS_DEBUG
,"Accepting client connection: %s", server
.neterr
);
1814 redisLog(REDIS_DEBUG
,"Accepted %s:%d", cip
, cport
);
1815 if ((c
= createClient(cfd
)) == NULL
) {
1816 redisLog(REDIS_WARNING
,"Error allocating resoures for the client");
1817 close(cfd
); /* May be already closed, just ingore errors */
1820 /* If maxclient directive is set and this is one client more... close the
1821 * connection. Note that we create the client instead to check before
1822 * for this condition, since now the socket is already set in nonblocking
1823 * mode and we can send an error for free using the Kernel I/O */
1824 if (server
.maxclients
&& listLength(server
.clients
) > server
.maxclients
) {
1825 char *err
= "-ERR max number of clients reached\r\n";
1827 /* That's a best effort error message, don't check write errors */
1828 (void) write(c
->fd
,err
,strlen(err
));
1832 server
.stat_numconnections
++;
1835 /* ======================= Redis objects implementation ===================== */
1837 static robj
*createObject(int type
, void *ptr
) {
1840 if (listLength(server
.objfreelist
)) {
1841 listNode
*head
= listFirst(server
.objfreelist
);
1842 o
= listNodeValue(head
);
1843 listDelNode(server
.objfreelist
,head
);
1845 o
= zmalloc(sizeof(*o
));
1848 o
->encoding
= REDIS_ENCODING_RAW
;
1854 static robj
*createStringObject(char *ptr
, size_t len
) {
1855 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
1858 static robj
*createListObject(void) {
1859 list
*l
= listCreate();
1861 listSetFreeMethod(l
,decrRefCount
);
1862 return createObject(REDIS_LIST
,l
);
1865 static robj
*createSetObject(void) {
1866 dict
*d
= dictCreate(&setDictType
,NULL
);
1867 return createObject(REDIS_SET
,d
);
1870 static robj
*createZsetObject(void) {
1871 zset
*zs
= zmalloc(sizeof(*zs
));
1873 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
1874 zs
->zsl
= zslCreate();
1875 return createObject(REDIS_ZSET
,zs
);
1878 static void freeStringObject(robj
*o
) {
1879 if (o
->encoding
== REDIS_ENCODING_RAW
) {
1884 static void freeListObject(robj
*o
) {
1885 listRelease((list
*) o
->ptr
);
1888 static void freeSetObject(robj
*o
) {
1889 dictRelease((dict
*) o
->ptr
);
1892 static void freeZsetObject(robj
*o
) {
1895 dictRelease(zs
->dict
);
1900 static void freeHashObject(robj
*o
) {
1901 dictRelease((dict
*) o
->ptr
);
1904 static void incrRefCount(robj
*o
) {
1906 #ifdef DEBUG_REFCOUNT
1907 if (o
->type
== REDIS_STRING
)
1908 printf("Increment '%s'(%p), now is: %d\n",o
->ptr
,o
,o
->refcount
);
1912 static void decrRefCount(void *obj
) {
1915 #ifdef DEBUG_REFCOUNT
1916 if (o
->type
== REDIS_STRING
)
1917 printf("Decrement '%s'(%p), now is: %d\n",o
->ptr
,o
,o
->refcount
-1);
1919 if (--(o
->refcount
) == 0) {
1921 case REDIS_STRING
: freeStringObject(o
); break;
1922 case REDIS_LIST
: freeListObject(o
); break;
1923 case REDIS_SET
: freeSetObject(o
); break;
1924 case REDIS_ZSET
: freeZsetObject(o
); break;
1925 case REDIS_HASH
: freeHashObject(o
); break;
1926 default: assert(0 != 0); break;
1928 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
1929 !listAddNodeHead(server
.objfreelist
,o
))
1934 static robj
*lookupKey(redisDb
*db
, robj
*key
) {
1935 dictEntry
*de
= dictFind(db
->dict
,key
);
1936 return de
? dictGetEntryVal(de
) : NULL
;
1939 static robj
*lookupKeyRead(redisDb
*db
, robj
*key
) {
1940 expireIfNeeded(db
,key
);
1941 return lookupKey(db
,key
);
1944 static robj
*lookupKeyWrite(redisDb
*db
, robj
*key
) {
1945 deleteIfVolatile(db
,key
);
1946 return lookupKey(db
,key
);
1949 static int deleteKey(redisDb
*db
, robj
*key
) {
1952 /* We need to protect key from destruction: after the first dictDelete()
1953 * it may happen that 'key' is no longer valid if we don't increment
1954 * it's count. This may happen when we get the object reference directly
1955 * from the hash table with dictRandomKey() or dict iterators */
1957 if (dictSize(db
->expires
)) dictDelete(db
->expires
,key
);
1958 retval
= dictDelete(db
->dict
,key
);
1961 return retval
== DICT_OK
;
1964 /* Try to share an object against the shared objects pool */
1965 static robj
*tryObjectSharing(robj
*o
) {
1966 struct dictEntry
*de
;
1969 if (o
== NULL
|| server
.shareobjects
== 0) return o
;
1971 assert(o
->type
== REDIS_STRING
);
1972 de
= dictFind(server
.sharingpool
,o
);
1974 robj
*shared
= dictGetEntryKey(de
);
1976 c
= ((unsigned long) dictGetEntryVal(de
))+1;
1977 dictGetEntryVal(de
) = (void*) c
;
1978 incrRefCount(shared
);
1982 /* Here we are using a stream algorihtm: Every time an object is
1983 * shared we increment its count, everytime there is a miss we
1984 * recrement the counter of a random object. If this object reaches
1985 * zero we remove the object and put the current object instead. */
1986 if (dictSize(server
.sharingpool
) >=
1987 server
.sharingpoolsize
) {
1988 de
= dictGetRandomKey(server
.sharingpool
);
1990 c
= ((unsigned long) dictGetEntryVal(de
))-1;
1991 dictGetEntryVal(de
) = (void*) c
;
1993 dictDelete(server
.sharingpool
,de
->key
);
1996 c
= 0; /* If the pool is empty we want to add this object */
2001 retval
= dictAdd(server
.sharingpool
,o
,(void*)1);
2002 assert(retval
== DICT_OK
);
2009 /* Check if the nul-terminated string 's' can be represented by a long
2010 * (that is, is a number that fits into long without any other space or
2011 * character before or after the digits).
2013 * If so, the function returns REDIS_OK and *longval is set to the value
2014 * of the number. Otherwise REDIS_ERR is returned */
2015 static int isStringRepresentableAsLong(sds s
, long *longval
) {
2016 char buf
[32], *endptr
;
2020 value
= strtol(s
, &endptr
, 10);
2021 if (endptr
[0] != '\0') return REDIS_ERR
;
2022 slen
= snprintf(buf
,32,"%ld",value
);
2024 /* If the number converted back into a string is not identical
2025 * then it's not possible to encode the string as integer */
2026 if (sdslen(s
) != (unsigned)slen
|| memcmp(buf
,s
,slen
)) return REDIS_ERR
;
2027 if (longval
) *longval
= value
;
2031 /* Try to encode a string object in order to save space */
2032 static int tryObjectEncoding(robj
*o
) {
2036 if (o
->encoding
!= REDIS_ENCODING_RAW
)
2037 return REDIS_ERR
; /* Already encoded */
2039 /* It's not save to encode shared objects: shared objects can be shared
2040 * everywhere in the "object space" of Redis. Encoded objects can only
2041 * appear as "values" (and not, for instance, as keys) */
2042 if (o
->refcount
> 1) return REDIS_ERR
;
2044 /* Currently we try to encode only strings */
2045 assert(o
->type
== REDIS_STRING
);
2047 /* Check if we can represent this string as a long integer */
2048 if (isStringRepresentableAsLong(s
,&value
) == REDIS_ERR
) return REDIS_ERR
;
2050 /* Ok, this object can be encoded */
2051 o
->encoding
= REDIS_ENCODING_INT
;
2053 o
->ptr
= (void*) value
;
2057 /* Get a decoded version of an encoded object (returned as a new object) */
2058 static robj
*getDecodedObject(const robj
*o
) {
2061 assert(o
->encoding
!= REDIS_ENCODING_RAW
);
2062 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
2065 snprintf(buf
,32,"%ld",(long)o
->ptr
);
2066 dec
= createStringObject(buf
,strlen(buf
));
2073 static int compareStringObjects(robj
*a
, robj
*b
) {
2074 assert(a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
2076 if (a
== b
) return 0;
2077 if (a
->encoding
== REDIS_ENCODING_INT
&& b
->encoding
== REDIS_ENCODING_INT
){
2078 return (long)a
->ptr
- (long)b
->ptr
;
2084 if (a
->encoding
!= REDIS_ENCODING_RAW
) a
= getDecodedObject(a
);
2085 if (b
->encoding
!= REDIS_ENCODING_RAW
) b
= getDecodedObject(a
);
2086 retval
= sdscmp(a
->ptr
,b
->ptr
);
2093 static size_t stringObjectLen(robj
*o
) {
2094 assert(o
->type
== REDIS_STRING
);
2095 if (o
->encoding
== REDIS_ENCODING_RAW
) {
2096 return sdslen(o
->ptr
);
2100 return snprintf(buf
,32,"%ld",(long)o
->ptr
);
2104 /*============================ DB saving/loading ============================ */
2106 static int rdbSaveType(FILE *fp
, unsigned char type
) {
2107 if (fwrite(&type
,1,1,fp
) == 0) return -1;
2111 static int rdbSaveTime(FILE *fp
, time_t t
) {
2112 int32_t t32
= (int32_t) t
;
2113 if (fwrite(&t32
,4,1,fp
) == 0) return -1;
2117 /* check rdbLoadLen() comments for more info */
2118 static int rdbSaveLen(FILE *fp
, uint32_t len
) {
2119 unsigned char buf
[2];
2122 /* Save a 6 bit len */
2123 buf
[0] = (len
&0xFF)|(REDIS_RDB_6BITLEN
<<6);
2124 if (fwrite(buf
,1,1,fp
) == 0) return -1;
2125 } else if (len
< (1<<14)) {
2126 /* Save a 14 bit len */
2127 buf
[0] = ((len
>>8)&0xFF)|(REDIS_RDB_14BITLEN
<<6);
2129 if (fwrite(buf
,2,1,fp
) == 0) return -1;
2131 /* Save a 32 bit len */
2132 buf
[0] = (REDIS_RDB_32BITLEN
<<6);
2133 if (fwrite(buf
,1,1,fp
) == 0) return -1;
2135 if (fwrite(&len
,4,1,fp
) == 0) return -1;
2140 /* String objects in the form "2391" "-100" without any space and with a
2141 * range of values that can fit in an 8, 16 or 32 bit signed value can be
2142 * encoded as integers to save space */
2143 static int rdbTryIntegerEncoding(sds s
, unsigned char *enc
) {
2145 char *endptr
, buf
[32];
2147 /* Check if it's possible to encode this value as a number */
2148 value
= strtoll(s
, &endptr
, 10);
2149 if (endptr
[0] != '\0') return 0;
2150 snprintf(buf
,32,"%lld",value
);
2152 /* If the number converted back into a string is not identical
2153 * then it's not possible to encode the string as integer */
2154 if (strlen(buf
) != sdslen(s
) || memcmp(buf
,s
,sdslen(s
))) return 0;
2156 /* Finally check if it fits in our ranges */
2157 if (value
>= -(1<<7) && value
<= (1<<7)-1) {
2158 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT8
;
2159 enc
[1] = value
&0xFF;
2161 } else if (value
>= -(1<<15) && value
<= (1<<15)-1) {
2162 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT16
;
2163 enc
[1] = value
&0xFF;
2164 enc
[2] = (value
>>8)&0xFF;
2166 } else if (value
>= -((long long)1<<31) && value
<= ((long long)1<<31)-1) {
2167 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT32
;
2168 enc
[1] = value
&0xFF;
2169 enc
[2] = (value
>>8)&0xFF;
2170 enc
[3] = (value
>>16)&0xFF;
2171 enc
[4] = (value
>>24)&0xFF;
2178 static int rdbSaveLzfStringObject(FILE *fp
, robj
*obj
) {
2179 unsigned int comprlen
, outlen
;
2183 /* We require at least four bytes compression for this to be worth it */
2184 outlen
= sdslen(obj
->ptr
)-4;
2185 if (outlen
<= 0) return 0;
2186 if ((out
= zmalloc(outlen
+1)) == NULL
) return 0;
2187 comprlen
= lzf_compress(obj
->ptr
, sdslen(obj
->ptr
), out
, outlen
);
2188 if (comprlen
== 0) {
2192 /* Data compressed! Let's save it on disk */
2193 byte
= (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_LZF
;
2194 if (fwrite(&byte
,1,1,fp
) == 0) goto writeerr
;
2195 if (rdbSaveLen(fp
,comprlen
) == -1) goto writeerr
;
2196 if (rdbSaveLen(fp
,sdslen(obj
->ptr
)) == -1) goto writeerr
;
2197 if (fwrite(out
,comprlen
,1,fp
) == 0) goto writeerr
;
2206 /* Save a string objet as [len][data] on disk. If the object is a string
2207 * representation of an integer value we try to safe it in a special form */
2208 static int rdbSaveStringObjectRaw(FILE *fp
, robj
*obj
) {
2212 len
= sdslen(obj
->ptr
);
2214 /* Try integer encoding */
2216 unsigned char buf
[5];
2217 if ((enclen
= rdbTryIntegerEncoding(obj
->ptr
,buf
)) > 0) {
2218 if (fwrite(buf
,enclen
,1,fp
) == 0) return -1;
2223 /* Try LZF compression - under 20 bytes it's unable to compress even
2224 * aaaaaaaaaaaaaaaaaa so skip it */
2228 retval
= rdbSaveLzfStringObject(fp
,obj
);
2229 if (retval
== -1) return -1;
2230 if (retval
> 0) return 0;
2231 /* retval == 0 means data can't be compressed, save the old way */
2234 /* Store verbatim */
2235 if (rdbSaveLen(fp
,len
) == -1) return -1;
2236 if (len
&& fwrite(obj
->ptr
,len
,1,fp
) == 0) return -1;
2240 /* Like rdbSaveStringObjectRaw() but handle encoded objects */
2241 static int rdbSaveStringObject(FILE *fp
, robj
*obj
) {
2245 if (obj
->encoding
!= REDIS_ENCODING_RAW
) {
2246 dec
= getDecodedObject(obj
);
2247 retval
= rdbSaveStringObjectRaw(fp
,dec
);
2251 return rdbSaveStringObjectRaw(fp
,obj
);
2255 /* Save a double value. Doubles are saved as strings prefixed by an unsigned
2256 * 8 bit integer specifing the length of the representation.
2257 * This 8 bit integer has special values in order to specify the following
2263 static int rdbSaveDoubleValue(FILE *fp
, double val
) {
2264 unsigned char buf
[128];
2270 } else if (!isfinite(val
)) {
2272 buf
[0] = (val
< 0) ? 255 : 254;
2274 snprintf((char*)buf
+1,sizeof(buf
)-1,"%.16g",val
);
2275 buf
[0] = strlen((char*)buf
);
2278 if (fwrite(buf
,len
,1,fp
) == 0) return -1;
2282 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
2283 static int rdbSave(char *filename
) {
2284 dictIterator
*di
= NULL
;
2289 time_t now
= time(NULL
);
2291 snprintf(tmpfile
,256,"temp-%d.rdb", (int) getpid());
2292 fp
= fopen(tmpfile
,"w");
2294 redisLog(REDIS_WARNING
, "Failed saving the DB: %s", strerror(errno
));
2297 if (fwrite("REDIS0001",9,1,fp
) == 0) goto werr
;
2298 for (j
= 0; j
< server
.dbnum
; j
++) {
2299 redisDb
*db
= server
.db
+j
;
2301 if (dictSize(d
) == 0) continue;
2302 di
= dictGetIterator(d
);
2308 /* Write the SELECT DB opcode */
2309 if (rdbSaveType(fp
,REDIS_SELECTDB
) == -1) goto werr
;
2310 if (rdbSaveLen(fp
,j
) == -1) goto werr
;
2312 /* Iterate this DB writing every entry */
2313 while((de
= dictNext(di
)) != NULL
) {
2314 robj
*key
= dictGetEntryKey(de
);
2315 robj
*o
= dictGetEntryVal(de
);
2316 time_t expiretime
= getExpire(db
,key
);
2318 /* Save the expire time */
2319 if (expiretime
!= -1) {
2320 /* If this key is already expired skip it */
2321 if (expiretime
< now
) continue;
2322 if (rdbSaveType(fp
,REDIS_EXPIRETIME
) == -1) goto werr
;
2323 if (rdbSaveTime(fp
,expiretime
) == -1) goto werr
;
2325 /* Save the key and associated value */
2326 if (rdbSaveType(fp
,o
->type
) == -1) goto werr
;
2327 if (rdbSaveStringObject(fp
,key
) == -1) goto werr
;
2328 if (o
->type
== REDIS_STRING
) {
2329 /* Save a string value */
2330 if (rdbSaveStringObject(fp
,o
) == -1) goto werr
;
2331 } else if (o
->type
== REDIS_LIST
) {
2332 /* Save a list value */
2333 list
*list
= o
->ptr
;
2337 if (rdbSaveLen(fp
,listLength(list
)) == -1) goto werr
;
2338 while((ln
= listYield(list
))) {
2339 robj
*eleobj
= listNodeValue(ln
);
2341 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
2343 } else if (o
->type
== REDIS_SET
) {
2344 /* Save a set value */
2346 dictIterator
*di
= dictGetIterator(set
);
2349 if (rdbSaveLen(fp
,dictSize(set
)) == -1) goto werr
;
2350 while((de
= dictNext(di
)) != NULL
) {
2351 robj
*eleobj
= dictGetEntryKey(de
);
2353 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
2355 dictReleaseIterator(di
);
2356 } else if (o
->type
== REDIS_ZSET
) {
2357 /* Save a set value */
2359 dictIterator
*di
= dictGetIterator(zs
->dict
);
2362 if (rdbSaveLen(fp
,dictSize(zs
->dict
)) == -1) goto werr
;
2363 while((de
= dictNext(di
)) != NULL
) {
2364 robj
*eleobj
= dictGetEntryKey(de
);
2365 double *score
= dictGetEntryVal(de
);
2367 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
2368 if (rdbSaveDoubleValue(fp
,*score
) == -1) goto werr
;
2370 dictReleaseIterator(di
);
2375 dictReleaseIterator(di
);
2378 if (rdbSaveType(fp
,REDIS_EOF
) == -1) goto werr
;
2380 /* Make sure data will not remain on the OS's output buffers */
2385 /* Use RENAME to make sure the DB file is changed atomically only
2386 * if the generate DB file is ok. */
2387 if (rename(tmpfile
,filename
) == -1) {
2388 redisLog(REDIS_WARNING
,"Error moving temp DB file on the final destination: %s", strerror(errno
));
2392 redisLog(REDIS_NOTICE
,"DB saved on disk");
2394 server
.lastsave
= time(NULL
);
2400 redisLog(REDIS_WARNING
,"Write error saving DB on disk: %s", strerror(errno
));
2401 if (di
) dictReleaseIterator(di
);
2405 static int rdbSaveBackground(char *filename
) {
2408 if (server
.bgsaveinprogress
) return REDIS_ERR
;
2409 if ((childpid
= fork()) == 0) {
2412 if (rdbSave(filename
) == REDIS_OK
) {
2419 if (childpid
== -1) {
2420 redisLog(REDIS_WARNING
,"Can't save in background: fork: %s",
2424 redisLog(REDIS_NOTICE
,"Background saving started by pid %d",childpid
);
2425 server
.bgsaveinprogress
= 1;
2426 server
.bgsavechildpid
= childpid
;
2429 return REDIS_OK
; /* unreached */
2432 static void rdbRemoveTempFile(pid_t childpid
) {
2435 snprintf(tmpfile
,256,"temp-%d.rdb", (int) childpid
);
2439 static int rdbLoadType(FILE *fp
) {
2441 if (fread(&type
,1,1,fp
) == 0) return -1;
2445 static time_t rdbLoadTime(FILE *fp
) {
2447 if (fread(&t32
,4,1,fp
) == 0) return -1;
2448 return (time_t) t32
;
2451 /* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
2452 * of this file for a description of how this are stored on disk.
2454 * isencoded is set to 1 if the readed length is not actually a length but
2455 * an "encoding type", check the above comments for more info */
2456 static uint32_t rdbLoadLen(FILE *fp
, int rdbver
, int *isencoded
) {
2457 unsigned char buf
[2];
2460 if (isencoded
) *isencoded
= 0;
2462 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
2467 if (fread(buf
,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2468 type
= (buf
[0]&0xC0)>>6;
2469 if (type
== REDIS_RDB_6BITLEN
) {
2470 /* Read a 6 bit len */
2472 } else if (type
== REDIS_RDB_ENCVAL
) {
2473 /* Read a 6 bit len encoding type */
2474 if (isencoded
) *isencoded
= 1;
2476 } else if (type
== REDIS_RDB_14BITLEN
) {
2477 /* Read a 14 bit len */
2478 if (fread(buf
+1,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2479 return ((buf
[0]&0x3F)<<8)|buf
[1];
2481 /* Read a 32 bit len */
2482 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
2488 static robj
*rdbLoadIntegerObject(FILE *fp
, int enctype
) {
2489 unsigned char enc
[4];
2492 if (enctype
== REDIS_RDB_ENC_INT8
) {
2493 if (fread(enc
,1,1,fp
) == 0) return NULL
;
2494 val
= (signed char)enc
[0];
2495 } else if (enctype
== REDIS_RDB_ENC_INT16
) {
2497 if (fread(enc
,2,1,fp
) == 0) return NULL
;
2498 v
= enc
[0]|(enc
[1]<<8);
2500 } else if (enctype
== REDIS_RDB_ENC_INT32
) {
2502 if (fread(enc
,4,1,fp
) == 0) return NULL
;
2503 v
= enc
[0]|(enc
[1]<<8)|(enc
[2]<<16)|(enc
[3]<<24);
2506 val
= 0; /* anti-warning */
2509 return createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",val
));
2512 static robj
*rdbLoadLzfStringObject(FILE*fp
, int rdbver
) {
2513 unsigned int len
, clen
;
2514 unsigned char *c
= NULL
;
2517 if ((clen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2518 if ((len
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2519 if ((c
= zmalloc(clen
)) == NULL
) goto err
;
2520 if ((val
= sdsnewlen(NULL
,len
)) == NULL
) goto err
;
2521 if (fread(c
,clen
,1,fp
) == 0) goto err
;
2522 if (lzf_decompress(c
,clen
,val
,len
) == 0) goto err
;
2524 return createObject(REDIS_STRING
,val
);
2531 static robj
*rdbLoadStringObject(FILE*fp
, int rdbver
) {
2536 len
= rdbLoadLen(fp
,rdbver
,&isencoded
);
2539 case REDIS_RDB_ENC_INT8
:
2540 case REDIS_RDB_ENC_INT16
:
2541 case REDIS_RDB_ENC_INT32
:
2542 return tryObjectSharing(rdbLoadIntegerObject(fp
,len
));
2543 case REDIS_RDB_ENC_LZF
:
2544 return tryObjectSharing(rdbLoadLzfStringObject(fp
,rdbver
));
2550 if (len
== REDIS_RDB_LENERR
) return NULL
;
2551 val
= sdsnewlen(NULL
,len
);
2552 if (len
&& fread(val
,len
,1,fp
) == 0) {
2556 return tryObjectSharing(createObject(REDIS_STRING
,val
));
2559 /* For information about double serialization check rdbSaveDoubleValue() */
2560 static int rdbLoadDoubleValue(FILE *fp
, double *val
) {
2564 if (fread(&len
,1,1,fp
) == 0) return -1;
2566 case 255: *val
= R_NegInf
; return 0;
2567 case 254: *val
= R_PosInf
; return 0;
2568 case 253: *val
= R_Nan
; return 0;
2570 if (fread(buf
,len
,1,fp
) == 0) return -1;
2571 sscanf(buf
, "%lg", val
);
2576 static int rdbLoad(char *filename
) {
2578 robj
*keyobj
= NULL
;
2580 int type
, retval
, rdbver
;
2581 dict
*d
= server
.db
[0].dict
;
2582 redisDb
*db
= server
.db
+0;
2584 time_t expiretime
= -1, now
= time(NULL
);
2586 fp
= fopen(filename
,"r");
2587 if (!fp
) return REDIS_ERR
;
2588 if (fread(buf
,9,1,fp
) == 0) goto eoferr
;
2590 if (memcmp(buf
,"REDIS",5) != 0) {
2592 redisLog(REDIS_WARNING
,"Wrong signature trying to load DB from file");
2595 rdbver
= atoi(buf
+5);
2598 redisLog(REDIS_WARNING
,"Can't handle RDB format version %d",rdbver
);
2605 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
2606 if (type
== REDIS_EXPIRETIME
) {
2607 if ((expiretime
= rdbLoadTime(fp
)) == -1) goto eoferr
;
2608 /* We read the time so we need to read the object type again */
2609 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
2611 if (type
== REDIS_EOF
) break;
2612 /* Handle SELECT DB opcode as a special case */
2613 if (type
== REDIS_SELECTDB
) {
2614 if ((dbid
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2616 if (dbid
>= (unsigned)server
.dbnum
) {
2617 redisLog(REDIS_WARNING
,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server
.dbnum
);
2620 db
= server
.db
+dbid
;
2625 if ((keyobj
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2627 if (type
== REDIS_STRING
) {
2628 /* Read string value */
2629 if ((o
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2630 tryObjectEncoding(o
);
2631 } else if (type
== REDIS_LIST
|| type
== REDIS_SET
) {
2632 /* Read list/set value */
2635 if ((listlen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2637 o
= (type
== REDIS_LIST
) ? createListObject() : createSetObject();
2638 /* Load every single element of the list/set */
2642 if ((ele
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2643 tryObjectEncoding(ele
);
2644 if (type
== REDIS_LIST
) {
2645 listAddNodeTail((list
*)o
->ptr
,ele
);
2647 dictAdd((dict
*)o
->ptr
,ele
,NULL
);
2650 } else if (type
== REDIS_ZSET
) {
2651 /* Read list/set value */
2655 if ((zsetlen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2657 o
= createZsetObject();
2659 /* Load every single element of the list/set */
2662 double *score
= zmalloc(sizeof(double));
2664 if ((ele
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2665 tryObjectEncoding(ele
);
2666 if (rdbLoadDoubleValue(fp
,score
) == -1) goto eoferr
;
2667 dictAdd(zs
->dict
,ele
,score
);
2668 zslInsert(zs
->zsl
,*score
,ele
);
2669 incrRefCount(ele
); /* added to skiplist */
2674 /* Add the new object in the hash table */
2675 retval
= dictAdd(d
,keyobj
,o
);
2676 if (retval
== DICT_ERR
) {
2677 redisLog(REDIS_WARNING
,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj
->ptr
);
2680 /* Set the expire time if needed */
2681 if (expiretime
!= -1) {
2682 setExpire(db
,keyobj
,expiretime
);
2683 /* Delete this key if already expired */
2684 if (expiretime
< now
) deleteKey(db
,keyobj
);
2692 eoferr
: /* unexpected end of file is handled here with a fatal exit */
2693 if (keyobj
) decrRefCount(keyobj
);
2694 redisLog(REDIS_WARNING
,"Short read or OOM loading DB. Unrecoverable error, exiting now.");
2696 return REDIS_ERR
; /* Just to avoid warning */
2699 /*================================== Commands =============================== */
2701 static void authCommand(redisClient
*c
) {
2702 if (!server
.requirepass
|| !strcmp(c
->argv
[1]->ptr
, server
.requirepass
)) {
2703 c
->authenticated
= 1;
2704 addReply(c
,shared
.ok
);
2706 c
->authenticated
= 0;
2707 addReply(c
,shared
.err
);
2711 static void pingCommand(redisClient
*c
) {
2712 addReply(c
,shared
.pong
);
2715 static void echoCommand(redisClient
*c
) {
2716 addReplyBulkLen(c
,c
->argv
[1]);
2717 addReply(c
,c
->argv
[1]);
2718 addReply(c
,shared
.crlf
);
2721 /*=================================== Strings =============================== */
2723 static void setGenericCommand(redisClient
*c
, int nx
) {
2726 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2727 if (retval
== DICT_ERR
) {
2729 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2730 incrRefCount(c
->argv
[2]);
2732 addReply(c
,shared
.czero
);
2736 incrRefCount(c
->argv
[1]);
2737 incrRefCount(c
->argv
[2]);
2740 removeExpire(c
->db
,c
->argv
[1]);
2741 addReply(c
, nx
? shared
.cone
: shared
.ok
);
2744 static void setCommand(redisClient
*c
) {
2745 setGenericCommand(c
,0);
2748 static void setnxCommand(redisClient
*c
) {
2749 setGenericCommand(c
,1);
2752 static void getCommand(redisClient
*c
) {
2753 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2756 addReply(c
,shared
.nullbulk
);
2758 if (o
->type
!= REDIS_STRING
) {
2759 addReply(c
,shared
.wrongtypeerr
);
2761 addReplyBulkLen(c
,o
);
2763 addReply(c
,shared
.crlf
);
2768 static void getsetCommand(redisClient
*c
) {
2770 if (dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]) == DICT_ERR
) {
2771 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2773 incrRefCount(c
->argv
[1]);
2775 incrRefCount(c
->argv
[2]);
2777 removeExpire(c
->db
,c
->argv
[1]);
2780 static void mgetCommand(redisClient
*c
) {
2783 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",c
->argc
-1));
2784 for (j
= 1; j
< c
->argc
; j
++) {
2785 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
2787 addReply(c
,shared
.nullbulk
);
2789 if (o
->type
!= REDIS_STRING
) {
2790 addReply(c
,shared
.nullbulk
);
2792 addReplyBulkLen(c
,o
);
2794 addReply(c
,shared
.crlf
);
2800 static void incrDecrCommand(redisClient
*c
, long long incr
) {
2805 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2809 if (o
->type
!= REDIS_STRING
) {
2814 if (o
->encoding
== REDIS_ENCODING_RAW
)
2815 value
= strtoll(o
->ptr
, &eptr
, 10);
2816 else if (o
->encoding
== REDIS_ENCODING_INT
)
2817 value
= (long)o
->ptr
;
2824 o
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",value
));
2825 tryObjectEncoding(o
);
2826 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],o
);
2827 if (retval
== DICT_ERR
) {
2828 dictReplace(c
->db
->dict
,c
->argv
[1],o
);
2829 removeExpire(c
->db
,c
->argv
[1]);
2831 incrRefCount(c
->argv
[1]);
2834 addReply(c
,shared
.colon
);
2836 addReply(c
,shared
.crlf
);
2839 static void incrCommand(redisClient
*c
) {
2840 incrDecrCommand(c
,1);
2843 static void decrCommand(redisClient
*c
) {
2844 incrDecrCommand(c
,-1);
2847 static void incrbyCommand(redisClient
*c
) {
2848 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
2849 incrDecrCommand(c
,incr
);
2852 static void decrbyCommand(redisClient
*c
) {
2853 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
2854 incrDecrCommand(c
,-incr
);
2857 /* ========================= Type agnostic commands ========================= */
2859 static void delCommand(redisClient
*c
) {
2862 for (j
= 1; j
< c
->argc
; j
++) {
2863 if (deleteKey(c
->db
,c
->argv
[j
])) {
2870 addReply(c
,shared
.czero
);
2873 addReply(c
,shared
.cone
);
2876 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",deleted
));
2881 static void existsCommand(redisClient
*c
) {
2882 addReply(c
,lookupKeyRead(c
->db
,c
->argv
[1]) ? shared
.cone
: shared
.czero
);
2885 static void selectCommand(redisClient
*c
) {
2886 int id
= atoi(c
->argv
[1]->ptr
);
2888 if (selectDb(c
,id
) == REDIS_ERR
) {
2889 addReplySds(c
,sdsnew("-ERR invalid DB index\r\n"));
2891 addReply(c
,shared
.ok
);
2895 static void randomkeyCommand(redisClient
*c
) {
2899 de
= dictGetRandomKey(c
->db
->dict
);
2900 if (!de
|| expireIfNeeded(c
->db
,dictGetEntryKey(de
)) == 0) break;
2903 addReply(c
,shared
.plus
);
2904 addReply(c
,shared
.crlf
);
2906 addReply(c
,shared
.plus
);
2907 addReply(c
,dictGetEntryKey(de
));
2908 addReply(c
,shared
.crlf
);
2912 static void keysCommand(redisClient
*c
) {
2915 sds pattern
= c
->argv
[1]->ptr
;
2916 int plen
= sdslen(pattern
);
2917 int numkeys
= 0, keyslen
= 0;
2918 robj
*lenobj
= createObject(REDIS_STRING
,NULL
);
2920 di
= dictGetIterator(c
->db
->dict
);
2922 decrRefCount(lenobj
);
2923 while((de
= dictNext(di
)) != NULL
) {
2924 robj
*keyobj
= dictGetEntryKey(de
);
2926 sds key
= keyobj
->ptr
;
2927 if ((pattern
[0] == '*' && pattern
[1] == '\0') ||
2928 stringmatchlen(pattern
,plen
,key
,sdslen(key
),0)) {
2929 if (expireIfNeeded(c
->db
,keyobj
) == 0) {
2931 addReply(c
,shared
.space
);
2934 keyslen
+= sdslen(key
);
2938 dictReleaseIterator(di
);
2939 lenobj
->ptr
= sdscatprintf(sdsempty(),"$%lu\r\n",keyslen
+(numkeys
? (numkeys
-1) : 0));
2940 addReply(c
,shared
.crlf
);
2943 static void dbsizeCommand(redisClient
*c
) {
2945 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c
->db
->dict
)));
2948 static void lastsaveCommand(redisClient
*c
) {
2950 sdscatprintf(sdsempty(),":%lu\r\n",server
.lastsave
));
2953 static void typeCommand(redisClient
*c
) {
2957 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2962 case REDIS_STRING
: type
= "+string"; break;
2963 case REDIS_LIST
: type
= "+list"; break;
2964 case REDIS_SET
: type
= "+set"; break;
2965 default: type
= "unknown"; break;
2968 addReplySds(c
,sdsnew(type
));
2969 addReply(c
,shared
.crlf
);
2972 static void saveCommand(redisClient
*c
) {
2973 if (server
.bgsaveinprogress
) {
2974 addReplySds(c
,sdsnew("-ERR background save in progress\r\n"));
2977 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
2978 addReply(c
,shared
.ok
);
2980 addReply(c
,shared
.err
);
2984 static void bgsaveCommand(redisClient
*c
) {
2985 if (server
.bgsaveinprogress
) {
2986 addReplySds(c
,sdsnew("-ERR background save already in progress\r\n"));
2989 if (rdbSaveBackground(server
.dbfilename
) == REDIS_OK
) {
2990 addReply(c
,shared
.ok
);
2992 addReply(c
,shared
.err
);
2996 static void shutdownCommand(redisClient
*c
) {
2997 redisLog(REDIS_WARNING
,"User requested shutdown, saving DB...");
2998 /* Kill the saving child if there is a background saving in progress.
2999 We want to avoid race conditions, for instance our saving child may
3000 overwrite the synchronous saving did by SHUTDOWN. */
3001 if (server
.bgsaveinprogress
) {
3002 redisLog(REDIS_WARNING
,"There is a live saving child. Killing it!");
3003 kill(server
.bgsavechildpid
,SIGKILL
);
3004 rdbRemoveTempFile(server
.bgsavechildpid
);
3007 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
3008 if (server
.daemonize
)
3009 unlink(server
.pidfile
);
3010 redisLog(REDIS_WARNING
,"%zu bytes used at exit",zmalloc_used_memory());
3011 redisLog(REDIS_WARNING
,"Server exit now, bye bye...");
3014 /* Ooops.. error saving! The best we can do is to continue operating.
3015 * Note that if there was a background saving process, in the next
3016 * cron() Redis will be notified that the background saving aborted,
3017 * handling special stuff like slaves pending for synchronization... */
3018 redisLog(REDIS_WARNING
,"Error trying to save the DB, can't exit");
3019 addReplySds(c
,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
3023 static void renameGenericCommand(redisClient
*c
, int nx
) {
3026 /* To use the same key as src and dst is probably an error */
3027 if (sdscmp(c
->argv
[1]->ptr
,c
->argv
[2]->ptr
) == 0) {
3028 addReply(c
,shared
.sameobjecterr
);
3032 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3034 addReply(c
,shared
.nokeyerr
);
3038 deleteIfVolatile(c
->db
,c
->argv
[2]);
3039 if (dictAdd(c
->db
->dict
,c
->argv
[2],o
) == DICT_ERR
) {
3042 addReply(c
,shared
.czero
);
3045 dictReplace(c
->db
->dict
,c
->argv
[2],o
);
3047 incrRefCount(c
->argv
[2]);
3049 deleteKey(c
->db
,c
->argv
[1]);
3051 addReply(c
,nx
? shared
.cone
: shared
.ok
);
3054 static void renameCommand(redisClient
*c
) {
3055 renameGenericCommand(c
,0);
3058 static void renamenxCommand(redisClient
*c
) {
3059 renameGenericCommand(c
,1);
3062 static void moveCommand(redisClient
*c
) {
3067 /* Obtain source and target DB pointers */
3070 if (selectDb(c
,atoi(c
->argv
[2]->ptr
)) == REDIS_ERR
) {
3071 addReply(c
,shared
.outofrangeerr
);
3075 selectDb(c
,srcid
); /* Back to the source DB */
3077 /* If the user is moving using as target the same
3078 * DB as the source DB it is probably an error. */
3080 addReply(c
,shared
.sameobjecterr
);
3084 /* Check if the element exists and get a reference */
3085 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3087 addReply(c
,shared
.czero
);
3091 /* Try to add the element to the target DB */
3092 deleteIfVolatile(dst
,c
->argv
[1]);
3093 if (dictAdd(dst
->dict
,c
->argv
[1],o
) == DICT_ERR
) {
3094 addReply(c
,shared
.czero
);
3097 incrRefCount(c
->argv
[1]);
3100 /* OK! key moved, free the entry in the source DB */
3101 deleteKey(src
,c
->argv
[1]);
3103 addReply(c
,shared
.cone
);
3106 /* =================================== Lists ================================ */
3107 static void pushGenericCommand(redisClient
*c
, int where
) {
3111 lobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3113 lobj
= createListObject();
3115 if (where
== REDIS_HEAD
) {
3116 listAddNodeHead(list
,c
->argv
[2]);
3118 listAddNodeTail(list
,c
->argv
[2]);
3120 dictAdd(c
->db
->dict
,c
->argv
[1],lobj
);
3121 incrRefCount(c
->argv
[1]);
3122 incrRefCount(c
->argv
[2]);
3124 if (lobj
->type
!= REDIS_LIST
) {
3125 addReply(c
,shared
.wrongtypeerr
);
3129 if (where
== REDIS_HEAD
) {
3130 listAddNodeHead(list
,c
->argv
[2]);
3132 listAddNodeTail(list
,c
->argv
[2]);
3134 incrRefCount(c
->argv
[2]);
3137 addReply(c
,shared
.ok
);
3140 static void lpushCommand(redisClient
*c
) {
3141 pushGenericCommand(c
,REDIS_HEAD
);
3144 static void rpushCommand(redisClient
*c
) {
3145 pushGenericCommand(c
,REDIS_TAIL
);
3148 static void llenCommand(redisClient
*c
) {
3152 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3154 addReply(c
,shared
.czero
);
3157 if (o
->type
!= REDIS_LIST
) {
3158 addReply(c
,shared
.wrongtypeerr
);
3161 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",listLength(l
)));
3166 static void lindexCommand(redisClient
*c
) {
3168 int index
= atoi(c
->argv
[2]->ptr
);
3170 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3172 addReply(c
,shared
.nullbulk
);
3174 if (o
->type
!= REDIS_LIST
) {
3175 addReply(c
,shared
.wrongtypeerr
);
3177 list
*list
= o
->ptr
;
3180 ln
= listIndex(list
, index
);
3182 addReply(c
,shared
.nullbulk
);
3184 robj
*ele
= listNodeValue(ln
);
3185 addReplyBulkLen(c
,ele
);
3187 addReply(c
,shared
.crlf
);
3193 static void lsetCommand(redisClient
*c
) {
3195 int index
= atoi(c
->argv
[2]->ptr
);
3197 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3199 addReply(c
,shared
.nokeyerr
);
3201 if (o
->type
!= REDIS_LIST
) {
3202 addReply(c
,shared
.wrongtypeerr
);
3204 list
*list
= o
->ptr
;
3207 ln
= listIndex(list
, index
);
3209 addReply(c
,shared
.outofrangeerr
);
3211 robj
*ele
= listNodeValue(ln
);
3214 listNodeValue(ln
) = c
->argv
[3];
3215 incrRefCount(c
->argv
[3]);
3216 addReply(c
,shared
.ok
);
3223 static void popGenericCommand(redisClient
*c
, int where
) {
3226 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3228 addReply(c
,shared
.nullbulk
);
3230 if (o
->type
!= REDIS_LIST
) {
3231 addReply(c
,shared
.wrongtypeerr
);
3233 list
*list
= o
->ptr
;
3236 if (where
== REDIS_HEAD
)
3237 ln
= listFirst(list
);
3239 ln
= listLast(list
);
3242 addReply(c
,shared
.nullbulk
);
3244 robj
*ele
= listNodeValue(ln
);
3245 addReplyBulkLen(c
,ele
);
3247 addReply(c
,shared
.crlf
);
3248 listDelNode(list
,ln
);
3255 static void lpopCommand(redisClient
*c
) {
3256 popGenericCommand(c
,REDIS_HEAD
);
3259 static void rpopCommand(redisClient
*c
) {
3260 popGenericCommand(c
,REDIS_TAIL
);
3263 static void lrangeCommand(redisClient
*c
) {
3265 int start
= atoi(c
->argv
[2]->ptr
);
3266 int end
= atoi(c
->argv
[3]->ptr
);
3268 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3270 addReply(c
,shared
.nullmultibulk
);
3272 if (o
->type
!= REDIS_LIST
) {
3273 addReply(c
,shared
.wrongtypeerr
);
3275 list
*list
= o
->ptr
;
3277 int llen
= listLength(list
);
3281 /* convert negative indexes */
3282 if (start
< 0) start
= llen
+start
;
3283 if (end
< 0) end
= llen
+end
;
3284 if (start
< 0) start
= 0;
3285 if (end
< 0) end
= 0;
3287 /* indexes sanity checks */
3288 if (start
> end
|| start
>= llen
) {
3289 /* Out of range start or start > end result in empty list */
3290 addReply(c
,shared
.emptymultibulk
);
3293 if (end
>= llen
) end
= llen
-1;
3294 rangelen
= (end
-start
)+1;
3296 /* Return the result in form of a multi-bulk reply */
3297 ln
= listIndex(list
, start
);
3298 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",rangelen
));
3299 for (j
= 0; j
< rangelen
; j
++) {
3300 ele
= listNodeValue(ln
);
3301 addReplyBulkLen(c
,ele
);
3303 addReply(c
,shared
.crlf
);
3310 static void ltrimCommand(redisClient
*c
) {
3312 int start
= atoi(c
->argv
[2]->ptr
);
3313 int end
= atoi(c
->argv
[3]->ptr
);
3315 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3317 addReply(c
,shared
.nokeyerr
);
3319 if (o
->type
!= REDIS_LIST
) {
3320 addReply(c
,shared
.wrongtypeerr
);
3322 list
*list
= o
->ptr
;
3324 int llen
= listLength(list
);
3325 int j
, ltrim
, rtrim
;
3327 /* convert negative indexes */
3328 if (start
< 0) start
= llen
+start
;
3329 if (end
< 0) end
= llen
+end
;
3330 if (start
< 0) start
= 0;
3331 if (end
< 0) end
= 0;
3333 /* indexes sanity checks */
3334 if (start
> end
|| start
>= llen
) {
3335 /* Out of range start or start > end result in empty list */
3339 if (end
>= llen
) end
= llen
-1;
3344 /* Remove list elements to perform the trim */
3345 for (j
= 0; j
< ltrim
; j
++) {
3346 ln
= listFirst(list
);
3347 listDelNode(list
,ln
);
3349 for (j
= 0; j
< rtrim
; j
++) {
3350 ln
= listLast(list
);
3351 listDelNode(list
,ln
);
3354 addReply(c
,shared
.ok
);
3359 static void lremCommand(redisClient
*c
) {
3362 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3364 addReply(c
,shared
.czero
);
3366 if (o
->type
!= REDIS_LIST
) {
3367 addReply(c
,shared
.wrongtypeerr
);
3369 list
*list
= o
->ptr
;
3370 listNode
*ln
, *next
;
3371 int toremove
= atoi(c
->argv
[2]->ptr
);
3376 toremove
= -toremove
;
3379 ln
= fromtail
? list
->tail
: list
->head
;
3381 robj
*ele
= listNodeValue(ln
);
3383 next
= fromtail
? ln
->prev
: ln
->next
;
3384 if (compareStringObjects(ele
,c
->argv
[3]) == 0) {
3385 listDelNode(list
,ln
);
3388 if (toremove
&& removed
== toremove
) break;
3392 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",removed
));
3397 /* ==================================== Sets ================================ */
3399 static void saddCommand(redisClient
*c
) {
3402 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3404 set
= createSetObject();
3405 dictAdd(c
->db
->dict
,c
->argv
[1],set
);
3406 incrRefCount(c
->argv
[1]);
3408 if (set
->type
!= REDIS_SET
) {
3409 addReply(c
,shared
.wrongtypeerr
);
3413 if (dictAdd(set
->ptr
,c
->argv
[2],NULL
) == DICT_OK
) {
3414 incrRefCount(c
->argv
[2]);
3416 addReply(c
,shared
.cone
);
3418 addReply(c
,shared
.czero
);
3422 static void sremCommand(redisClient
*c
) {
3425 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3427 addReply(c
,shared
.czero
);
3429 if (set
->type
!= REDIS_SET
) {
3430 addReply(c
,shared
.wrongtypeerr
);
3433 if (dictDelete(set
->ptr
,c
->argv
[2]) == DICT_OK
) {
3435 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
3436 addReply(c
,shared
.cone
);
3438 addReply(c
,shared
.czero
);
3443 static void smoveCommand(redisClient
*c
) {
3444 robj
*srcset
, *dstset
;
3446 srcset
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3447 dstset
= lookupKeyWrite(c
->db
,c
->argv
[2]);
3449 /* If the source key does not exist return 0, if it's of the wrong type
3451 if (srcset
== NULL
|| srcset
->type
!= REDIS_SET
) {
3452 addReply(c
, srcset
? shared
.wrongtypeerr
: shared
.czero
);
3455 /* Error if the destination key is not a set as well */
3456 if (dstset
&& dstset
->type
!= REDIS_SET
) {
3457 addReply(c
,shared
.wrongtypeerr
);
3460 /* Remove the element from the source set */
3461 if (dictDelete(srcset
->ptr
,c
->argv
[3]) == DICT_ERR
) {
3462 /* Key not found in the src set! return zero */
3463 addReply(c
,shared
.czero
);
3467 /* Add the element to the destination set */
3469 dstset
= createSetObject();
3470 dictAdd(c
->db
->dict
,c
->argv
[2],dstset
);
3471 incrRefCount(c
->argv
[2]);
3473 if (dictAdd(dstset
->ptr
,c
->argv
[3],NULL
) == DICT_OK
)
3474 incrRefCount(c
->argv
[3]);
3475 addReply(c
,shared
.cone
);
3478 static void sismemberCommand(redisClient
*c
) {
3481 set
= lookupKeyRead(c
->db
,c
->argv
[1]);
3483 addReply(c
,shared
.czero
);
3485 if (set
->type
!= REDIS_SET
) {
3486 addReply(c
,shared
.wrongtypeerr
);
3489 if (dictFind(set
->ptr
,c
->argv
[2]))
3490 addReply(c
,shared
.cone
);
3492 addReply(c
,shared
.czero
);
3496 static void scardCommand(redisClient
*c
) {
3500 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3502 addReply(c
,shared
.czero
);
3505 if (o
->type
!= REDIS_SET
) {
3506 addReply(c
,shared
.wrongtypeerr
);
3509 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3515 static void spopCommand(redisClient
*c
) {
3519 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3521 addReply(c
,shared
.nullbulk
);
3523 if (set
->type
!= REDIS_SET
) {
3524 addReply(c
,shared
.wrongtypeerr
);
3527 de
= dictGetRandomKey(set
->ptr
);
3529 addReply(c
,shared
.nullbulk
);
3531 robj
*ele
= dictGetEntryKey(de
);
3533 addReplyBulkLen(c
,ele
);
3535 addReply(c
,shared
.crlf
);
3536 dictDelete(set
->ptr
,ele
);
3537 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
3543 static void srandmemberCommand(redisClient
*c
) {
3547 set
= lookupKeyRead(c
->db
,c
->argv
[1]);
3549 addReply(c
,shared
.nullbulk
);
3551 if (set
->type
!= REDIS_SET
) {
3552 addReply(c
,shared
.wrongtypeerr
);
3555 de
= dictGetRandomKey(set
->ptr
);
3557 addReply(c
,shared
.nullbulk
);
3559 robj
*ele
= dictGetEntryKey(de
);
3561 addReplyBulkLen(c
,ele
);
3563 addReply(c
,shared
.crlf
);
3568 static int qsortCompareSetsByCardinality(const void *s1
, const void *s2
) {
3569 dict
**d1
= (void*) s1
, **d2
= (void*) s2
;
3571 return dictSize(*d1
)-dictSize(*d2
);
3574 static void sinterGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
) {
3575 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
3578 robj
*lenobj
= NULL
, *dstset
= NULL
;
3579 int j
, cardinality
= 0;
3581 for (j
= 0; j
< setsnum
; j
++) {
3585 lookupKeyWrite(c
->db
,setskeys
[j
]) :
3586 lookupKeyRead(c
->db
,setskeys
[j
]);
3590 deleteKey(c
->db
,dstkey
);
3591 addReply(c
,shared
.ok
);
3593 addReply(c
,shared
.nullmultibulk
);
3597 if (setobj
->type
!= REDIS_SET
) {
3599 addReply(c
,shared
.wrongtypeerr
);
3602 dv
[j
] = setobj
->ptr
;
3604 /* Sort sets from the smallest to largest, this will improve our
3605 * algorithm's performace */
3606 qsort(dv
,setsnum
,sizeof(dict
*),qsortCompareSetsByCardinality
);
3608 /* The first thing we should output is the total number of elements...
3609 * since this is a multi-bulk write, but at this stage we don't know
3610 * the intersection set size, so we use a trick, append an empty object
3611 * to the output list and save the pointer to later modify it with the
3614 lenobj
= createObject(REDIS_STRING
,NULL
);
3616 decrRefCount(lenobj
);
3618 /* If we have a target key where to store the resulting set
3619 * create this key with an empty set inside */
3620 dstset
= createSetObject();
3623 /* Iterate all the elements of the first (smallest) set, and test
3624 * the element against all the other sets, if at least one set does
3625 * not include the element it is discarded */
3626 di
= dictGetIterator(dv
[0]);
3628 while((de
= dictNext(di
)) != NULL
) {
3631 for (j
= 1; j
< setsnum
; j
++)
3632 if (dictFind(dv
[j
],dictGetEntryKey(de
)) == NULL
) break;
3634 continue; /* at least one set does not contain the member */
3635 ele
= dictGetEntryKey(de
);
3637 addReplyBulkLen(c
,ele
);
3639 addReply(c
,shared
.crlf
);
3642 dictAdd(dstset
->ptr
,ele
,NULL
);
3646 dictReleaseIterator(di
);
3649 /* Store the resulting set into the target */
3650 deleteKey(c
->db
,dstkey
);
3651 dictAdd(c
->db
->dict
,dstkey
,dstset
);
3652 incrRefCount(dstkey
);
3656 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%d\r\n",cardinality
);
3658 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3659 dictSize((dict
*)dstset
->ptr
)));
3665 static void sinterCommand(redisClient
*c
) {
3666 sinterGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
);
3669 static void sinterstoreCommand(redisClient
*c
) {
3670 sinterGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1]);
3673 #define REDIS_OP_UNION 0
3674 #define REDIS_OP_DIFF 1
3676 static void sunionDiffGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
, int op
) {
3677 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
3680 robj
*dstset
= NULL
;
3681 int j
, cardinality
= 0;
3683 for (j
= 0; j
< setsnum
; j
++) {
3687 lookupKeyWrite(c
->db
,setskeys
[j
]) :
3688 lookupKeyRead(c
->db
,setskeys
[j
]);
3693 if (setobj
->type
!= REDIS_SET
) {
3695 addReply(c
,shared
.wrongtypeerr
);
3698 dv
[j
] = setobj
->ptr
;
3701 /* We need a temp set object to store our union. If the dstkey
3702 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
3703 * this set object will be the resulting object to set into the target key*/
3704 dstset
= createSetObject();
3706 /* Iterate all the elements of all the sets, add every element a single
3707 * time to the result set */
3708 for (j
= 0; j
< setsnum
; j
++) {
3709 if (op
== REDIS_OP_DIFF
&& j
== 0 && !dv
[j
]) break; /* result set is empty */
3710 if (!dv
[j
]) continue; /* non existing keys are like empty sets */
3712 di
= dictGetIterator(dv
[j
]);
3714 while((de
= dictNext(di
)) != NULL
) {
3717 /* dictAdd will not add the same element multiple times */
3718 ele
= dictGetEntryKey(de
);
3719 if (op
== REDIS_OP_UNION
|| j
== 0) {
3720 if (dictAdd(dstset
->ptr
,ele
,NULL
) == DICT_OK
) {
3724 } else if (op
== REDIS_OP_DIFF
) {
3725 if (dictDelete(dstset
->ptr
,ele
) == DICT_OK
) {
3730 dictReleaseIterator(di
);
3732 if (op
== REDIS_OP_DIFF
&& cardinality
== 0) break; /* result set is empty */
3735 /* Output the content of the resulting set, if not in STORE mode */
3737 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",cardinality
));
3738 di
= dictGetIterator(dstset
->ptr
);
3739 while((de
= dictNext(di
)) != NULL
) {
3742 ele
= dictGetEntryKey(de
);
3743 addReplyBulkLen(c
,ele
);
3745 addReply(c
,shared
.crlf
);
3747 dictReleaseIterator(di
);
3749 /* If we have a target key where to store the resulting set
3750 * create this key with the result set inside */
3751 deleteKey(c
->db
,dstkey
);
3752 dictAdd(c
->db
->dict
,dstkey
,dstset
);
3753 incrRefCount(dstkey
);
3758 decrRefCount(dstset
);
3760 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3761 dictSize((dict
*)dstset
->ptr
)));
3767 static void sunionCommand(redisClient
*c
) {
3768 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_UNION
);
3771 static void sunionstoreCommand(redisClient
*c
) {
3772 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_UNION
);
3775 static void sdiffCommand(redisClient
*c
) {
3776 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_DIFF
);
3779 static void sdiffstoreCommand(redisClient
*c
) {
3780 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_DIFF
);
3783 /* ==================================== ZSets =============================== */
3785 /* ZSETs are ordered sets using two data structures to hold the same elements
3786 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
3789 * The elements are added to an hash table mapping Redis objects to scores.
3790 * At the same time the elements are added to a skip list mapping scores
3791 * to Redis objects (so objects are sorted by scores in this "view"). */
3793 /* This skiplist implementation is almost a C translation of the original
3794 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
3795 * Alternative to Balanced Trees", modified in three ways:
3796 * a) this implementation allows for repeated values.
3797 * b) the comparison is not just by key (our 'score') but by satellite data.
3798 * c) there is a back pointer, so it's a doubly linked list with the back
3799 * pointers being only at "level 1". This allows to traverse the list
3800 * from tail to head, useful for ZREVRANGE. */
3802 static zskiplistNode
*zslCreateNode(int level
, double score
, robj
*obj
) {
3803 zskiplistNode
*zn
= zmalloc(sizeof(*zn
));
3805 zn
->forward
= zmalloc(sizeof(zskiplistNode
*) * level
);
3811 static zskiplist
*zslCreate(void) {
3815 zsl
= zmalloc(sizeof(*zsl
));
3818 zsl
->header
= zslCreateNode(ZSKIPLIST_MAXLEVEL
,0,NULL
);
3819 for (j
= 0; j
< ZSKIPLIST_MAXLEVEL
; j
++)
3820 zsl
->header
->forward
[j
] = NULL
;
3821 zsl
->header
->backward
= NULL
;
3826 static void zslFreeNode(zskiplistNode
*node
) {
3827 decrRefCount(node
->obj
);
3828 zfree(node
->forward
);
3832 static void zslFree(zskiplist
*zsl
) {
3833 zskiplistNode
*node
= zsl
->header
->forward
[0], *next
;
3835 zfree(zsl
->header
->forward
);
3838 next
= node
->forward
[0];
3845 static int zslRandomLevel(void) {
3847 while ((random()&0xFFFF) < (ZSKIPLIST_P
* 0xFFFF))
3852 static void zslInsert(zskiplist
*zsl
, double score
, robj
*obj
) {
3853 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
3857 for (i
= zsl
->level
-1; i
>= 0; i
--) {
3858 while (x
->forward
[i
] &&
3859 (x
->forward
[i
]->score
< score
||
3860 (x
->forward
[i
]->score
== score
&&
3861 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0)))
3865 /* we assume the key is not already inside, since we allow duplicated
3866 * scores, and the re-insertion of score and redis object should never
3867 * happpen since the caller of zslInsert() should test in the hash table
3868 * if the element is already inside or not. */
3869 level
= zslRandomLevel();
3870 if (level
> zsl
->level
) {
3871 for (i
= zsl
->level
; i
< level
; i
++)
3872 update
[i
] = zsl
->header
;
3875 x
= zslCreateNode(level
,score
,obj
);
3876 for (i
= 0; i
< level
; i
++) {
3877 x
->forward
[i
] = update
[i
]->forward
[i
];
3878 update
[i
]->forward
[i
] = x
;
3880 x
->backward
= (update
[0] == zsl
->header
) ? NULL
: update
[0];
3882 x
->forward
[0]->backward
= x
;
3888 static int zslDelete(zskiplist
*zsl
, double score
, robj
*obj
) {
3889 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
3893 for (i
= zsl
->level
-1; i
>= 0; i
--) {
3894 while (x
->forward
[i
] &&
3895 (x
->forward
[i
]->score
< score
||
3896 (x
->forward
[i
]->score
== score
&&
3897 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0)))
3901 /* We may have multiple elements with the same score, what we need
3902 * is to find the element with both the right score and object. */
3904 if (compareStringObjects(x
->obj
,obj
) == 0) {
3905 for (i
= 0; i
< zsl
->level
; i
++) {
3906 if (update
[i
]->forward
[i
] != x
) break;
3907 update
[i
]->forward
[i
] = x
->forward
[i
];
3909 if (x
->forward
[0]) {
3910 x
->forward
[0]->backward
= (x
->backward
== zsl
->header
) ?
3913 zsl
->tail
= x
->backward
;
3916 while(zsl
->level
> 1 && zsl
->header
->forward
[zsl
->level
-1] == NULL
)
3921 return 0; /* not found */
3923 return 0; /* not found */
3926 /* The actual Z-commands implementations */
3928 static void zaddCommand(redisClient
*c
) {
3933 zsetobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3934 if (zsetobj
== NULL
) {
3935 zsetobj
= createZsetObject();
3936 dictAdd(c
->db
->dict
,c
->argv
[1],zsetobj
);
3937 incrRefCount(c
->argv
[1]);
3939 if (zsetobj
->type
!= REDIS_ZSET
) {
3940 addReply(c
,shared
.wrongtypeerr
);
3944 score
= zmalloc(sizeof(double));
3945 *score
= strtod(c
->argv
[2]->ptr
,NULL
);
3947 if (dictAdd(zs
->dict
,c
->argv
[3],score
) == DICT_OK
) {
3948 /* case 1: New element */
3949 incrRefCount(c
->argv
[3]); /* added to hash */
3950 zslInsert(zs
->zsl
,*score
,c
->argv
[3]);
3951 incrRefCount(c
->argv
[3]); /* added to skiplist */
3953 addReply(c
,shared
.cone
);
3958 /* case 2: Score update operation */
3959 de
= dictFind(zs
->dict
,c
->argv
[3]);
3961 oldscore
= dictGetEntryVal(de
);
3962 if (*score
!= *oldscore
) {
3965 deleted
= zslDelete(zs
->zsl
,*oldscore
,c
->argv
[3]);
3966 assert(deleted
!= 0);
3967 zslInsert(zs
->zsl
,*score
,c
->argv
[3]);
3968 incrRefCount(c
->argv
[3]);
3969 dictReplace(zs
->dict
,c
->argv
[3],score
);
3974 addReply(c
,shared
.czero
);
3978 static void zremCommand(redisClient
*c
) {
3982 zsetobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3983 if (zsetobj
== NULL
) {
3984 addReply(c
,shared
.czero
);
3990 if (zsetobj
->type
!= REDIS_ZSET
) {
3991 addReply(c
,shared
.wrongtypeerr
);
3995 de
= dictFind(zs
->dict
,c
->argv
[2]);
3997 addReply(c
,shared
.czero
);
4000 /* Delete from the skiplist */
4001 oldscore
= dictGetEntryVal(de
);
4002 deleted
= zslDelete(zs
->zsl
,*oldscore
,c
->argv
[2]);
4003 assert(deleted
!= 0);
4005 /* Delete from the hash table */
4006 dictDelete(zs
->dict
,c
->argv
[2]);
4007 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
4009 addReply(c
,shared
.cone
);
4013 static void zrangeGenericCommand(redisClient
*c
, int reverse
) {
4015 int start
= atoi(c
->argv
[2]->ptr
);
4016 int end
= atoi(c
->argv
[3]->ptr
);
4018 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4020 addReply(c
,shared
.nullmultibulk
);
4022 if (o
->type
!= REDIS_ZSET
) {
4023 addReply(c
,shared
.wrongtypeerr
);
4025 zset
*zsetobj
= o
->ptr
;
4026 zskiplist
*zsl
= zsetobj
->zsl
;
4029 int llen
= zsl
->length
;
4033 /* convert negative indexes */
4034 if (start
< 0) start
= llen
+start
;
4035 if (end
< 0) end
= llen
+end
;
4036 if (start
< 0) start
= 0;
4037 if (end
< 0) end
= 0;
4039 /* indexes sanity checks */
4040 if (start
> end
|| start
>= llen
) {
4041 /* Out of range start or start > end result in empty list */
4042 addReply(c
,shared
.emptymultibulk
);
4045 if (end
>= llen
) end
= llen
-1;
4046 rangelen
= (end
-start
)+1;
4048 /* Return the result in form of a multi-bulk reply */
4054 ln
= zsl
->header
->forward
[0];
4056 ln
= ln
->forward
[0];
4059 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",rangelen
));
4060 for (j
= 0; j
< rangelen
; j
++) {
4062 addReplyBulkLen(c
,ele
);
4064 addReply(c
,shared
.crlf
);
4065 ln
= reverse
? ln
->backward
: ln
->forward
[0];
4071 static void zrangeCommand(redisClient
*c
) {
4072 zrangeGenericCommand(c
,0);
4075 static void zrevrangeCommand(redisClient
*c
) {
4076 zrangeGenericCommand(c
,1);
4079 static void zlenCommand(redisClient
*c
) {
4083 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4085 addReply(c
,shared
.czero
);
4088 if (o
->type
!= REDIS_ZSET
) {
4089 addReply(c
,shared
.wrongtypeerr
);
4092 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",zs
->zsl
->length
));
4097 /* ========================= Non type-specific commands ==================== */
4099 static void flushdbCommand(redisClient
*c
) {
4100 server
.dirty
+= dictSize(c
->db
->dict
);
4101 dictEmpty(c
->db
->dict
);
4102 dictEmpty(c
->db
->expires
);
4103 addReply(c
,shared
.ok
);
4106 static void flushallCommand(redisClient
*c
) {
4107 server
.dirty
+= emptyDb();
4108 addReply(c
,shared
.ok
);
4109 rdbSave(server
.dbfilename
);
4113 static redisSortOperation
*createSortOperation(int type
, robj
*pattern
) {
4114 redisSortOperation
*so
= zmalloc(sizeof(*so
));
4116 so
->pattern
= pattern
;
4120 /* Return the value associated to the key with a name obtained
4121 * substituting the first occurence of '*' in 'pattern' with 'subst' */
4122 static robj
*lookupKeyByPattern(redisDb
*db
, robj
*pattern
, robj
*subst
) {
4126 int prefixlen
, sublen
, postfixlen
;
4127 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
4131 char buf
[REDIS_SORTKEY_MAX
+1];
4134 if (subst
->encoding
== REDIS_ENCODING_RAW
)
4135 incrRefCount(subst
);
4137 subst
= getDecodedObject(subst
);
4140 spat
= pattern
->ptr
;
4142 if (sdslen(spat
)+sdslen(ssub
)-1 > REDIS_SORTKEY_MAX
) return NULL
;
4143 p
= strchr(spat
,'*');
4144 if (!p
) return NULL
;
4147 sublen
= sdslen(ssub
);
4148 postfixlen
= sdslen(spat
)-(prefixlen
+1);
4149 memcpy(keyname
.buf
,spat
,prefixlen
);
4150 memcpy(keyname
.buf
+prefixlen
,ssub
,sublen
);
4151 memcpy(keyname
.buf
+prefixlen
+sublen
,p
+1,postfixlen
);
4152 keyname
.buf
[prefixlen
+sublen
+postfixlen
] = '\0';
4153 keyname
.len
= prefixlen
+sublen
+postfixlen
;
4155 keyobj
.refcount
= 1;
4156 keyobj
.type
= REDIS_STRING
;
4157 keyobj
.ptr
= ((char*)&keyname
)+(sizeof(long)*2);
4159 decrRefCount(subst
);
4161 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
4162 return lookupKeyRead(db
,&keyobj
);
4165 /* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
4166 * the additional parameter is not standard but a BSD-specific we have to
4167 * pass sorting parameters via the global 'server' structure */
4168 static int sortCompare(const void *s1
, const void *s2
) {
4169 const redisSortObject
*so1
= s1
, *so2
= s2
;
4172 if (!server
.sort_alpha
) {
4173 /* Numeric sorting. Here it's trivial as we precomputed scores */
4174 if (so1
->u
.score
> so2
->u
.score
) {
4176 } else if (so1
->u
.score
< so2
->u
.score
) {
4182 /* Alphanumeric sorting */
4183 if (server
.sort_bypattern
) {
4184 if (!so1
->u
.cmpobj
|| !so2
->u
.cmpobj
) {
4185 /* At least one compare object is NULL */
4186 if (so1
->u
.cmpobj
== so2
->u
.cmpobj
)
4188 else if (so1
->u
.cmpobj
== NULL
)
4193 /* We have both the objects, use strcoll */
4194 cmp
= strcoll(so1
->u
.cmpobj
->ptr
,so2
->u
.cmpobj
->ptr
);
4197 /* Compare elements directly */
4198 if (so1
->obj
->encoding
== REDIS_ENCODING_RAW
&&
4199 so2
->obj
->encoding
== REDIS_ENCODING_RAW
) {
4200 cmp
= strcoll(so1
->obj
->ptr
,so2
->obj
->ptr
);
4204 dec1
= so1
->obj
->encoding
== REDIS_ENCODING_RAW
?
4205 so1
->obj
: getDecodedObject(so1
->obj
);
4206 dec2
= so2
->obj
->encoding
== REDIS_ENCODING_RAW
?
4207 so2
->obj
: getDecodedObject(so2
->obj
);
4208 cmp
= strcoll(dec1
->ptr
,dec2
->ptr
);
4209 if (dec1
!= so1
->obj
) decrRefCount(dec1
);
4210 if (dec2
!= so2
->obj
) decrRefCount(dec2
);
4214 return server
.sort_desc
? -cmp
: cmp
;
4217 /* The SORT command is the most complex command in Redis. Warning: this code
4218 * is optimized for speed and a bit less for readability */
4219 static void sortCommand(redisClient
*c
) {
4222 int desc
= 0, alpha
= 0;
4223 int limit_start
= 0, limit_count
= -1, start
, end
;
4224 int j
, dontsort
= 0, vectorlen
;
4225 int getop
= 0; /* GET operation counter */
4226 robj
*sortval
, *sortby
= NULL
;
4227 redisSortObject
*vector
; /* Resulting vector to sort */
4229 /* Lookup the key to sort. It must be of the right types */
4230 sortval
= lookupKeyRead(c
->db
,c
->argv
[1]);
4231 if (sortval
== NULL
) {
4232 addReply(c
,shared
.nokeyerr
);
4235 if (sortval
->type
!= REDIS_SET
&& sortval
->type
!= REDIS_LIST
) {
4236 addReply(c
,shared
.wrongtypeerr
);
4240 /* Create a list of operations to perform for every sorted element.
4241 * Operations can be GET/DEL/INCR/DECR */
4242 operations
= listCreate();
4243 listSetFreeMethod(operations
,zfree
);
4246 /* Now we need to protect sortval incrementing its count, in the future
4247 * SORT may have options able to overwrite/delete keys during the sorting
4248 * and the sorted key itself may get destroied */
4249 incrRefCount(sortval
);
4251 /* The SORT command has an SQL-alike syntax, parse it */
4252 while(j
< c
->argc
) {
4253 int leftargs
= c
->argc
-j
-1;
4254 if (!strcasecmp(c
->argv
[j
]->ptr
,"asc")) {
4256 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"desc")) {
4258 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"alpha")) {
4260 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"limit") && leftargs
>= 2) {
4261 limit_start
= atoi(c
->argv
[j
+1]->ptr
);
4262 limit_count
= atoi(c
->argv
[j
+2]->ptr
);
4264 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"by") && leftargs
>= 1) {
4265 sortby
= c
->argv
[j
+1];
4266 /* If the BY pattern does not contain '*', i.e. it is constant,
4267 * we don't need to sort nor to lookup the weight keys. */
4268 if (strchr(c
->argv
[j
+1]->ptr
,'*') == NULL
) dontsort
= 1;
4270 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
4271 listAddNodeTail(operations
,createSortOperation(
4272 REDIS_SORT_GET
,c
->argv
[j
+1]));
4275 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"del") && leftargs
>= 1) {
4276 listAddNodeTail(operations
,createSortOperation(
4277 REDIS_SORT_DEL
,c
->argv
[j
+1]));
4279 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"incr") && leftargs
>= 1) {
4280 listAddNodeTail(operations
,createSortOperation(
4281 REDIS_SORT_INCR
,c
->argv
[j
+1]));
4283 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
4284 listAddNodeTail(operations
,createSortOperation(
4285 REDIS_SORT_DECR
,c
->argv
[j
+1]));
4288 decrRefCount(sortval
);
4289 listRelease(operations
);
4290 addReply(c
,shared
.syntaxerr
);
4296 /* Load the sorting vector with all the objects to sort */
4297 vectorlen
= (sortval
->type
== REDIS_LIST
) ?
4298 listLength((list
*)sortval
->ptr
) :
4299 dictSize((dict
*)sortval
->ptr
);
4300 vector
= zmalloc(sizeof(redisSortObject
)*vectorlen
);
4302 if (sortval
->type
== REDIS_LIST
) {
4303 list
*list
= sortval
->ptr
;
4307 while((ln
= listYield(list
))) {
4308 robj
*ele
= ln
->value
;
4309 vector
[j
].obj
= ele
;
4310 vector
[j
].u
.score
= 0;
4311 vector
[j
].u
.cmpobj
= NULL
;
4315 dict
*set
= sortval
->ptr
;
4319 di
= dictGetIterator(set
);
4320 while((setele
= dictNext(di
)) != NULL
) {
4321 vector
[j
].obj
= dictGetEntryKey(setele
);
4322 vector
[j
].u
.score
= 0;
4323 vector
[j
].u
.cmpobj
= NULL
;
4326 dictReleaseIterator(di
);
4328 assert(j
== vectorlen
);
4330 /* Now it's time to load the right scores in the sorting vector */
4331 if (dontsort
== 0) {
4332 for (j
= 0; j
< vectorlen
; j
++) {
4336 byval
= lookupKeyByPattern(c
->db
,sortby
,vector
[j
].obj
);
4337 if (!byval
|| byval
->type
!= REDIS_STRING
) continue;
4339 if (byval
->encoding
== REDIS_ENCODING_RAW
) {
4340 vector
[j
].u
.cmpobj
= byval
;
4341 incrRefCount(byval
);
4343 vector
[j
].u
.cmpobj
= getDecodedObject(byval
);
4346 if (byval
->encoding
== REDIS_ENCODING_RAW
) {
4347 vector
[j
].u
.score
= strtod(byval
->ptr
,NULL
);
4349 if (byval
->encoding
== REDIS_ENCODING_INT
) {
4350 vector
[j
].u
.score
= (long)byval
->ptr
;
4357 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_RAW
)
4358 vector
[j
].u
.score
= strtod(vector
[j
].obj
->ptr
,NULL
);
4360 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_INT
)
4361 vector
[j
].u
.score
= (long) vector
[j
].obj
->ptr
;
4370 /* We are ready to sort the vector... perform a bit of sanity check
4371 * on the LIMIT option too. We'll use a partial version of quicksort. */
4372 start
= (limit_start
< 0) ? 0 : limit_start
;
4373 end
= (limit_count
< 0) ? vectorlen
-1 : start
+limit_count
-1;
4374 if (start
>= vectorlen
) {
4375 start
= vectorlen
-1;
4378 if (end
>= vectorlen
) end
= vectorlen
-1;
4380 if (dontsort
== 0) {
4381 server
.sort_desc
= desc
;
4382 server
.sort_alpha
= alpha
;
4383 server
.sort_bypattern
= sortby
? 1 : 0;
4384 if (sortby
&& (start
!= 0 || end
!= vectorlen
-1))
4385 pqsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
, start
,end
);
4387 qsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
);
4390 /* Send command output to the output buffer, performing the specified
4391 * GET/DEL/INCR/DECR operations if any. */
4392 outputlen
= getop
? getop
*(end
-start
+1) : end
-start
+1;
4393 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",outputlen
));
4394 for (j
= start
; j
<= end
; j
++) {
4397 addReplyBulkLen(c
,vector
[j
].obj
);
4398 addReply(c
,vector
[j
].obj
);
4399 addReply(c
,shared
.crlf
);
4401 listRewind(operations
);
4402 while((ln
= listYield(operations
))) {
4403 redisSortOperation
*sop
= ln
->value
;
4404 robj
*val
= lookupKeyByPattern(c
->db
,sop
->pattern
,
4407 if (sop
->type
== REDIS_SORT_GET
) {
4408 if (!val
|| val
->type
!= REDIS_STRING
) {
4409 addReply(c
,shared
.nullbulk
);
4411 addReplyBulkLen(c
,val
);
4413 addReply(c
,shared
.crlf
);
4415 } else if (sop
->type
== REDIS_SORT_DEL
) {
4422 decrRefCount(sortval
);
4423 listRelease(operations
);
4424 for (j
= 0; j
< vectorlen
; j
++) {
4425 if (sortby
&& alpha
&& vector
[j
].u
.cmpobj
)
4426 decrRefCount(vector
[j
].u
.cmpobj
);
4431 static void infoCommand(redisClient
*c
) {
4433 time_t uptime
= time(NULL
)-server
.stat_starttime
;
4436 info
= sdscatprintf(sdsempty(),
4437 "redis_version:%s\r\n"
4439 "uptime_in_seconds:%d\r\n"
4440 "uptime_in_days:%d\r\n"
4441 "connected_clients:%d\r\n"
4442 "connected_slaves:%d\r\n"
4443 "used_memory:%zu\r\n"
4444 "changes_since_last_save:%lld\r\n"
4445 "bgsave_in_progress:%d\r\n"
4446 "last_save_time:%d\r\n"
4447 "total_connections_received:%lld\r\n"
4448 "total_commands_processed:%lld\r\n"
4451 (sizeof(long) == 8) ? "64" : "32",
4454 listLength(server
.clients
)-listLength(server
.slaves
),
4455 listLength(server
.slaves
),
4458 server
.bgsaveinprogress
,
4460 server
.stat_numconnections
,
4461 server
.stat_numcommands
,
4462 server
.masterhost
== NULL
? "master" : "slave"
4464 if (server
.masterhost
) {
4465 info
= sdscatprintf(info
,
4466 "master_host:%s\r\n"
4467 "master_port:%d\r\n"
4468 "master_link_status:%s\r\n"
4469 "master_last_io_seconds_ago:%d\r\n"
4472 (server
.replstate
== REDIS_REPL_CONNECTED
) ?
4474 (int)(time(NULL
)-server
.master
->lastinteraction
)
4477 for (j
= 0; j
< server
.dbnum
; j
++) {
4478 long long keys
, vkeys
;
4480 keys
= dictSize(server
.db
[j
].dict
);
4481 vkeys
= dictSize(server
.db
[j
].expires
);
4482 if (keys
|| vkeys
) {
4483 info
= sdscatprintf(info
, "db%d: keys=%lld,expires=%lld\r\n",
4487 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(info
)));
4488 addReplySds(c
,info
);
4489 addReply(c
,shared
.crlf
);
4492 static void monitorCommand(redisClient
*c
) {
4493 /* ignore MONITOR if aleady slave or in monitor mode */
4494 if (c
->flags
& REDIS_SLAVE
) return;
4496 c
->flags
|= (REDIS_SLAVE
|REDIS_MONITOR
);
4498 listAddNodeTail(server
.monitors
,c
);
4499 addReply(c
,shared
.ok
);
4502 /* ================================= Expire ================================= */
4503 static int removeExpire(redisDb
*db
, robj
*key
) {
4504 if (dictDelete(db
->expires
,key
) == DICT_OK
) {
4511 static int setExpire(redisDb
*db
, robj
*key
, time_t when
) {
4512 if (dictAdd(db
->expires
,key
,(void*)when
) == DICT_ERR
) {
4520 /* Return the expire time of the specified key, or -1 if no expire
4521 * is associated with this key (i.e. the key is non volatile) */
4522 static time_t getExpire(redisDb
*db
, robj
*key
) {
4525 /* No expire? return ASAP */
4526 if (dictSize(db
->expires
) == 0 ||
4527 (de
= dictFind(db
->expires
,key
)) == NULL
) return -1;
4529 return (time_t) dictGetEntryVal(de
);
4532 static int expireIfNeeded(redisDb
*db
, robj
*key
) {
4536 /* No expire? return ASAP */
4537 if (dictSize(db
->expires
) == 0 ||
4538 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
4540 /* Lookup the expire */
4541 when
= (time_t) dictGetEntryVal(de
);
4542 if (time(NULL
) <= when
) return 0;
4544 /* Delete the key */
4545 dictDelete(db
->expires
,key
);
4546 return dictDelete(db
->dict
,key
) == DICT_OK
;
4549 static int deleteIfVolatile(redisDb
*db
, robj
*key
) {
4552 /* No expire? return ASAP */
4553 if (dictSize(db
->expires
) == 0 ||
4554 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
4556 /* Delete the key */
4558 dictDelete(db
->expires
,key
);
4559 return dictDelete(db
->dict
,key
) == DICT_OK
;
4562 static void expireCommand(redisClient
*c
) {
4564 int seconds
= atoi(c
->argv
[2]->ptr
);
4566 de
= dictFind(c
->db
->dict
,c
->argv
[1]);
4568 addReply(c
,shared
.czero
);
4572 addReply(c
, shared
.czero
);
4575 time_t when
= time(NULL
)+seconds
;
4576 if (setExpire(c
->db
,c
->argv
[1],when
)) {
4577 addReply(c
,shared
.cone
);
4580 addReply(c
,shared
.czero
);
4586 static void ttlCommand(redisClient
*c
) {
4590 expire
= getExpire(c
->db
,c
->argv
[1]);
4592 ttl
= (int) (expire
-time(NULL
));
4593 if (ttl
< 0) ttl
= -1;
4595 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",ttl
));
4598 static void msetGenericCommand(redisClient
*c
, int nx
) {
4601 if ((c
->argc
% 2) == 0) {
4602 addReplySds(c
,sdsnew("-ERR wrong number of arguments\r\n"));
4605 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
4606 * set nothing at all if at least one already key exists. */
4608 for (j
= 1; j
< c
->argc
; j
+= 2) {
4609 if (dictFind(c
->db
->dict
,c
->argv
[j
]) != NULL
) {
4610 addReply(c
, shared
.czero
);
4616 for (j
= 1; j
< c
->argc
; j
+= 2) {
4619 retval
= dictAdd(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
4620 if (retval
== DICT_ERR
) {
4621 dictReplace(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
4622 incrRefCount(c
->argv
[j
+1]);
4624 incrRefCount(c
->argv
[j
]);
4625 incrRefCount(c
->argv
[j
+1]);
4627 removeExpire(c
->db
,c
->argv
[j
]);
4629 server
.dirty
+= (c
->argc
-1)/2;
4630 addReply(c
, nx
? shared
.cone
: shared
.ok
);
4633 static void msetCommand(redisClient
*c
) {
4634 msetGenericCommand(c
,0);
4637 static void msetnxCommand(redisClient
*c
) {
4638 msetGenericCommand(c
,1);
4641 /* =============================== Replication ============================= */
4643 static int syncWrite(int fd
, char *ptr
, ssize_t size
, int timeout
) {
4644 ssize_t nwritten
, ret
= size
;
4645 time_t start
= time(NULL
);
4649 if (aeWait(fd
,AE_WRITABLE
,1000) & AE_WRITABLE
) {
4650 nwritten
= write(fd
,ptr
,size
);
4651 if (nwritten
== -1) return -1;
4655 if ((time(NULL
)-start
) > timeout
) {
4663 static int syncRead(int fd
, char *ptr
, ssize_t size
, int timeout
) {
4664 ssize_t nread
, totread
= 0;
4665 time_t start
= time(NULL
);
4669 if (aeWait(fd
,AE_READABLE
,1000) & AE_READABLE
) {
4670 nread
= read(fd
,ptr
,size
);
4671 if (nread
== -1) return -1;
4676 if ((time(NULL
)-start
) > timeout
) {
4684 static int syncReadLine(int fd
, char *ptr
, ssize_t size
, int timeout
) {
4691 if (syncRead(fd
,&c
,1,timeout
) == -1) return -1;
4694 if (nread
&& *(ptr
-1) == '\r') *(ptr
-1) = '\0';
4705 static void syncCommand(redisClient
*c
) {
4706 /* ignore SYNC if aleady slave or in monitor mode */
4707 if (c
->flags
& REDIS_SLAVE
) return;
4709 /* SYNC can't be issued when the server has pending data to send to
4710 * the client about already issued commands. We need a fresh reply
4711 * buffer registering the differences between the BGSAVE and the current
4712 * dataset, so that we can copy to other slaves if needed. */
4713 if (listLength(c
->reply
) != 0) {
4714 addReplySds(c
,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
4718 redisLog(REDIS_NOTICE
,"Slave ask for synchronization");
4719 /* Here we need to check if there is a background saving operation
4720 * in progress, or if it is required to start one */
4721 if (server
.bgsaveinprogress
) {
4722 /* Ok a background save is in progress. Let's check if it is a good
4723 * one for replication, i.e. if there is another slave that is
4724 * registering differences since the server forked to save */
4728 listRewind(server
.slaves
);
4729 while((ln
= listYield(server
.slaves
))) {
4731 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) break;
4734 /* Perfect, the server is already registering differences for
4735 * another slave. Set the right state, and copy the buffer. */
4736 listRelease(c
->reply
);
4737 c
->reply
= listDup(slave
->reply
);
4738 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
4739 redisLog(REDIS_NOTICE
,"Waiting for end of BGSAVE for SYNC");
4741 /* No way, we need to wait for the next BGSAVE in order to
4742 * register differences */
4743 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
4744 redisLog(REDIS_NOTICE
,"Waiting for next BGSAVE for SYNC");
4747 /* Ok we don't have a BGSAVE in progress, let's start one */
4748 redisLog(REDIS_NOTICE
,"Starting BGSAVE for SYNC");
4749 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
4750 redisLog(REDIS_NOTICE
,"Replication failed, can't BGSAVE");
4751 addReplySds(c
,sdsnew("-ERR Unalbe to perform background save\r\n"));
4754 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
4757 c
->flags
|= REDIS_SLAVE
;
4759 listAddNodeTail(server
.slaves
,c
);
4763 static void sendBulkToSlave(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
4764 redisClient
*slave
= privdata
;
4766 REDIS_NOTUSED(mask
);
4767 char buf
[REDIS_IOBUF_LEN
];
4768 ssize_t nwritten
, buflen
;
4770 if (slave
->repldboff
== 0) {
4771 /* Write the bulk write count before to transfer the DB. In theory here
4772 * we don't know how much room there is in the output buffer of the
4773 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
4774 * operations) will never be smaller than the few bytes we need. */
4777 bulkcount
= sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
4779 if (write(fd
,bulkcount
,sdslen(bulkcount
)) != (signed)sdslen(bulkcount
))
4787 lseek(slave
->repldbfd
,slave
->repldboff
,SEEK_SET
);
4788 buflen
= read(slave
->repldbfd
,buf
,REDIS_IOBUF_LEN
);
4790 redisLog(REDIS_WARNING
,"Read error sending DB to slave: %s",
4791 (buflen
== 0) ? "premature EOF" : strerror(errno
));
4795 if ((nwritten
= write(fd
,buf
,buflen
)) == -1) {
4796 redisLog(REDIS_DEBUG
,"Write error sending DB to slave: %s",
4801 slave
->repldboff
+= nwritten
;
4802 if (slave
->repldboff
== slave
->repldbsize
) {
4803 close(slave
->repldbfd
);
4804 slave
->repldbfd
= -1;
4805 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
4806 slave
->replstate
= REDIS_REPL_ONLINE
;
4807 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
,
4808 sendReplyToClient
, slave
, NULL
) == AE_ERR
) {
4812 addReplySds(slave
,sdsempty());
4813 redisLog(REDIS_NOTICE
,"Synchronization with slave succeeded");
4817 /* This function is called at the end of every backgrond saving.
4818 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
4819 * otherwise REDIS_ERR is passed to the function.
4821 * The goal of this function is to handle slaves waiting for a successful
4822 * background saving in order to perform non-blocking synchronization. */
4823 static void updateSlavesWaitingBgsave(int bgsaveerr
) {
4825 int startbgsave
= 0;
4827 listRewind(server
.slaves
);
4828 while((ln
= listYield(server
.slaves
))) {
4829 redisClient
*slave
= ln
->value
;
4831 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) {
4833 slave
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
4834 } else if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) {
4835 struct redis_stat buf
;
4837 if (bgsaveerr
!= REDIS_OK
) {
4839 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE child returned an error");
4842 if ((slave
->repldbfd
= open(server
.dbfilename
,O_RDONLY
)) == -1 ||
4843 redis_fstat(slave
->repldbfd
,&buf
) == -1) {
4845 redisLog(REDIS_WARNING
,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno
));
4848 slave
->repldboff
= 0;
4849 slave
->repldbsize
= buf
.st_size
;
4850 slave
->replstate
= REDIS_REPL_SEND_BULK
;
4851 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
4852 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
, sendBulkToSlave
, slave
, NULL
) == AE_ERR
) {
4859 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
4860 listRewind(server
.slaves
);
4861 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE failed");
4862 while((ln
= listYield(server
.slaves
))) {
4863 redisClient
*slave
= ln
->value
;
4865 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
)
4872 static int syncWithMaster(void) {
4873 char buf
[1024], tmpfile
[256];
4875 int fd
= anetTcpConnect(NULL
,server
.masterhost
,server
.masterport
);
4879 redisLog(REDIS_WARNING
,"Unable to connect to MASTER: %s",
4883 /* Issue the SYNC command */
4884 if (syncWrite(fd
,"SYNC \r\n",7,5) == -1) {
4886 redisLog(REDIS_WARNING
,"I/O error writing to MASTER: %s",
4890 /* Read the bulk write count */
4891 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
4893 redisLog(REDIS_WARNING
,"I/O error reading bulk count from MASTER: %s",
4897 dumpsize
= atoi(buf
+1);
4898 redisLog(REDIS_NOTICE
,"Receiving %d bytes data dump from MASTER",dumpsize
);
4899 /* Read the bulk write data on a temp file */
4900 snprintf(tmpfile
,256,"temp-%d.%ld.rdb",(int)time(NULL
),(long int)random());
4901 dfd
= open(tmpfile
,O_CREAT
|O_WRONLY
,0644);
4904 redisLog(REDIS_WARNING
,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno
));
4908 int nread
, nwritten
;
4910 nread
= read(fd
,buf
,(dumpsize
< 1024)?dumpsize
:1024);
4912 redisLog(REDIS_WARNING
,"I/O error trying to sync with MASTER: %s",
4918 nwritten
= write(dfd
,buf
,nread
);
4919 if (nwritten
== -1) {
4920 redisLog(REDIS_WARNING
,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno
));
4928 if (rename(tmpfile
,server
.dbfilename
) == -1) {
4929 redisLog(REDIS_WARNING
,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno
));
4935 if (rdbLoad(server
.dbfilename
) != REDIS_OK
) {
4936 redisLog(REDIS_WARNING
,"Failed trying to load the MASTER synchronization DB from disk");
4940 server
.master
= createClient(fd
);
4941 server
.master
->flags
|= REDIS_MASTER
;
4942 server
.replstate
= REDIS_REPL_CONNECTED
;
4946 static void slaveofCommand(redisClient
*c
) {
4947 if (!strcasecmp(c
->argv
[1]->ptr
,"no") &&
4948 !strcasecmp(c
->argv
[2]->ptr
,"one")) {
4949 if (server
.masterhost
) {
4950 sdsfree(server
.masterhost
);
4951 server
.masterhost
= NULL
;
4952 if (server
.master
) freeClient(server
.master
);
4953 server
.replstate
= REDIS_REPL_NONE
;
4954 redisLog(REDIS_NOTICE
,"MASTER MODE enabled (user request)");
4957 sdsfree(server
.masterhost
);
4958 server
.masterhost
= sdsdup(c
->argv
[1]->ptr
);
4959 server
.masterport
= atoi(c
->argv
[2]->ptr
);
4960 if (server
.master
) freeClient(server
.master
);
4961 server
.replstate
= REDIS_REPL_CONNECT
;
4962 redisLog(REDIS_NOTICE
,"SLAVE OF %s:%d enabled (user request)",
4963 server
.masterhost
, server
.masterport
);
4965 addReply(c
,shared
.ok
);
4968 /* ============================ Maxmemory directive ======================== */
4970 /* This function gets called when 'maxmemory' is set on the config file to limit
4971 * the max memory used by the server, and we are out of memory.
4972 * This function will try to, in order:
4974 * - Free objects from the free list
4975 * - Try to remove keys with an EXPIRE set
4977 * It is not possible to free enough memory to reach used-memory < maxmemory
4978 * the server will start refusing commands that will enlarge even more the
4981 static void freeMemoryIfNeeded(void) {
4982 while (server
.maxmemory
&& zmalloc_used_memory() > server
.maxmemory
) {
4983 if (listLength(server
.objfreelist
)) {
4986 listNode
*head
= listFirst(server
.objfreelist
);
4987 o
= listNodeValue(head
);
4988 listDelNode(server
.objfreelist
,head
);
4991 int j
, k
, freed
= 0;
4993 for (j
= 0; j
< server
.dbnum
; j
++) {
4995 robj
*minkey
= NULL
;
4996 struct dictEntry
*de
;
4998 if (dictSize(server
.db
[j
].expires
)) {
5000 /* From a sample of three keys drop the one nearest to
5001 * the natural expire */
5002 for (k
= 0; k
< 3; k
++) {
5005 de
= dictGetRandomKey(server
.db
[j
].expires
);
5006 t
= (time_t) dictGetEntryVal(de
);
5007 if (minttl
== -1 || t
< minttl
) {
5008 minkey
= dictGetEntryKey(de
);
5012 deleteKey(server
.db
+j
,minkey
);
5015 if (!freed
) return; /* nothing to free... */
5020 /* ================================= Debugging ============================== */
5022 static void debugCommand(redisClient
*c
) {
5023 if (!strcasecmp(c
->argv
[1]->ptr
,"segfault")) {
5025 } else if (!strcasecmp(c
->argv
[1]->ptr
,"object") && c
->argc
== 3) {
5026 dictEntry
*de
= dictFind(c
->db
->dict
,c
->argv
[2]);
5030 addReply(c
,shared
.nokeyerr
);
5033 key
= dictGetEntryKey(de
);
5034 val
= dictGetEntryVal(de
);
5035 addReplySds(c
,sdscatprintf(sdsempty(),
5036 "+Key at:%p refcount:%d, value at:%p refcount:%d encoding:%d\r\n",
5037 key
, key
->refcount
, val
, val
->refcount
, val
->encoding
));
5039 addReplySds(c
,sdsnew(
5040 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>]\r\n"));
5044 #ifdef HAVE_BACKTRACE
5045 static struct redisFunctionSym symsTable
[] = {
5046 {"compareStringObjects", (unsigned long)compareStringObjects
},
5047 {"isStringRepresentableAsLong", (unsigned long)isStringRepresentableAsLong
},
5048 {"dictEncObjKeyCompare", (unsigned long)dictEncObjKeyCompare
},
5049 {"dictEncObjHash", (unsigned long)dictEncObjHash
},
5050 {"incrDecrCommand", (unsigned long)incrDecrCommand
},
5051 {"freeStringObject", (unsigned long)freeStringObject
},
5052 {"freeListObject", (unsigned long)freeListObject
},
5053 {"freeSetObject", (unsigned long)freeSetObject
},
5054 {"decrRefCount", (unsigned long)decrRefCount
},
5055 {"createObject", (unsigned long)createObject
},
5056 {"freeClient", (unsigned long)freeClient
},
5057 {"rdbLoad", (unsigned long)rdbLoad
},
5058 {"rdbSaveStringObject", (unsigned long)rdbSaveStringObject
},
5059 {"rdbSaveStringObjectRaw", (unsigned long)rdbSaveStringObjectRaw
},
5060 {"addReply", (unsigned long)addReply
},
5061 {"addReplySds", (unsigned long)addReplySds
},
5062 {"incrRefCount", (unsigned long)incrRefCount
},
5063 {"rdbSaveBackground", (unsigned long)rdbSaveBackground
},
5064 {"createStringObject", (unsigned long)createStringObject
},
5065 {"replicationFeedSlaves", (unsigned long)replicationFeedSlaves
},
5066 {"syncWithMaster", (unsigned long)syncWithMaster
},
5067 {"tryObjectSharing", (unsigned long)tryObjectSharing
},
5068 {"tryObjectEncoding", (unsigned long)tryObjectEncoding
},
5069 {"getDecodedObject", (unsigned long)getDecodedObject
},
5070 {"removeExpire", (unsigned long)removeExpire
},
5071 {"expireIfNeeded", (unsigned long)expireIfNeeded
},
5072 {"deleteIfVolatile", (unsigned long)deleteIfVolatile
},
5073 {"deleteKey", (unsigned long)deleteKey
},
5074 {"getExpire", (unsigned long)getExpire
},
5075 {"setExpire", (unsigned long)setExpire
},
5076 {"updateSlavesWaitingBgsave", (unsigned long)updateSlavesWaitingBgsave
},
5077 {"freeMemoryIfNeeded", (unsigned long)freeMemoryIfNeeded
},
5078 {"authCommand", (unsigned long)authCommand
},
5079 {"pingCommand", (unsigned long)pingCommand
},
5080 {"echoCommand", (unsigned long)echoCommand
},
5081 {"setCommand", (unsigned long)setCommand
},
5082 {"setnxCommand", (unsigned long)setnxCommand
},
5083 {"getCommand", (unsigned long)getCommand
},
5084 {"delCommand", (unsigned long)delCommand
},
5085 {"existsCommand", (unsigned long)existsCommand
},
5086 {"incrCommand", (unsigned long)incrCommand
},
5087 {"decrCommand", (unsigned long)decrCommand
},
5088 {"incrbyCommand", (unsigned long)incrbyCommand
},
5089 {"decrbyCommand", (unsigned long)decrbyCommand
},
5090 {"selectCommand", (unsigned long)selectCommand
},
5091 {"randomkeyCommand", (unsigned long)randomkeyCommand
},
5092 {"keysCommand", (unsigned long)keysCommand
},
5093 {"dbsizeCommand", (unsigned long)dbsizeCommand
},
5094 {"lastsaveCommand", (unsigned long)lastsaveCommand
},
5095 {"saveCommand", (unsigned long)saveCommand
},
5096 {"bgsaveCommand", (unsigned long)bgsaveCommand
},
5097 {"shutdownCommand", (unsigned long)shutdownCommand
},
5098 {"moveCommand", (unsigned long)moveCommand
},
5099 {"renameCommand", (unsigned long)renameCommand
},
5100 {"renamenxCommand", (unsigned long)renamenxCommand
},
5101 {"lpushCommand", (unsigned long)lpushCommand
},
5102 {"rpushCommand", (unsigned long)rpushCommand
},
5103 {"lpopCommand", (unsigned long)lpopCommand
},
5104 {"rpopCommand", (unsigned long)rpopCommand
},
5105 {"llenCommand", (unsigned long)llenCommand
},
5106 {"lindexCommand", (unsigned long)lindexCommand
},
5107 {"lrangeCommand", (unsigned long)lrangeCommand
},
5108 {"ltrimCommand", (unsigned long)ltrimCommand
},
5109 {"typeCommand", (unsigned long)typeCommand
},
5110 {"lsetCommand", (unsigned long)lsetCommand
},
5111 {"saddCommand", (unsigned long)saddCommand
},
5112 {"sremCommand", (unsigned long)sremCommand
},
5113 {"smoveCommand", (unsigned long)smoveCommand
},
5114 {"sismemberCommand", (unsigned long)sismemberCommand
},
5115 {"scardCommand", (unsigned long)scardCommand
},
5116 {"spopCommand", (unsigned long)spopCommand
},
5117 {"srandmemberCommand", (unsigned long)srandmemberCommand
},
5118 {"sinterCommand", (unsigned long)sinterCommand
},
5119 {"sinterstoreCommand", (unsigned long)sinterstoreCommand
},
5120 {"sunionCommand", (unsigned long)sunionCommand
},
5121 {"sunionstoreCommand", (unsigned long)sunionstoreCommand
},
5122 {"sdiffCommand", (unsigned long)sdiffCommand
},
5123 {"sdiffstoreCommand", (unsigned long)sdiffstoreCommand
},
5124 {"syncCommand", (unsigned long)syncCommand
},
5125 {"flushdbCommand", (unsigned long)flushdbCommand
},
5126 {"flushallCommand", (unsigned long)flushallCommand
},
5127 {"sortCommand", (unsigned long)sortCommand
},
5128 {"lremCommand", (unsigned long)lremCommand
},
5129 {"infoCommand", (unsigned long)infoCommand
},
5130 {"mgetCommand", (unsigned long)mgetCommand
},
5131 {"monitorCommand", (unsigned long)monitorCommand
},
5132 {"expireCommand", (unsigned long)expireCommand
},
5133 {"getsetCommand", (unsigned long)getsetCommand
},
5134 {"ttlCommand", (unsigned long)ttlCommand
},
5135 {"slaveofCommand", (unsigned long)slaveofCommand
},
5136 {"debugCommand", (unsigned long)debugCommand
},
5137 {"processCommand", (unsigned long)processCommand
},
5138 {"setupSigSegvAction", (unsigned long)setupSigSegvAction
},
5139 {"readQueryFromClient", (unsigned long)readQueryFromClient
},
5140 {"rdbRemoveTempFile", (unsigned long)rdbRemoveTempFile
},
5141 {"msetGenericCommand", (unsigned long)msetGenericCommand
},
5142 {"msetCommand", (unsigned long)msetCommand
},
5143 {"msetnxCommand", (unsigned long)msetnxCommand
},
5144 {"zslCreateNode", (unsigned long)zslCreateNode
},
5145 {"zslCreate", (unsigned long)zslCreate
},
5146 {"zslFreeNode",(unsigned long)zslFreeNode
},
5147 {"zslFree",(unsigned long)zslFree
},
5148 {"zslRandomLevel",(unsigned long)zslRandomLevel
},
5149 {"zslInsert",(unsigned long)zslInsert
},
5150 {"zslDelete",(unsigned long)zslDelete
},
5151 {"createZsetObject",(unsigned long)createZsetObject
},
5152 {"zaddCommand",(unsigned long)zaddCommand
},
5153 {"zrangeGenericCommand",(unsigned long)zrangeGenericCommand
},
5154 {"zrangeCommand",(unsigned long)zrangeCommand
},
5155 {"zrevrangeCommand",(unsigned long)zrevrangeCommand
},
5156 {"zremCommand",(unsigned long)zremCommand
},
5157 {"rdbSaveDoubleValue",(unsigned long)rdbSaveDoubleValue
},
5158 {"rdbLoadDoubleValue",(unsigned long)rdbLoadDoubleValue
},
5162 /* This function try to convert a pointer into a function name. It's used in
5163 * oreder to provide a backtrace under segmentation fault that's able to
5164 * display functions declared as static (otherwise the backtrace is useless). */
5165 static char *findFuncName(void *pointer
, unsigned long *offset
){
5167 unsigned long off
, minoff
= 0;
5169 /* Try to match against the Symbol with the smallest offset */
5170 for (i
=0; symsTable
[i
].pointer
; i
++) {
5171 unsigned long lp
= (unsigned long) pointer
;
5173 if (lp
!= (unsigned long)-1 && lp
>= symsTable
[i
].pointer
) {
5174 off
=lp
-symsTable
[i
].pointer
;
5175 if (ret
< 0 || off
< minoff
) {
5181 if (ret
== -1) return NULL
;
5183 return symsTable
[ret
].name
;
5186 static void *getMcontextEip(ucontext_t
*uc
) {
5187 #if defined(__FreeBSD__)
5188 return (void*) uc
->uc_mcontext
.mc_eip
;
5189 #elif defined(__dietlibc__)
5190 return (void*) uc
->uc_mcontext
.eip
;
5191 #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
5192 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
5193 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
5194 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
5195 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
5197 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
5199 #elif defined(__i386__) || defined(__X86_64__) /* Linux x86 */
5200 return (void*) uc
->uc_mcontext
.gregs
[REG_EIP
];
5201 #elif defined(__ia64__) /* Linux IA64 */
5202 return (void*) uc
->uc_mcontext
.sc_ip
;
5208 static void segvHandler(int sig
, siginfo_t
*info
, void *secret
) {
5210 char **messages
= NULL
;
5211 int i
, trace_size
= 0;
5212 unsigned long offset
=0;
5213 time_t uptime
= time(NULL
)-server
.stat_starttime
;
5214 ucontext_t
*uc
= (ucontext_t
*) secret
;
5215 REDIS_NOTUSED(info
);
5217 redisLog(REDIS_WARNING
,
5218 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION
, sig
);
5219 redisLog(REDIS_WARNING
, "%s", sdscatprintf(sdsempty(),
5220 "redis_version:%s; "
5221 "uptime_in_seconds:%d; "
5222 "connected_clients:%d; "
5223 "connected_slaves:%d; "
5225 "changes_since_last_save:%lld; "
5226 "bgsave_in_progress:%d; "
5227 "last_save_time:%d; "
5228 "total_connections_received:%lld; "
5229 "total_commands_processed:%lld; "
5233 listLength(server
.clients
)-listLength(server
.slaves
),
5234 listLength(server
.slaves
),
5237 server
.bgsaveinprogress
,
5239 server
.stat_numconnections
,
5240 server
.stat_numcommands
,
5241 server
.masterhost
== NULL
? "master" : "slave"
5244 trace_size
= backtrace(trace
, 100);
5245 /* overwrite sigaction with caller's address */
5246 if (getMcontextEip(uc
) != NULL
) {
5247 trace
[1] = getMcontextEip(uc
);
5249 messages
= backtrace_symbols(trace
, trace_size
);
5251 for (i
=1; i
<trace_size
; ++i
) {
5252 char *fn
= findFuncName(trace
[i
], &offset
), *p
;
5254 p
= strchr(messages
[i
],'+');
5255 if (!fn
|| (p
&& ((unsigned long)strtol(p
+1,NULL
,10)) < offset
)) {
5256 redisLog(REDIS_WARNING
,"%s", messages
[i
]);
5258 redisLog(REDIS_WARNING
,"%d redis-server %p %s + %d", i
, trace
[i
], fn
, (unsigned int)offset
);
5265 static void setupSigSegvAction(void) {
5266 struct sigaction act
;
5268 sigemptyset (&act
.sa_mask
);
5269 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
5270 * is used. Otherwise, sa_handler is used */
5271 act
.sa_flags
= SA_NODEFER
| SA_ONSTACK
| SA_RESETHAND
| SA_SIGINFO
;
5272 act
.sa_sigaction
= segvHandler
;
5273 sigaction (SIGSEGV
, &act
, NULL
);
5274 sigaction (SIGBUS
, &act
, NULL
);
5275 sigaction (SIGFPE
, &act
, NULL
);
5276 sigaction (SIGILL
, &act
, NULL
);
5277 sigaction (SIGBUS
, &act
, NULL
);
5280 #else /* HAVE_BACKTRACE */
5281 static void setupSigSegvAction(void) {
5283 #endif /* HAVE_BACKTRACE */
5285 /* =================================== Main! ================================ */
5288 int linuxOvercommitMemoryValue(void) {
5289 FILE *fp
= fopen("/proc/sys/vm/overcommit_memory","r");
5293 if (fgets(buf
,64,fp
) == NULL
) {
5302 void linuxOvercommitMemoryWarning(void) {
5303 if (linuxOvercommitMemoryValue() == 0) {
5304 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.");
5307 #endif /* __linux__ */
5309 static void daemonize(void) {
5313 if (fork() != 0) exit(0); /* parent exits */
5314 setsid(); /* create a new session */
5316 /* Every output goes to /dev/null. If Redis is daemonized but
5317 * the 'logfile' is set to 'stdout' in the configuration file
5318 * it will not log at all. */
5319 if ((fd
= open("/dev/null", O_RDWR
, 0)) != -1) {
5320 dup2(fd
, STDIN_FILENO
);
5321 dup2(fd
, STDOUT_FILENO
);
5322 dup2(fd
, STDERR_FILENO
);
5323 if (fd
> STDERR_FILENO
) close(fd
);
5325 /* Try to write the pid file */
5326 fp
= fopen(server
.pidfile
,"w");
5328 fprintf(fp
,"%d\n",getpid());
5333 int main(int argc
, char **argv
) {
5336 ResetServerSaveParams();
5337 loadServerConfig(argv
[1]);
5338 } else if (argc
> 2) {
5339 fprintf(stderr
,"Usage: ./redis-server [/path/to/redis.conf]\n");
5342 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'");
5345 if (server
.daemonize
) daemonize();
5346 redisLog(REDIS_NOTICE
,"Server started, Redis version " REDIS_VERSION
);
5348 linuxOvercommitMemoryWarning();
5350 if (rdbLoad(server
.dbfilename
) == REDIS_OK
)
5351 redisLog(REDIS_NOTICE
,"DB loaded from disk");
5352 if (aeCreateFileEvent(server
.el
, server
.fd
, AE_READABLE
,
5353 acceptHandler
, NULL
, NULL
) == AE_ERR
) oom("creating file event");
5354 redisLog(REDIS_NOTICE
,"The server is now ready to accept connections on port %d", server
.port
);
5356 aeDeleteEventLoop(server
.el
);