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>
64 #include "solarisfixes.h"
68 #include "ae.h" /* Event driven programming library */
69 #include "sds.h" /* Dynamic safe strings */
70 #include "anet.h" /* Networking the easy way */
71 #include "dict.h" /* Hash tables */
72 #include "adlist.h" /* Linked lists */
73 #include "zmalloc.h" /* total memory usage aware version of malloc/free */
74 #include "lzf.h" /* LZF compression library */
75 #include "pqsort.h" /* Partial qsort for SORT+LIMIT */
81 /* Static server configuration */
82 #define REDIS_SERVERPORT 6379 /* TCP port */
83 #define REDIS_MAXIDLETIME (60*5) /* default client timeout */
84 #define REDIS_IOBUF_LEN 1024
85 #define REDIS_LOADBUF_LEN 1024
86 #define REDIS_STATIC_ARGS 4
87 #define REDIS_DEFAULT_DBNUM 16
88 #define REDIS_CONFIGLINE_MAX 1024
89 #define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
90 #define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
91 #define REDIS_EXPIRELOOKUPS_PER_CRON 100 /* try to expire 100 keys/second */
92 #define REDIS_MAX_WRITE_PER_EVENT (1024*64)
93 #define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
95 /* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
96 #define REDIS_WRITEV_THRESHOLD 3
97 /* Max number of iovecs used for each writev call */
98 #define REDIS_WRITEV_IOVEC_COUNT 256
100 /* Hash table parameters */
101 #define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
104 #define REDIS_CMD_BULK 1 /* Bulk write command */
105 #define REDIS_CMD_INLINE 2 /* Inline command */
106 /* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
107 this flags will return an error when the 'maxmemory' option is set in the
108 config file and the server is using more than maxmemory bytes of memory.
109 In short this commands are denied on low memory conditions. */
110 #define REDIS_CMD_DENYOOM 4
113 #define REDIS_STRING 0
119 /* Objects encoding */
120 #define REDIS_ENCODING_RAW 0 /* Raw representation */
121 #define REDIS_ENCODING_INT 1 /* Encoded as integer */
123 /* Object types only used for dumping to disk */
124 #define REDIS_EXPIRETIME 253
125 #define REDIS_SELECTDB 254
126 #define REDIS_EOF 255
128 /* Defines related to the dump file format. To store 32 bits lengths for short
129 * keys requires a lot of space, so we check the most significant 2 bits of
130 * the first byte to interpreter the length:
132 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
133 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
134 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
135 * 11|000000 this means: specially encoded object will follow. The six bits
136 * number specify the kind of object that follows.
137 * See the REDIS_RDB_ENC_* defines.
139 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
140 * values, will fit inside. */
141 #define REDIS_RDB_6BITLEN 0
142 #define REDIS_RDB_14BITLEN 1
143 #define REDIS_RDB_32BITLEN 2
144 #define REDIS_RDB_ENCVAL 3
145 #define REDIS_RDB_LENERR UINT_MAX
147 /* When a length of a string object stored on disk has the first two bits
148 * set, the remaining two bits specify a special encoding for the object
149 * accordingly to the following defines: */
150 #define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
151 #define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
152 #define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
153 #define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
156 #define REDIS_CLOSE 1 /* This client connection should be closed ASAP */
157 #define REDIS_SLAVE 2 /* This client is a slave server */
158 #define REDIS_MASTER 4 /* This client is a master server */
159 #define REDIS_MONITOR 8 /* This client is a slave monitor, see MONITOR */
161 /* Slave replication state - slave side */
162 #define REDIS_REPL_NONE 0 /* No active replication */
163 #define REDIS_REPL_CONNECT 1 /* Must connect to master */
164 #define REDIS_REPL_CONNECTED 2 /* Connected to master */
166 /* Slave replication state - from the point of view of master
167 * Note that in SEND_BULK and ONLINE state the slave receives new updates
168 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
169 * to start the next background saving in order to send updates to it. */
170 #define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
171 #define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
172 #define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
173 #define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
175 /* List related stuff */
179 /* Sort operations */
180 #define REDIS_SORT_GET 0
181 #define REDIS_SORT_ASC 1
182 #define REDIS_SORT_DESC 2
183 #define REDIS_SORTKEY_MAX 1024
186 #define REDIS_DEBUG 0
187 #define REDIS_NOTICE 1
188 #define REDIS_WARNING 2
190 /* Anti-warning macro... */
191 #define REDIS_NOTUSED(V) ((void) V)
193 #define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
194 #define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
196 /* Append only defines */
197 #define APPENDFSYNC_NO 0
198 #define APPENDFSYNC_ALWAYS 1
199 #define APPENDFSYNC_EVERYSEC 2
201 /*================================= Data types ============================== */
203 /* A redis object, that is a type able to hold a string / list / set */
204 typedef struct redisObject
{
207 unsigned char encoding
;
208 unsigned char notused
[2];
212 typedef struct redisDb
{
218 /* With multiplexing we need to take per-clinet state.
219 * Clients are taken in a liked list. */
220 typedef struct redisClient
{
225 robj
**argv
, **mbargv
;
227 int bulklen
; /* bulk read len. -1 if not in bulk read mode */
228 int multibulk
; /* multi bulk command format active */
231 time_t lastinteraction
; /* time of the last interaction, used for timeout */
232 int flags
; /* REDIS_CLOSE | REDIS_SLAVE | REDIS_MONITOR */
233 int slaveseldb
; /* slave selected db, if this client is a slave */
234 int authenticated
; /* when requirepass is non-NULL */
235 int replstate
; /* replication state if this is a slave */
236 int repldbfd
; /* replication DB file descriptor */
237 long repldboff
; /* replication DB file offset */
238 off_t repldbsize
; /* replication DB file size */
246 /* Global server state structure */
252 unsigned int sharingpoolsize
;
253 long long dirty
; /* changes to DB from the last save */
255 list
*slaves
, *monitors
;
256 char neterr
[ANET_ERR_LEN
];
258 int cronloops
; /* number of times the cron function run */
259 list
*objfreelist
; /* A list of freed objects to avoid malloc() */
260 time_t lastsave
; /* Unix time of last save succeeede */
261 size_t usedmemory
; /* Used memory in megabytes */
262 /* Fields used only for stats */
263 time_t stat_starttime
; /* server start time */
264 long long stat_numcommands
; /* number of processed commands */
265 long long stat_numconnections
; /* number of connections received */
278 int bgsaveinprogress
;
279 pid_t bgsavechildpid
;
280 struct saveparam
*saveparams
;
285 char *appendfilename
;
288 /* Replication related */
293 redisClient
*master
; /* client that is master for this slave */
295 unsigned int maxclients
;
296 unsigned long maxmemory
;
297 /* Sort parameters - qsort_r() is only available under BSD so we
298 * have to take this state global, in order to pass it to sortCompare() */
304 typedef void redisCommandProc(redisClient
*c
);
305 struct redisCommand
{
307 redisCommandProc
*proc
;
312 struct redisFunctionSym
{
314 unsigned long pointer
;
317 typedef struct _redisSortObject
{
325 typedef struct _redisSortOperation
{
328 } redisSortOperation
;
330 /* ZSETs use a specialized version of Skiplists */
332 typedef struct zskiplistNode
{
333 struct zskiplistNode
**forward
;
334 struct zskiplistNode
*backward
;
339 typedef struct zskiplist
{
340 struct zskiplistNode
*header
, *tail
;
341 unsigned long length
;
345 typedef struct zset
{
350 /* Our shared "common" objects */
352 struct sharedObjectsStruct
{
353 robj
*crlf
, *ok
, *err
, *emptybulk
, *czero
, *cone
, *pong
, *space
,
354 *colon
, *nullbulk
, *nullmultibulk
,
355 *emptymultibulk
, *wrongtypeerr
, *nokeyerr
, *syntaxerr
, *sameobjecterr
,
356 *outofrangeerr
, *plus
,
357 *select0
, *select1
, *select2
, *select3
, *select4
,
358 *select5
, *select6
, *select7
, *select8
, *select9
;
361 /* Global vars that are actally used as constants. The following double
362 * values are used for double on-disk serialization, and are initialized
363 * at runtime to avoid strange compiler optimizations. */
365 static double R_Zero
, R_PosInf
, R_NegInf
, R_Nan
;
367 /*================================ Prototypes =============================== */
369 static void freeStringObject(robj
*o
);
370 static void freeListObject(robj
*o
);
371 static void freeSetObject(robj
*o
);
372 static void decrRefCount(void *o
);
373 static robj
*createObject(int type
, void *ptr
);
374 static void freeClient(redisClient
*c
);
375 static int rdbLoad(char *filename
);
376 static void addReply(redisClient
*c
, robj
*obj
);
377 static void addReplySds(redisClient
*c
, sds s
);
378 static void incrRefCount(robj
*o
);
379 static int rdbSaveBackground(char *filename
);
380 static robj
*createStringObject(char *ptr
, size_t len
);
381 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
);
382 static void feedAppendOnlyFile(struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
);
383 static int syncWithMaster(void);
384 static robj
*tryObjectSharing(robj
*o
);
385 static int tryObjectEncoding(robj
*o
);
386 static robj
*getDecodedObject(const robj
*o
);
387 static int removeExpire(redisDb
*db
, robj
*key
);
388 static int expireIfNeeded(redisDb
*db
, robj
*key
);
389 static int deleteIfVolatile(redisDb
*db
, robj
*key
);
390 static int deleteKey(redisDb
*db
, robj
*key
);
391 static time_t getExpire(redisDb
*db
, robj
*key
);
392 static int setExpire(redisDb
*db
, robj
*key
, time_t when
);
393 static void updateSlavesWaitingBgsave(int bgsaveerr
);
394 static void freeMemoryIfNeeded(void);
395 static int processCommand(redisClient
*c
);
396 static void setupSigSegvAction(void);
397 static void rdbRemoveTempFile(pid_t childpid
);
398 static size_t stringObjectLen(robj
*o
);
399 static void processInputBuffer(redisClient
*c
);
400 static zskiplist
*zslCreate(void);
401 static void zslFree(zskiplist
*zsl
);
402 static void zslInsert(zskiplist
*zsl
, double score
, robj
*obj
);
403 static void sendReplyToClientWritev(aeEventLoop
*el
, int fd
, void *privdata
, int mask
);
405 static void authCommand(redisClient
*c
);
406 static void pingCommand(redisClient
*c
);
407 static void echoCommand(redisClient
*c
);
408 static void setCommand(redisClient
*c
);
409 static void setnxCommand(redisClient
*c
);
410 static void getCommand(redisClient
*c
);
411 static void delCommand(redisClient
*c
);
412 static void existsCommand(redisClient
*c
);
413 static void incrCommand(redisClient
*c
);
414 static void decrCommand(redisClient
*c
);
415 static void incrbyCommand(redisClient
*c
);
416 static void decrbyCommand(redisClient
*c
);
417 static void selectCommand(redisClient
*c
);
418 static void randomkeyCommand(redisClient
*c
);
419 static void keysCommand(redisClient
*c
);
420 static void dbsizeCommand(redisClient
*c
);
421 static void lastsaveCommand(redisClient
*c
);
422 static void saveCommand(redisClient
*c
);
423 static void bgsaveCommand(redisClient
*c
);
424 static void shutdownCommand(redisClient
*c
);
425 static void moveCommand(redisClient
*c
);
426 static void renameCommand(redisClient
*c
);
427 static void renamenxCommand(redisClient
*c
);
428 static void lpushCommand(redisClient
*c
);
429 static void rpushCommand(redisClient
*c
);
430 static void lpopCommand(redisClient
*c
);
431 static void rpopCommand(redisClient
*c
);
432 static void llenCommand(redisClient
*c
);
433 static void lindexCommand(redisClient
*c
);
434 static void lrangeCommand(redisClient
*c
);
435 static void ltrimCommand(redisClient
*c
);
436 static void typeCommand(redisClient
*c
);
437 static void lsetCommand(redisClient
*c
);
438 static void saddCommand(redisClient
*c
);
439 static void sremCommand(redisClient
*c
);
440 static void smoveCommand(redisClient
*c
);
441 static void sismemberCommand(redisClient
*c
);
442 static void scardCommand(redisClient
*c
);
443 static void spopCommand(redisClient
*c
);
444 static void srandmemberCommand(redisClient
*c
);
445 static void sinterCommand(redisClient
*c
);
446 static void sinterstoreCommand(redisClient
*c
);
447 static void sunionCommand(redisClient
*c
);
448 static void sunionstoreCommand(redisClient
*c
);
449 static void sdiffCommand(redisClient
*c
);
450 static void sdiffstoreCommand(redisClient
*c
);
451 static void syncCommand(redisClient
*c
);
452 static void flushdbCommand(redisClient
*c
);
453 static void flushallCommand(redisClient
*c
);
454 static void sortCommand(redisClient
*c
);
455 static void lremCommand(redisClient
*c
);
456 static void rpoplpushcommand(redisClient
*c
);
457 static void infoCommand(redisClient
*c
);
458 static void mgetCommand(redisClient
*c
);
459 static void monitorCommand(redisClient
*c
);
460 static void expireCommand(redisClient
*c
);
461 static void expireatCommand(redisClient
*c
);
462 static void getsetCommand(redisClient
*c
);
463 static void ttlCommand(redisClient
*c
);
464 static void slaveofCommand(redisClient
*c
);
465 static void debugCommand(redisClient
*c
);
466 static void msetCommand(redisClient
*c
);
467 static void msetnxCommand(redisClient
*c
);
468 static void zaddCommand(redisClient
*c
);
469 static void zrangeCommand(redisClient
*c
);
470 static void zrangebyscoreCommand(redisClient
*c
);
471 static void zrevrangeCommand(redisClient
*c
);
472 static void zcardCommand(redisClient
*c
);
473 static void zremCommand(redisClient
*c
);
474 static void zscoreCommand(redisClient
*c
);
475 static void zremrangebyscoreCommand(redisClient
*c
);
477 /*================================= Globals ================================= */
480 static struct redisServer server
; /* server global state */
481 static struct redisCommand cmdTable
[] = {
482 {"get",getCommand
,2,REDIS_CMD_INLINE
},
483 {"set",setCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
484 {"setnx",setnxCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
485 {"del",delCommand
,-2,REDIS_CMD_INLINE
},
486 {"exists",existsCommand
,2,REDIS_CMD_INLINE
},
487 {"incr",incrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
488 {"decr",decrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
489 {"mget",mgetCommand
,-2,REDIS_CMD_INLINE
},
490 {"rpush",rpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
491 {"lpush",lpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
492 {"rpop",rpopCommand
,2,REDIS_CMD_INLINE
},
493 {"lpop",lpopCommand
,2,REDIS_CMD_INLINE
},
494 {"llen",llenCommand
,2,REDIS_CMD_INLINE
},
495 {"lindex",lindexCommand
,3,REDIS_CMD_INLINE
},
496 {"lset",lsetCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
497 {"lrange",lrangeCommand
,4,REDIS_CMD_INLINE
},
498 {"ltrim",ltrimCommand
,4,REDIS_CMD_INLINE
},
499 {"lrem",lremCommand
,4,REDIS_CMD_BULK
},
500 {"rpoplpush",rpoplpushcommand
,3,REDIS_CMD_BULK
},
501 {"sadd",saddCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
502 {"srem",sremCommand
,3,REDIS_CMD_BULK
},
503 {"smove",smoveCommand
,4,REDIS_CMD_BULK
},
504 {"sismember",sismemberCommand
,3,REDIS_CMD_BULK
},
505 {"scard",scardCommand
,2,REDIS_CMD_INLINE
},
506 {"spop",spopCommand
,2,REDIS_CMD_INLINE
},
507 {"srandmember",srandmemberCommand
,2,REDIS_CMD_INLINE
},
508 {"sinter",sinterCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
509 {"sinterstore",sinterstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
510 {"sunion",sunionCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
511 {"sunionstore",sunionstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
512 {"sdiff",sdiffCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
513 {"sdiffstore",sdiffstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
514 {"smembers",sinterCommand
,2,REDIS_CMD_INLINE
},
515 {"zadd",zaddCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
516 {"zrem",zremCommand
,3,REDIS_CMD_BULK
},
517 {"zremrangebyscore",zremrangebyscoreCommand
,4,REDIS_CMD_INLINE
},
518 {"zrange",zrangeCommand
,4,REDIS_CMD_INLINE
},
519 {"zrangebyscore",zrangebyscoreCommand
,4,REDIS_CMD_INLINE
},
520 {"zrevrange",zrevrangeCommand
,4,REDIS_CMD_INLINE
},
521 {"zcard",zcardCommand
,2,REDIS_CMD_INLINE
},
522 {"zscore",zscoreCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
523 {"incrby",incrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
524 {"decrby",decrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
525 {"getset",getsetCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
526 {"mset",msetCommand
,-3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
527 {"msetnx",msetnxCommand
,-3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
528 {"randomkey",randomkeyCommand
,1,REDIS_CMD_INLINE
},
529 {"select",selectCommand
,2,REDIS_CMD_INLINE
},
530 {"move",moveCommand
,3,REDIS_CMD_INLINE
},
531 {"rename",renameCommand
,3,REDIS_CMD_INLINE
},
532 {"renamenx",renamenxCommand
,3,REDIS_CMD_INLINE
},
533 {"expire",expireCommand
,3,REDIS_CMD_INLINE
},
534 {"expireat",expireatCommand
,3,REDIS_CMD_INLINE
},
535 {"keys",keysCommand
,2,REDIS_CMD_INLINE
},
536 {"dbsize",dbsizeCommand
,1,REDIS_CMD_INLINE
},
537 {"auth",authCommand
,2,REDIS_CMD_INLINE
},
538 {"ping",pingCommand
,1,REDIS_CMD_INLINE
},
539 {"echo",echoCommand
,2,REDIS_CMD_BULK
},
540 {"save",saveCommand
,1,REDIS_CMD_INLINE
},
541 {"bgsave",bgsaveCommand
,1,REDIS_CMD_INLINE
},
542 {"shutdown",shutdownCommand
,1,REDIS_CMD_INLINE
},
543 {"lastsave",lastsaveCommand
,1,REDIS_CMD_INLINE
},
544 {"type",typeCommand
,2,REDIS_CMD_INLINE
},
545 {"sync",syncCommand
,1,REDIS_CMD_INLINE
},
546 {"flushdb",flushdbCommand
,1,REDIS_CMD_INLINE
},
547 {"flushall",flushallCommand
,1,REDIS_CMD_INLINE
},
548 {"sort",sortCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
549 {"info",infoCommand
,1,REDIS_CMD_INLINE
},
550 {"monitor",monitorCommand
,1,REDIS_CMD_INLINE
},
551 {"ttl",ttlCommand
,2,REDIS_CMD_INLINE
},
552 {"slaveof",slaveofCommand
,3,REDIS_CMD_INLINE
},
553 {"debug",debugCommand
,-2,REDIS_CMD_INLINE
},
557 /*============================ Utility functions ============================ */
559 /* Glob-style pattern matching. */
560 int stringmatchlen(const char *pattern
, int patternLen
,
561 const char *string
, int stringLen
, int nocase
)
566 while (pattern
[1] == '*') {
571 return 1; /* match */
573 if (stringmatchlen(pattern
+1, patternLen
-1,
574 string
, stringLen
, nocase
))
575 return 1; /* match */
579 return 0; /* no match */
583 return 0; /* no match */
593 not = pattern
[0] == '^';
600 if (pattern
[0] == '\\') {
603 if (pattern
[0] == string
[0])
605 } else if (pattern
[0] == ']') {
607 } else if (patternLen
== 0) {
611 } else if (pattern
[1] == '-' && patternLen
>= 3) {
612 int start
= pattern
[0];
613 int end
= pattern
[2];
621 start
= tolower(start
);
627 if (c
>= start
&& c
<= end
)
631 if (pattern
[0] == string
[0])
634 if (tolower((int)pattern
[0]) == tolower((int)string
[0]))
644 return 0; /* no match */
650 if (patternLen
>= 2) {
657 if (pattern
[0] != string
[0])
658 return 0; /* no match */
660 if (tolower((int)pattern
[0]) != tolower((int)string
[0]))
661 return 0; /* no match */
669 if (stringLen
== 0) {
670 while(*pattern
== '*') {
677 if (patternLen
== 0 && stringLen
== 0)
682 static void redisLog(int level
, const char *fmt
, ...) {
686 fp
= (server
.logfile
== NULL
) ? stdout
: fopen(server
.logfile
,"a");
690 if (level
>= server
.verbosity
) {
696 strftime(buf
,64,"%d %b %H:%M:%S",localtime(&now
));
697 fprintf(fp
,"%s %c ",buf
,c
[level
]);
698 vfprintf(fp
, fmt
, ap
);
704 if (server
.logfile
) fclose(fp
);
707 /*====================== Hash table type implementation ==================== */
709 /* This is an hash table type that uses the SDS dynamic strings libary as
710 * keys and radis objects as values (objects can hold SDS strings,
713 static void dictVanillaFree(void *privdata
, void *val
)
715 DICT_NOTUSED(privdata
);
719 static int sdsDictKeyCompare(void *privdata
, const void *key1
,
723 DICT_NOTUSED(privdata
);
725 l1
= sdslen((sds
)key1
);
726 l2
= sdslen((sds
)key2
);
727 if (l1
!= l2
) return 0;
728 return memcmp(key1
, key2
, l1
) == 0;
731 static void dictRedisObjectDestructor(void *privdata
, void *val
)
733 DICT_NOTUSED(privdata
);
738 static int dictObjKeyCompare(void *privdata
, const void *key1
,
741 const robj
*o1
= key1
, *o2
= key2
;
742 return sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
745 static unsigned int dictObjHash(const void *key
) {
747 return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
750 static int dictEncObjKeyCompare(void *privdata
, const void *key1
,
753 const robj
*o1
= key1
, *o2
= key2
;
755 if (o1
->encoding
== REDIS_ENCODING_RAW
&&
756 o2
->encoding
== REDIS_ENCODING_RAW
)
757 return sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
762 dec1
= o1
->encoding
!= REDIS_ENCODING_RAW
?
763 getDecodedObject(o1
) : (robj
*)o1
;
764 dec2
= o2
->encoding
!= REDIS_ENCODING_RAW
?
765 getDecodedObject(o2
) : (robj
*)o2
;
766 cmp
= sdsDictKeyCompare(privdata
,dec1
->ptr
,dec2
->ptr
);
767 if (dec1
!= o1
) decrRefCount(dec1
);
768 if (dec2
!= o2
) decrRefCount(dec2
);
773 static unsigned int dictEncObjHash(const void *key
) {
776 if (o
->encoding
== REDIS_ENCODING_RAW
)
777 return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
779 robj
*dec
= getDecodedObject(o
);
780 unsigned int hash
= dictGenHashFunction(dec
->ptr
, sdslen((sds
)dec
->ptr
));
786 static dictType setDictType
= {
787 dictEncObjHash
, /* hash function */
790 dictEncObjKeyCompare
, /* key compare */
791 dictRedisObjectDestructor
, /* key destructor */
792 NULL
/* val destructor */
795 static dictType zsetDictType
= {
796 dictEncObjHash
, /* hash function */
799 dictEncObjKeyCompare
, /* key compare */
800 dictRedisObjectDestructor
, /* key destructor */
801 dictVanillaFree
/* val destructor */
804 static dictType hashDictType
= {
805 dictObjHash
, /* hash function */
808 dictObjKeyCompare
, /* key compare */
809 dictRedisObjectDestructor
, /* key destructor */
810 dictRedisObjectDestructor
/* val destructor */
813 /* ========================= Random utility functions ======================= */
815 /* Redis generally does not try to recover from out of memory conditions
816 * when allocating objects or strings, it is not clear if it will be possible
817 * to report this condition to the client since the networking layer itself
818 * is based on heap allocation for send buffers, so we simply abort.
819 * At least the code will be simpler to read... */
820 static void oom(const char *msg
) {
821 fprintf(stderr
, "%s: Out of memory\n",msg
);
827 /* ====================== Redis server networking stuff ===================== */
828 static void closeTimedoutClients(void) {
831 time_t now
= time(NULL
);
833 listRewind(server
.clients
);
834 while ((ln
= listYield(server
.clients
)) != NULL
) {
835 c
= listNodeValue(ln
);
836 if (!(c
->flags
& REDIS_SLAVE
) && /* no timeout for slaves */
837 !(c
->flags
& REDIS_MASTER
) && /* no timeout for masters */
838 (now
- c
->lastinteraction
> server
.maxidletime
)) {
839 redisLog(REDIS_DEBUG
,"Closing idle client");
845 static int htNeedsResize(dict
*dict
) {
846 long long size
, used
;
848 size
= dictSlots(dict
);
849 used
= dictSize(dict
);
850 return (size
&& used
&& size
> DICT_HT_INITIAL_SIZE
&&
851 (used
*100/size
< REDIS_HT_MINFILL
));
854 /* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
855 * we resize the hash table to save memory */
856 static void tryResizeHashTables(void) {
859 for (j
= 0; j
< server
.dbnum
; j
++) {
860 if (htNeedsResize(server
.db
[j
].dict
)) {
861 redisLog(REDIS_DEBUG
,"The hash table %d is too sparse, resize it...",j
);
862 dictResize(server
.db
[j
].dict
);
863 redisLog(REDIS_DEBUG
,"Hash table %d resized.",j
);
865 if (htNeedsResize(server
.db
[j
].expires
))
866 dictResize(server
.db
[j
].expires
);
870 static int serverCron(struct aeEventLoop
*eventLoop
, long long id
, void *clientData
) {
871 int j
, loops
= server
.cronloops
++;
872 REDIS_NOTUSED(eventLoop
);
874 REDIS_NOTUSED(clientData
);
876 /* Update the global state with the amount of used memory */
877 server
.usedmemory
= zmalloc_used_memory();
879 /* Show some info about non-empty databases */
880 for (j
= 0; j
< server
.dbnum
; j
++) {
881 long long size
, used
, vkeys
;
883 size
= dictSlots(server
.db
[j
].dict
);
884 used
= dictSize(server
.db
[j
].dict
);
885 vkeys
= dictSize(server
.db
[j
].expires
);
886 if (!(loops
% 5) && (used
|| vkeys
)) {
887 redisLog(REDIS_DEBUG
,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j
,used
,vkeys
,size
);
888 /* dictPrintStats(server.dict); */
892 /* We don't want to resize the hash tables while a bacground saving
893 * is in progress: the saving child is created using fork() that is
894 * implemented with a copy-on-write semantic in most modern systems, so
895 * if we resize the HT while there is the saving child at work actually
896 * a lot of memory movements in the parent will cause a lot of pages
898 if (!server
.bgsaveinprogress
) tryResizeHashTables();
900 /* Show information about connected clients */
902 redisLog(REDIS_DEBUG
,"%d clients connected (%d slaves), %zu bytes in use, %d shared objects",
903 listLength(server
.clients
)-listLength(server
.slaves
),
904 listLength(server
.slaves
),
906 dictSize(server
.sharingpool
));
909 /* Close connections of timedout clients */
910 if (server
.maxidletime
&& !(loops
% 10))
911 closeTimedoutClients();
913 /* Check if a background saving in progress terminated */
914 if (server
.bgsaveinprogress
) {
916 if (wait3(&statloc
,WNOHANG
,NULL
)) {
917 int exitcode
= WEXITSTATUS(statloc
);
918 int bysignal
= WIFSIGNALED(statloc
);
920 if (!bysignal
&& exitcode
== 0) {
921 redisLog(REDIS_NOTICE
,
922 "Background saving terminated with success");
924 server
.lastsave
= time(NULL
);
925 } else if (!bysignal
&& exitcode
!= 0) {
926 redisLog(REDIS_WARNING
, "Background saving error");
928 redisLog(REDIS_WARNING
,
929 "Background saving terminated by signal");
930 rdbRemoveTempFile(server
.bgsavechildpid
);
932 server
.bgsaveinprogress
= 0;
933 server
.bgsavechildpid
= -1;
934 updateSlavesWaitingBgsave(exitcode
== 0 ? REDIS_OK
: REDIS_ERR
);
937 /* If there is not a background saving in progress check if
938 * we have to save now */
939 time_t now
= time(NULL
);
940 for (j
= 0; j
< server
.saveparamslen
; j
++) {
941 struct saveparam
*sp
= server
.saveparams
+j
;
943 if (server
.dirty
>= sp
->changes
&&
944 now
-server
.lastsave
> sp
->seconds
) {
945 redisLog(REDIS_NOTICE
,"%d changes in %d seconds. Saving...",
946 sp
->changes
, sp
->seconds
);
947 rdbSaveBackground(server
.dbfilename
);
953 /* Try to expire a few timed out keys. The algorithm used is adaptive and
954 * will use few CPU cycles if there are few expiring keys, otherwise
955 * it will get more aggressive to avoid that too much memory is used by
956 * keys that can be removed from the keyspace. */
957 for (j
= 0; j
< server
.dbnum
; j
++) {
959 redisDb
*db
= server
.db
+j
;
961 /* Continue to expire if at the end of the cycle more than 25%
962 * of the keys were expired. */
964 int num
= dictSize(db
->expires
);
965 time_t now
= time(NULL
);
968 if (num
> REDIS_EXPIRELOOKUPS_PER_CRON
)
969 num
= REDIS_EXPIRELOOKUPS_PER_CRON
;
974 if ((de
= dictGetRandomKey(db
->expires
)) == NULL
) break;
975 t
= (time_t) dictGetEntryVal(de
);
977 deleteKey(db
,dictGetEntryKey(de
));
981 } while (expired
> REDIS_EXPIRELOOKUPS_PER_CRON
/4);
984 /* Check if we should connect to a MASTER */
985 if (server
.replstate
== REDIS_REPL_CONNECT
) {
986 redisLog(REDIS_NOTICE
,"Connecting to MASTER...");
987 if (syncWithMaster() == REDIS_OK
) {
988 redisLog(REDIS_NOTICE
,"MASTER <-> SLAVE sync succeeded");
994 static void createSharedObjects(void) {
995 shared
.crlf
= createObject(REDIS_STRING
,sdsnew("\r\n"));
996 shared
.ok
= createObject(REDIS_STRING
,sdsnew("+OK\r\n"));
997 shared
.err
= createObject(REDIS_STRING
,sdsnew("-ERR\r\n"));
998 shared
.emptybulk
= createObject(REDIS_STRING
,sdsnew("$0\r\n\r\n"));
999 shared
.czero
= createObject(REDIS_STRING
,sdsnew(":0\r\n"));
1000 shared
.cone
= createObject(REDIS_STRING
,sdsnew(":1\r\n"));
1001 shared
.nullbulk
= createObject(REDIS_STRING
,sdsnew("$-1\r\n"));
1002 shared
.nullmultibulk
= createObject(REDIS_STRING
,sdsnew("*-1\r\n"));
1003 shared
.emptymultibulk
= createObject(REDIS_STRING
,sdsnew("*0\r\n"));
1005 shared
.pong
= createObject(REDIS_STRING
,sdsnew("+PONG\r\n"));
1006 shared
.wrongtypeerr
= createObject(REDIS_STRING
,sdsnew(
1007 "-ERR Operation against a key holding the wrong kind of value\r\n"));
1008 shared
.nokeyerr
= createObject(REDIS_STRING
,sdsnew(
1009 "-ERR no such key\r\n"));
1010 shared
.syntaxerr
= createObject(REDIS_STRING
,sdsnew(
1011 "-ERR syntax error\r\n"));
1012 shared
.sameobjecterr
= createObject(REDIS_STRING
,sdsnew(
1013 "-ERR source and destination objects are the same\r\n"));
1014 shared
.outofrangeerr
= createObject(REDIS_STRING
,sdsnew(
1015 "-ERR index out of range\r\n"));
1016 shared
.space
= createObject(REDIS_STRING
,sdsnew(" "));
1017 shared
.colon
= createObject(REDIS_STRING
,sdsnew(":"));
1018 shared
.plus
= createObject(REDIS_STRING
,sdsnew("+"));
1019 shared
.select0
= createStringObject("select 0\r\n",10);
1020 shared
.select1
= createStringObject("select 1\r\n",10);
1021 shared
.select2
= createStringObject("select 2\r\n",10);
1022 shared
.select3
= createStringObject("select 3\r\n",10);
1023 shared
.select4
= createStringObject("select 4\r\n",10);
1024 shared
.select5
= createStringObject("select 5\r\n",10);
1025 shared
.select6
= createStringObject("select 6\r\n",10);
1026 shared
.select7
= createStringObject("select 7\r\n",10);
1027 shared
.select8
= createStringObject("select 8\r\n",10);
1028 shared
.select9
= createStringObject("select 9\r\n",10);
1031 static void appendServerSaveParams(time_t seconds
, int changes
) {
1032 server
.saveparams
= zrealloc(server
.saveparams
,sizeof(struct saveparam
)*(server
.saveparamslen
+1));
1033 server
.saveparams
[server
.saveparamslen
].seconds
= seconds
;
1034 server
.saveparams
[server
.saveparamslen
].changes
= changes
;
1035 server
.saveparamslen
++;
1038 static void resetServerSaveParams() {
1039 zfree(server
.saveparams
);
1040 server
.saveparams
= NULL
;
1041 server
.saveparamslen
= 0;
1044 static void initServerConfig() {
1045 server
.dbnum
= REDIS_DEFAULT_DBNUM
;
1046 server
.port
= REDIS_SERVERPORT
;
1047 server
.verbosity
= REDIS_DEBUG
;
1048 server
.maxidletime
= REDIS_MAXIDLETIME
;
1049 server
.saveparams
= NULL
;
1050 server
.logfile
= NULL
; /* NULL = log on standard output */
1051 server
.bindaddr
= NULL
;
1052 server
.glueoutputbuf
= 1;
1053 server
.daemonize
= 0;
1054 server
.appendonly
= 0;
1055 server
.appendfsync
= APPENDFSYNC_ALWAYS
;
1056 server
.lastfsync
= time(NULL
);
1057 server
.appendfd
= -1;
1058 server
.appendseldb
= -1; /* Make sure the first time will not match */
1059 server
.pidfile
= "/var/run/redis.pid";
1060 server
.dbfilename
= "dump.rdb";
1061 server
.appendfilename
= "appendonly.log";
1062 server
.requirepass
= NULL
;
1063 server
.shareobjects
= 0;
1064 server
.sharingpoolsize
= 1024;
1065 server
.maxclients
= 0;
1066 server
.maxmemory
= 0;
1067 resetServerSaveParams();
1069 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
1070 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
1071 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1072 /* Replication related */
1074 server
.masterauth
= NULL
;
1075 server
.masterhost
= NULL
;
1076 server
.masterport
= 6379;
1077 server
.master
= NULL
;
1078 server
.replstate
= REDIS_REPL_NONE
;
1080 /* Double constants initialization */
1082 R_PosInf
= 1.0/R_Zero
;
1083 R_NegInf
= -1.0/R_Zero
;
1084 R_Nan
= R_Zero
/R_Zero
;
1087 static void initServer() {
1090 signal(SIGHUP
, SIG_IGN
);
1091 signal(SIGPIPE
, SIG_IGN
);
1092 setupSigSegvAction();
1094 server
.clients
= listCreate();
1095 server
.slaves
= listCreate();
1096 server
.monitors
= listCreate();
1097 server
.objfreelist
= listCreate();
1098 createSharedObjects();
1099 server
.el
= aeCreateEventLoop();
1100 server
.db
= zmalloc(sizeof(redisDb
)*server
.dbnum
);
1101 server
.sharingpool
= dictCreate(&setDictType
,NULL
);
1102 server
.fd
= anetTcpServer(server
.neterr
, server
.port
, server
.bindaddr
);
1103 if (server
.fd
== -1) {
1104 redisLog(REDIS_WARNING
, "Opening TCP port: %s", server
.neterr
);
1107 for (j
= 0; j
< server
.dbnum
; j
++) {
1108 server
.db
[j
].dict
= dictCreate(&hashDictType
,NULL
);
1109 server
.db
[j
].expires
= dictCreate(&setDictType
,NULL
);
1110 server
.db
[j
].id
= j
;
1112 server
.cronloops
= 0;
1113 server
.bgsaveinprogress
= 0;
1114 server
.bgsavechildpid
= -1;
1115 server
.lastsave
= time(NULL
);
1117 server
.usedmemory
= 0;
1118 server
.stat_numcommands
= 0;
1119 server
.stat_numconnections
= 0;
1120 server
.stat_starttime
= time(NULL
);
1121 aeCreateTimeEvent(server
.el
, 1, serverCron
, NULL
, NULL
);
1123 if (server
.appendonly
) {
1124 server
.appendfd
= open(server
.appendfilename
,O_WRONLY
|O_APPEND
|O_CREAT
,0644);
1125 if (server
.appendfd
== -1) {
1126 redisLog(REDIS_WARNING
, "Can't open the append-only file: %s",
1133 /* Empty the whole database */
1134 static long long emptyDb() {
1136 long long removed
= 0;
1138 for (j
= 0; j
< server
.dbnum
; j
++) {
1139 removed
+= dictSize(server
.db
[j
].dict
);
1140 dictEmpty(server
.db
[j
].dict
);
1141 dictEmpty(server
.db
[j
].expires
);
1146 static int yesnotoi(char *s
) {
1147 if (!strcasecmp(s
,"yes")) return 1;
1148 else if (!strcasecmp(s
,"no")) return 0;
1152 /* I agree, this is a very rudimental way to load a configuration...
1153 will improve later if the config gets more complex */
1154 static void loadServerConfig(char *filename
) {
1156 char buf
[REDIS_CONFIGLINE_MAX
+1], *err
= NULL
;
1160 if (filename
[0] == '-' && filename
[1] == '\0')
1163 if ((fp
= fopen(filename
,"r")) == NULL
) {
1164 redisLog(REDIS_WARNING
,"Fatal error, can't open config file");
1169 while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) {
1175 line
= sdstrim(line
," \t\r\n");
1177 /* Skip comments and blank lines*/
1178 if (line
[0] == '#' || line
[0] == '\0') {
1183 /* Split into arguments */
1184 argv
= sdssplitlen(line
,sdslen(line
)," ",1,&argc
);
1185 sdstolower(argv
[0]);
1187 /* Execute config directives */
1188 if (!strcasecmp(argv
[0],"timeout") && argc
== 2) {
1189 server
.maxidletime
= atoi(argv
[1]);
1190 if (server
.maxidletime
< 0) {
1191 err
= "Invalid timeout value"; goto loaderr
;
1193 } else if (!strcasecmp(argv
[0],"port") && argc
== 2) {
1194 server
.port
= atoi(argv
[1]);
1195 if (server
.port
< 1 || server
.port
> 65535) {
1196 err
= "Invalid port"; goto loaderr
;
1198 } else if (!strcasecmp(argv
[0],"bind") && argc
== 2) {
1199 server
.bindaddr
= zstrdup(argv
[1]);
1200 } else if (!strcasecmp(argv
[0],"save") && argc
== 3) {
1201 int seconds
= atoi(argv
[1]);
1202 int changes
= atoi(argv
[2]);
1203 if (seconds
< 1 || changes
< 0) {
1204 err
= "Invalid save parameters"; goto loaderr
;
1206 appendServerSaveParams(seconds
,changes
);
1207 } else if (!strcasecmp(argv
[0],"dir") && argc
== 2) {
1208 if (chdir(argv
[1]) == -1) {
1209 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s",
1210 argv
[1], strerror(errno
));
1213 } else if (!strcasecmp(argv
[0],"loglevel") && argc
== 2) {
1214 if (!strcasecmp(argv
[1],"debug")) server
.verbosity
= REDIS_DEBUG
;
1215 else if (!strcasecmp(argv
[1],"notice")) server
.verbosity
= REDIS_NOTICE
;
1216 else if (!strcasecmp(argv
[1],"warning")) server
.verbosity
= REDIS_WARNING
;
1218 err
= "Invalid log level. Must be one of debug, notice, warning";
1221 } else if (!strcasecmp(argv
[0],"logfile") && argc
== 2) {
1224 server
.logfile
= zstrdup(argv
[1]);
1225 if (!strcasecmp(server
.logfile
,"stdout")) {
1226 zfree(server
.logfile
);
1227 server
.logfile
= NULL
;
1229 if (server
.logfile
) {
1230 /* Test if we are able to open the file. The server will not
1231 * be able to abort just for this problem later... */
1232 logfp
= fopen(server
.logfile
,"a");
1233 if (logfp
== NULL
) {
1234 err
= sdscatprintf(sdsempty(),
1235 "Can't open the log file: %s", strerror(errno
));
1240 } else if (!strcasecmp(argv
[0],"databases") && argc
== 2) {
1241 server
.dbnum
= atoi(argv
[1]);
1242 if (server
.dbnum
< 1) {
1243 err
= "Invalid number of databases"; goto loaderr
;
1245 } else if (!strcasecmp(argv
[0],"maxclients") && argc
== 2) {
1246 server
.maxclients
= atoi(argv
[1]);
1247 } else if (!strcasecmp(argv
[0],"maxmemory") && argc
== 2) {
1248 server
.maxmemory
= strtoll(argv
[1], NULL
, 10);
1249 } else if (!strcasecmp(argv
[0],"slaveof") && argc
== 3) {
1250 server
.masterhost
= sdsnew(argv
[1]);
1251 server
.masterport
= atoi(argv
[2]);
1252 server
.replstate
= REDIS_REPL_CONNECT
;
1253 } else if (!strcasecmp(argv
[0],"masterauth") && argc
== 2) {
1254 server
.masterauth
= zstrdup(argv
[1]);
1255 } else if (!strcasecmp(argv
[0],"glueoutputbuf") && argc
== 2) {
1256 if ((server
.glueoutputbuf
= yesnotoi(argv
[1])) == -1) {
1257 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1259 } else if (!strcasecmp(argv
[0],"shareobjects") && argc
== 2) {
1260 if ((server
.shareobjects
= yesnotoi(argv
[1])) == -1) {
1261 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1263 } else if (!strcasecmp(argv
[0],"shareobjectspoolsize") && argc
== 2) {
1264 server
.sharingpoolsize
= atoi(argv
[1]);
1265 if (server
.sharingpoolsize
< 1) {
1266 err
= "invalid object sharing pool size"; goto loaderr
;
1268 } else if (!strcasecmp(argv
[0],"daemonize") && argc
== 2) {
1269 if ((server
.daemonize
= yesnotoi(argv
[1])) == -1) {
1270 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1272 } else if (!strcasecmp(argv
[0],"appendonly") && argc
== 2) {
1273 if ((server
.appendonly
= yesnotoi(argv
[1])) == -1) {
1274 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1276 } else if (!strcasecmp(argv
[0],"appendfsync") && argc
== 2) {
1277 if (!strcasecmp(argv
[1],"no")) {
1278 server
.appendfsync
= APPENDFSYNC_NO
;
1279 } else if (!strcasecmp(argv
[1],"always")) {
1280 server
.appendfsync
= APPENDFSYNC_ALWAYS
;
1281 } else if (!strcasecmp(argv
[1],"everysec")) {
1282 server
.appendfsync
= APPENDFSYNC_EVERYSEC
;
1284 err
= "argument must be 'no', 'always' or 'everysec'";
1287 } else if (!strcasecmp(argv
[0],"requirepass") && argc
== 2) {
1288 server
.requirepass
= zstrdup(argv
[1]);
1289 } else if (!strcasecmp(argv
[0],"pidfile") && argc
== 2) {
1290 server
.pidfile
= zstrdup(argv
[1]);
1291 } else if (!strcasecmp(argv
[0],"dbfilename") && argc
== 2) {
1292 server
.dbfilename
= zstrdup(argv
[1]);
1294 err
= "Bad directive or wrong number of arguments"; goto loaderr
;
1296 for (j
= 0; j
< argc
; j
++)
1301 if (fp
!= stdin
) fclose(fp
);
1305 fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n");
1306 fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
);
1307 fprintf(stderr
, ">>> '%s'\n", line
);
1308 fprintf(stderr
, "%s\n", err
);
1312 static void freeClientArgv(redisClient
*c
) {
1315 for (j
= 0; j
< c
->argc
; j
++)
1316 decrRefCount(c
->argv
[j
]);
1317 for (j
= 0; j
< c
->mbargc
; j
++)
1318 decrRefCount(c
->mbargv
[j
]);
1323 static void freeClient(redisClient
*c
) {
1326 aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
);
1327 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1328 sdsfree(c
->querybuf
);
1329 listRelease(c
->reply
);
1332 ln
= listSearchKey(server
.clients
,c
);
1334 listDelNode(server
.clients
,ln
);
1335 if (c
->flags
& REDIS_SLAVE
) {
1336 if (c
->replstate
== REDIS_REPL_SEND_BULK
&& c
->repldbfd
!= -1)
1338 list
*l
= (c
->flags
& REDIS_MONITOR
) ? server
.monitors
: server
.slaves
;
1339 ln
= listSearchKey(l
,c
);
1343 if (c
->flags
& REDIS_MASTER
) {
1344 server
.master
= NULL
;
1345 server
.replstate
= REDIS_REPL_CONNECT
;
1352 #define GLUEREPLY_UP_TO (1024)
1353 static void glueReplyBuffersIfNeeded(redisClient
*c
) {
1355 char buf
[GLUEREPLY_UP_TO
];
1359 listRewind(c
->reply
);
1360 while((ln
= listYield(c
->reply
))) {
1364 objlen
= sdslen(o
->ptr
);
1365 if (copylen
+ objlen
<= GLUEREPLY_UP_TO
) {
1366 memcpy(buf
+copylen
,o
->ptr
,objlen
);
1368 listDelNode(c
->reply
,ln
);
1370 if (copylen
== 0) return;
1374 /* Now the output buffer is empty, add the new single element */
1375 o
= createObject(REDIS_STRING
,sdsnewlen(buf
,copylen
));
1376 listAddNodeHead(c
->reply
,o
);
1379 static void sendReplyToClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1380 redisClient
*c
= privdata
;
1381 int nwritten
= 0, totwritten
= 0, objlen
;
1384 REDIS_NOTUSED(mask
);
1387 /* Use writev() if we have enough buffers to send */
1388 if (!server
.glueoutputbuf
&&
1389 listLength(c
->reply
) > REDIS_WRITEV_THRESHOLD
&&
1390 !(c
->flags
& REDIS_MASTER
))
1392 sendReplyToClientWritev(el
, fd
, privdata
, mask
);
1396 while(listLength(c
->reply
)) {
1397 if (server
.glueoutputbuf
&& listLength(c
->reply
) > 1)
1398 glueReplyBuffersIfNeeded(c
);
1400 o
= listNodeValue(listFirst(c
->reply
));
1401 objlen
= sdslen(o
->ptr
);
1404 listDelNode(c
->reply
,listFirst(c
->reply
));
1408 if (c
->flags
& REDIS_MASTER
) {
1409 /* Don't reply to a master */
1410 nwritten
= objlen
- c
->sentlen
;
1412 nwritten
= write(fd
, ((char*)o
->ptr
)+c
->sentlen
, objlen
- c
->sentlen
);
1413 if (nwritten
<= 0) break;
1415 c
->sentlen
+= nwritten
;
1416 totwritten
+= nwritten
;
1417 /* If we fully sent the object on head go to the next one */
1418 if (c
->sentlen
== objlen
) {
1419 listDelNode(c
->reply
,listFirst(c
->reply
));
1422 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
1423 * bytes, in a single threaded server it's a good idea to serve
1424 * other clients as well, even if a very large request comes from
1425 * super fast link that is always able to accept data (in real world
1426 * scenario think about 'KEYS *' against the loopback interfae) */
1427 if (totwritten
> REDIS_MAX_WRITE_PER_EVENT
) break;
1429 if (nwritten
== -1) {
1430 if (errno
== EAGAIN
) {
1433 redisLog(REDIS_DEBUG
,
1434 "Error writing to client: %s", strerror(errno
));
1439 if (totwritten
> 0) c
->lastinteraction
= time(NULL
);
1440 if (listLength(c
->reply
) == 0) {
1442 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1446 static void sendReplyToClientWritev(aeEventLoop
*el
, int fd
, void *privdata
, int mask
)
1448 redisClient
*c
= privdata
;
1449 int nwritten
= 0, totwritten
= 0, objlen
, willwrite
;
1451 struct iovec iov
[REDIS_WRITEV_IOVEC_COUNT
];
1452 int offset
, ion
= 0;
1454 REDIS_NOTUSED(mask
);
1457 while (listLength(c
->reply
)) {
1458 offset
= c
->sentlen
;
1462 /* fill-in the iov[] array */
1463 for(node
= listFirst(c
->reply
); node
; node
= listNextNode(node
)) {
1464 o
= listNodeValue(node
);
1465 objlen
= sdslen(o
->ptr
);
1467 if (totwritten
+ objlen
- offset
> REDIS_MAX_WRITE_PER_EVENT
)
1470 if(ion
== REDIS_WRITEV_IOVEC_COUNT
)
1471 break; /* no more iovecs */
1473 iov
[ion
].iov_base
= ((char*)o
->ptr
) + offset
;
1474 iov
[ion
].iov_len
= objlen
- offset
;
1475 willwrite
+= objlen
- offset
;
1476 offset
= 0; /* just for the first item */
1483 /* write all collected blocks at once */
1484 if((nwritten
= writev(fd
, iov
, ion
)) < 0) {
1485 if (errno
!= EAGAIN
) {
1486 redisLog(REDIS_DEBUG
,
1487 "Error writing to client: %s", strerror(errno
));
1494 totwritten
+= nwritten
;
1495 offset
= c
->sentlen
;
1497 /* remove written robjs from c->reply */
1498 while (nwritten
&& listLength(c
->reply
)) {
1499 o
= listNodeValue(listFirst(c
->reply
));
1500 objlen
= sdslen(o
->ptr
);
1502 if(nwritten
>= objlen
- offset
) {
1503 listDelNode(c
->reply
, listFirst(c
->reply
));
1504 nwritten
-= objlen
- offset
;
1508 c
->sentlen
+= nwritten
;
1516 c
->lastinteraction
= time(NULL
);
1518 if (listLength(c
->reply
) == 0) {
1520 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1524 static struct redisCommand
*lookupCommand(char *name
) {
1526 while(cmdTable
[j
].name
!= NULL
) {
1527 if (!strcasecmp(name
,cmdTable
[j
].name
)) return &cmdTable
[j
];
1533 /* resetClient prepare the client to process the next command */
1534 static void resetClient(redisClient
*c
) {
1540 /* If this function gets called we already read a whole
1541 * command, argments are in the client argv/argc fields.
1542 * processCommand() execute the command or prepare the
1543 * server for a bulk read from the client.
1545 * If 1 is returned the client is still alive and valid and
1546 * and other operations can be performed by the caller. Otherwise
1547 * if 0 is returned the client was destroied (i.e. after QUIT). */
1548 static int processCommand(redisClient
*c
) {
1549 struct redisCommand
*cmd
;
1552 /* Free some memory if needed (maxmemory setting) */
1553 if (server
.maxmemory
) freeMemoryIfNeeded();
1555 /* Handle the multi bulk command type. This is an alternative protocol
1556 * supported by Redis in order to receive commands that are composed of
1557 * multiple binary-safe "bulk" arguments. The latency of processing is
1558 * a bit higher but this allows things like multi-sets, so if this
1559 * protocol is used only for MSET and similar commands this is a big win. */
1560 if (c
->multibulk
== 0 && c
->argc
== 1 && ((char*)(c
->argv
[0]->ptr
))[0] == '*') {
1561 c
->multibulk
= atoi(((char*)c
->argv
[0]->ptr
)+1);
1562 if (c
->multibulk
<= 0) {
1566 decrRefCount(c
->argv
[c
->argc
-1]);
1570 } else if (c
->multibulk
) {
1571 if (c
->bulklen
== -1) {
1572 if (((char*)c
->argv
[0]->ptr
)[0] != '$') {
1573 addReplySds(c
,sdsnew("-ERR multi bulk protocol error\r\n"));
1577 int bulklen
= atoi(((char*)c
->argv
[0]->ptr
)+1);
1578 decrRefCount(c
->argv
[0]);
1579 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
1581 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
1586 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
1590 c
->mbargv
= zrealloc(c
->mbargv
,(sizeof(robj
*))*(c
->mbargc
+1));
1591 c
->mbargv
[c
->mbargc
] = c
->argv
[0];
1595 if (c
->multibulk
== 0) {
1599 /* Here we need to swap the multi-bulk argc/argv with the
1600 * normal argc/argv of the client structure. */
1602 c
->argv
= c
->mbargv
;
1603 c
->mbargv
= auxargv
;
1606 c
->argc
= c
->mbargc
;
1607 c
->mbargc
= auxargc
;
1609 /* We need to set bulklen to something different than -1
1610 * in order for the code below to process the command without
1611 * to try to read the last argument of a bulk command as
1612 * a special argument. */
1614 /* continue below and process the command */
1621 /* -- end of multi bulk commands processing -- */
1623 /* The QUIT command is handled as a special case. Normal command
1624 * procs are unable to close the client connection safely */
1625 if (!strcasecmp(c
->argv
[0]->ptr
,"quit")) {
1629 cmd
= lookupCommand(c
->argv
[0]->ptr
);
1631 addReplySds(c
,sdsnew("-ERR unknown command\r\n"));
1634 } else if ((cmd
->arity
> 0 && cmd
->arity
!= c
->argc
) ||
1635 (c
->argc
< -cmd
->arity
)) {
1636 addReplySds(c
,sdsnew("-ERR wrong number of arguments\r\n"));
1639 } else if (server
.maxmemory
&& cmd
->flags
& REDIS_CMD_DENYOOM
&& zmalloc_used_memory() > server
.maxmemory
) {
1640 addReplySds(c
,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
1643 } else if (cmd
->flags
& REDIS_CMD_BULK
&& c
->bulklen
== -1) {
1644 int bulklen
= atoi(c
->argv
[c
->argc
-1]->ptr
);
1646 decrRefCount(c
->argv
[c
->argc
-1]);
1647 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
1649 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
1654 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
1655 /* It is possible that the bulk read is already in the
1656 * buffer. Check this condition and handle it accordingly.
1657 * This is just a fast path, alternative to call processInputBuffer().
1658 * It's a good idea since the code is small and this condition
1659 * happens most of the times. */
1660 if ((signed)sdslen(c
->querybuf
) >= c
->bulklen
) {
1661 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
1663 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
1668 /* Let's try to share objects on the command arguments vector */
1669 if (server
.shareobjects
) {
1671 for(j
= 1; j
< c
->argc
; j
++)
1672 c
->argv
[j
] = tryObjectSharing(c
->argv
[j
]);
1674 /* Let's try to encode the bulk object to save space. */
1675 if (cmd
->flags
& REDIS_CMD_BULK
)
1676 tryObjectEncoding(c
->argv
[c
->argc
-1]);
1678 /* Check if the user is authenticated */
1679 if (server
.requirepass
&& !c
->authenticated
&& cmd
->proc
!= authCommand
) {
1680 addReplySds(c
,sdsnew("-ERR operation not permitted\r\n"));
1685 /* Exec the command */
1686 dirty
= server
.dirty
;
1688 if (server
.appendonly
&& server
.dirty
-dirty
)
1689 feedAppendOnlyFile(cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1690 if (server
.dirty
-dirty
&& listLength(server
.slaves
))
1691 replicationFeedSlaves(server
.slaves
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1692 if (listLength(server
.monitors
))
1693 replicationFeedSlaves(server
.monitors
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1694 server
.stat_numcommands
++;
1696 /* Prepare the client for the next command */
1697 if (c
->flags
& REDIS_CLOSE
) {
1705 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
) {
1709 /* (args*2)+1 is enough room for args, spaces, newlines */
1710 robj
*static_outv
[REDIS_STATIC_ARGS
*2+1];
1712 if (argc
<= REDIS_STATIC_ARGS
) {
1715 outv
= zmalloc(sizeof(robj
*)*(argc
*2+1));
1718 for (j
= 0; j
< argc
; j
++) {
1719 if (j
!= 0) outv
[outc
++] = shared
.space
;
1720 if ((cmd
->flags
& REDIS_CMD_BULK
) && j
== argc
-1) {
1723 lenobj
= createObject(REDIS_STRING
,
1724 sdscatprintf(sdsempty(),"%d\r\n",
1725 stringObjectLen(argv
[j
])));
1726 lenobj
->refcount
= 0;
1727 outv
[outc
++] = lenobj
;
1729 outv
[outc
++] = argv
[j
];
1731 outv
[outc
++] = shared
.crlf
;
1733 /* Increment all the refcounts at start and decrement at end in order to
1734 * be sure to free objects if there is no slave in a replication state
1735 * able to be feed with commands */
1736 for (j
= 0; j
< outc
; j
++) incrRefCount(outv
[j
]);
1738 while((ln
= listYield(slaves
))) {
1739 redisClient
*slave
= ln
->value
;
1741 /* Don't feed slaves that are still waiting for BGSAVE to start */
1742 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) continue;
1744 /* Feed all the other slaves, MONITORs and so on */
1745 if (slave
->slaveseldb
!= dictid
) {
1749 case 0: selectcmd
= shared
.select0
; break;
1750 case 1: selectcmd
= shared
.select1
; break;
1751 case 2: selectcmd
= shared
.select2
; break;
1752 case 3: selectcmd
= shared
.select3
; break;
1753 case 4: selectcmd
= shared
.select4
; break;
1754 case 5: selectcmd
= shared
.select5
; break;
1755 case 6: selectcmd
= shared
.select6
; break;
1756 case 7: selectcmd
= shared
.select7
; break;
1757 case 8: selectcmd
= shared
.select8
; break;
1758 case 9: selectcmd
= shared
.select9
; break;
1760 selectcmd
= createObject(REDIS_STRING
,
1761 sdscatprintf(sdsempty(),"select %d\r\n",dictid
));
1762 selectcmd
->refcount
= 0;
1765 addReply(slave
,selectcmd
);
1766 slave
->slaveseldb
= dictid
;
1768 for (j
= 0; j
< outc
; j
++) addReply(slave
,outv
[j
]);
1770 for (j
= 0; j
< outc
; j
++) decrRefCount(outv
[j
]);
1771 if (outv
!= static_outv
) zfree(outv
);
1774 static void processInputBuffer(redisClient
*c
) {
1776 if (c
->bulklen
== -1) {
1777 /* Read the first line of the query */
1778 char *p
= strchr(c
->querybuf
,'\n');
1785 query
= c
->querybuf
;
1786 c
->querybuf
= sdsempty();
1787 querylen
= 1+(p
-(query
));
1788 if (sdslen(query
) > querylen
) {
1789 /* leave data after the first line of the query in the buffer */
1790 c
->querybuf
= sdscatlen(c
->querybuf
,query
+querylen
,sdslen(query
)-querylen
);
1792 *p
= '\0'; /* remove "\n" */
1793 if (*(p
-1) == '\r') *(p
-1) = '\0'; /* and "\r" if any */
1794 sdsupdatelen(query
);
1796 /* Now we can split the query in arguments */
1797 if (sdslen(query
) == 0) {
1798 /* Ignore empty query */
1802 argv
= sdssplitlen(query
,sdslen(query
)," ",1,&argc
);
1805 if (c
->argv
) zfree(c
->argv
);
1806 c
->argv
= zmalloc(sizeof(robj
*)*argc
);
1808 for (j
= 0; j
< argc
; j
++) {
1809 if (sdslen(argv
[j
])) {
1810 c
->argv
[c
->argc
] = createObject(REDIS_STRING
,argv
[j
]);
1817 /* Execute the command. If the client is still valid
1818 * after processCommand() return and there is something
1819 * on the query buffer try to process the next command. */
1820 if (c
->argc
&& processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
1822 } else if (sdslen(c
->querybuf
) >= REDIS_REQUEST_MAX_SIZE
) {
1823 redisLog(REDIS_DEBUG
, "Client protocol error");
1828 /* Bulk read handling. Note that if we are at this point
1829 the client already sent a command terminated with a newline,
1830 we are reading the bulk data that is actually the last
1831 argument of the command. */
1832 int qbl
= sdslen(c
->querybuf
);
1834 if (c
->bulklen
<= qbl
) {
1835 /* Copy everything but the final CRLF as final argument */
1836 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
1838 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
1839 /* Process the command. If the client is still valid after
1840 * the processing and there is more data in the buffer
1841 * try to parse it. */
1842 if (processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
1848 static void readQueryFromClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1849 redisClient
*c
= (redisClient
*) privdata
;
1850 char buf
[REDIS_IOBUF_LEN
];
1853 REDIS_NOTUSED(mask
);
1855 nread
= read(fd
, buf
, REDIS_IOBUF_LEN
);
1857 if (errno
== EAGAIN
) {
1860 redisLog(REDIS_DEBUG
, "Reading from client: %s",strerror(errno
));
1864 } else if (nread
== 0) {
1865 redisLog(REDIS_DEBUG
, "Client closed connection");
1870 c
->querybuf
= sdscatlen(c
->querybuf
, buf
, nread
);
1871 c
->lastinteraction
= time(NULL
);
1875 processInputBuffer(c
);
1878 static int selectDb(redisClient
*c
, int id
) {
1879 if (id
< 0 || id
>= server
.dbnum
)
1881 c
->db
= &server
.db
[id
];
1885 static void *dupClientReplyValue(void *o
) {
1886 incrRefCount((robj
*)o
);
1890 static redisClient
*createClient(int fd
) {
1891 redisClient
*c
= zmalloc(sizeof(*c
));
1893 anetNonBlock(NULL
,fd
);
1894 anetTcpNoDelay(NULL
,fd
);
1895 if (!c
) return NULL
;
1898 c
->querybuf
= sdsempty();
1907 c
->lastinteraction
= time(NULL
);
1908 c
->authenticated
= 0;
1909 c
->replstate
= REDIS_REPL_NONE
;
1910 c
->reply
= listCreate();
1911 listSetFreeMethod(c
->reply
,decrRefCount
);
1912 listSetDupMethod(c
->reply
,dupClientReplyValue
);
1913 if (aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
,
1914 readQueryFromClient
, c
, NULL
) == AE_ERR
) {
1918 listAddNodeTail(server
.clients
,c
);
1922 static void addReply(redisClient
*c
, robj
*obj
) {
1923 if (listLength(c
->reply
) == 0 &&
1924 (c
->replstate
== REDIS_REPL_NONE
||
1925 c
->replstate
== REDIS_REPL_ONLINE
) &&
1926 aeCreateFileEvent(server
.el
, c
->fd
, AE_WRITABLE
,
1927 sendReplyToClient
, c
, NULL
) == AE_ERR
) return;
1928 if (obj
->encoding
!= REDIS_ENCODING_RAW
) {
1929 obj
= getDecodedObject(obj
);
1933 listAddNodeTail(c
->reply
,obj
);
1936 static void addReplySds(redisClient
*c
, sds s
) {
1937 robj
*o
= createObject(REDIS_STRING
,s
);
1942 static void addReplyBulkLen(redisClient
*c
, robj
*obj
) {
1945 if (obj
->encoding
== REDIS_ENCODING_RAW
) {
1946 len
= sdslen(obj
->ptr
);
1948 long n
= (long)obj
->ptr
;
1955 while((n
= n
/10) != 0) {
1959 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",len
));
1962 static void acceptHandler(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1967 REDIS_NOTUSED(mask
);
1968 REDIS_NOTUSED(privdata
);
1970 cfd
= anetAccept(server
.neterr
, fd
, cip
, &cport
);
1971 if (cfd
== AE_ERR
) {
1972 redisLog(REDIS_DEBUG
,"Accepting client connection: %s", server
.neterr
);
1975 redisLog(REDIS_DEBUG
,"Accepted %s:%d", cip
, cport
);
1976 if ((c
= createClient(cfd
)) == NULL
) {
1977 redisLog(REDIS_WARNING
,"Error allocating resoures for the client");
1978 close(cfd
); /* May be already closed, just ingore errors */
1981 /* If maxclient directive is set and this is one client more... close the
1982 * connection. Note that we create the client instead to check before
1983 * for this condition, since now the socket is already set in nonblocking
1984 * mode and we can send an error for free using the Kernel I/O */
1985 if (server
.maxclients
&& listLength(server
.clients
) > server
.maxclients
) {
1986 char *err
= "-ERR max number of clients reached\r\n";
1988 /* That's a best effort error message, don't check write errors */
1989 if (write(c
->fd
,err
,strlen(err
)) == -1) {
1990 /* Nothing to do, Just to avoid the warning... */
1995 server
.stat_numconnections
++;
1998 /* ======================= Redis objects implementation ===================== */
2000 static robj
*createObject(int type
, void *ptr
) {
2003 if (listLength(server
.objfreelist
)) {
2004 listNode
*head
= listFirst(server
.objfreelist
);
2005 o
= listNodeValue(head
);
2006 listDelNode(server
.objfreelist
,head
);
2008 o
= zmalloc(sizeof(*o
));
2011 o
->encoding
= REDIS_ENCODING_RAW
;
2017 static robj
*createStringObject(char *ptr
, size_t len
) {
2018 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
2021 static robj
*createListObject(void) {
2022 list
*l
= listCreate();
2024 listSetFreeMethod(l
,decrRefCount
);
2025 return createObject(REDIS_LIST
,l
);
2028 static robj
*createSetObject(void) {
2029 dict
*d
= dictCreate(&setDictType
,NULL
);
2030 return createObject(REDIS_SET
,d
);
2033 static robj
*createZsetObject(void) {
2034 zset
*zs
= zmalloc(sizeof(*zs
));
2036 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
2037 zs
->zsl
= zslCreate();
2038 return createObject(REDIS_ZSET
,zs
);
2041 static void freeStringObject(robj
*o
) {
2042 if (o
->encoding
== REDIS_ENCODING_RAW
) {
2047 static void freeListObject(robj
*o
) {
2048 listRelease((list
*) o
->ptr
);
2051 static void freeSetObject(robj
*o
) {
2052 dictRelease((dict
*) o
->ptr
);
2055 static void freeZsetObject(robj
*o
) {
2058 dictRelease(zs
->dict
);
2063 static void freeHashObject(robj
*o
) {
2064 dictRelease((dict
*) o
->ptr
);
2067 static void incrRefCount(robj
*o
) {
2069 #ifdef DEBUG_REFCOUNT
2070 if (o
->type
== REDIS_STRING
)
2071 printf("Increment '%s'(%p), now is: %d\n",o
->ptr
,o
,o
->refcount
);
2075 static void decrRefCount(void *obj
) {
2078 #ifdef DEBUG_REFCOUNT
2079 if (o
->type
== REDIS_STRING
)
2080 printf("Decrement '%s'(%p), now is: %d\n",o
->ptr
,o
,o
->refcount
-1);
2082 if (--(o
->refcount
) == 0) {
2084 case REDIS_STRING
: freeStringObject(o
); break;
2085 case REDIS_LIST
: freeListObject(o
); break;
2086 case REDIS_SET
: freeSetObject(o
); break;
2087 case REDIS_ZSET
: freeZsetObject(o
); break;
2088 case REDIS_HASH
: freeHashObject(o
); break;
2089 default: assert(0 != 0); break;
2091 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
2092 !listAddNodeHead(server
.objfreelist
,o
))
2097 static robj
*lookupKey(redisDb
*db
, robj
*key
) {
2098 dictEntry
*de
= dictFind(db
->dict
,key
);
2099 return de
? dictGetEntryVal(de
) : NULL
;
2102 static robj
*lookupKeyRead(redisDb
*db
, robj
*key
) {
2103 expireIfNeeded(db
,key
);
2104 return lookupKey(db
,key
);
2107 static robj
*lookupKeyWrite(redisDb
*db
, robj
*key
) {
2108 deleteIfVolatile(db
,key
);
2109 return lookupKey(db
,key
);
2112 static int deleteKey(redisDb
*db
, robj
*key
) {
2115 /* We need to protect key from destruction: after the first dictDelete()
2116 * it may happen that 'key' is no longer valid if we don't increment
2117 * it's count. This may happen when we get the object reference directly
2118 * from the hash table with dictRandomKey() or dict iterators */
2120 if (dictSize(db
->expires
)) dictDelete(db
->expires
,key
);
2121 retval
= dictDelete(db
->dict
,key
);
2124 return retval
== DICT_OK
;
2127 /* Try to share an object against the shared objects pool */
2128 static robj
*tryObjectSharing(robj
*o
) {
2129 struct dictEntry
*de
;
2132 if (o
== NULL
|| server
.shareobjects
== 0) return o
;
2134 assert(o
->type
== REDIS_STRING
);
2135 de
= dictFind(server
.sharingpool
,o
);
2137 robj
*shared
= dictGetEntryKey(de
);
2139 c
= ((unsigned long) dictGetEntryVal(de
))+1;
2140 dictGetEntryVal(de
) = (void*) c
;
2141 incrRefCount(shared
);
2145 /* Here we are using a stream algorihtm: Every time an object is
2146 * shared we increment its count, everytime there is a miss we
2147 * recrement the counter of a random object. If this object reaches
2148 * zero we remove the object and put the current object instead. */
2149 if (dictSize(server
.sharingpool
) >=
2150 server
.sharingpoolsize
) {
2151 de
= dictGetRandomKey(server
.sharingpool
);
2153 c
= ((unsigned long) dictGetEntryVal(de
))-1;
2154 dictGetEntryVal(de
) = (void*) c
;
2156 dictDelete(server
.sharingpool
,de
->key
);
2159 c
= 0; /* If the pool is empty we want to add this object */
2164 retval
= dictAdd(server
.sharingpool
,o
,(void*)1);
2165 assert(retval
== DICT_OK
);
2172 /* Check if the nul-terminated string 's' can be represented by a long
2173 * (that is, is a number that fits into long without any other space or
2174 * character before or after the digits).
2176 * If so, the function returns REDIS_OK and *longval is set to the value
2177 * of the number. Otherwise REDIS_ERR is returned */
2178 static int isStringRepresentableAsLong(sds s
, long *longval
) {
2179 char buf
[32], *endptr
;
2183 value
= strtol(s
, &endptr
, 10);
2184 if (endptr
[0] != '\0') return REDIS_ERR
;
2185 slen
= snprintf(buf
,32,"%ld",value
);
2187 /* If the number converted back into a string is not identical
2188 * then it's not possible to encode the string as integer */
2189 if (sdslen(s
) != (unsigned)slen
|| memcmp(buf
,s
,slen
)) return REDIS_ERR
;
2190 if (longval
) *longval
= value
;
2194 /* Try to encode a string object in order to save space */
2195 static int tryObjectEncoding(robj
*o
) {
2199 if (o
->encoding
!= REDIS_ENCODING_RAW
)
2200 return REDIS_ERR
; /* Already encoded */
2202 /* It's not save to encode shared objects: shared objects can be shared
2203 * everywhere in the "object space" of Redis. Encoded objects can only
2204 * appear as "values" (and not, for instance, as keys) */
2205 if (o
->refcount
> 1) return REDIS_ERR
;
2207 /* Currently we try to encode only strings */
2208 assert(o
->type
== REDIS_STRING
);
2210 /* Check if we can represent this string as a long integer */
2211 if (isStringRepresentableAsLong(s
,&value
) == REDIS_ERR
) return REDIS_ERR
;
2213 /* Ok, this object can be encoded */
2214 o
->encoding
= REDIS_ENCODING_INT
;
2216 o
->ptr
= (void*) value
;
2220 /* Get a decoded version of an encoded object (returned as a new object) */
2221 static robj
*getDecodedObject(const robj
*o
) {
2224 assert(o
->encoding
!= REDIS_ENCODING_RAW
);
2225 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
2228 snprintf(buf
,32,"%ld",(long)o
->ptr
);
2229 dec
= createStringObject(buf
,strlen(buf
));
2236 /* Compare two string objects via strcmp() or alike.
2237 * Note that the objects may be integer-encoded. In such a case we
2238 * use snprintf() to get a string representation of the numbers on the stack
2239 * and compare the strings, it's much faster than calling getDecodedObject(). */
2240 static int compareStringObjects(robj
*a
, robj
*b
) {
2241 assert(a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
2242 char bufa
[128], bufb
[128], *astr
, *bstr
;
2245 if (a
== b
) return 0;
2246 if (a
->encoding
!= REDIS_ENCODING_RAW
) {
2247 snprintf(bufa
,sizeof(bufa
),"%ld",(long) a
->ptr
);
2253 if (b
->encoding
!= REDIS_ENCODING_RAW
) {
2254 snprintf(bufb
,sizeof(bufb
),"%ld",(long) b
->ptr
);
2260 return bothsds
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
);
2263 static size_t stringObjectLen(robj
*o
) {
2264 assert(o
->type
== REDIS_STRING
);
2265 if (o
->encoding
== REDIS_ENCODING_RAW
) {
2266 return sdslen(o
->ptr
);
2270 return snprintf(buf
,32,"%ld",(long)o
->ptr
);
2274 /*============================ DB saving/loading ============================ */
2276 static int rdbSaveType(FILE *fp
, unsigned char type
) {
2277 if (fwrite(&type
,1,1,fp
) == 0) return -1;
2281 static int rdbSaveTime(FILE *fp
, time_t t
) {
2282 int32_t t32
= (int32_t) t
;
2283 if (fwrite(&t32
,4,1,fp
) == 0) return -1;
2287 /* check rdbLoadLen() comments for more info */
2288 static int rdbSaveLen(FILE *fp
, uint32_t len
) {
2289 unsigned char buf
[2];
2292 /* Save a 6 bit len */
2293 buf
[0] = (len
&0xFF)|(REDIS_RDB_6BITLEN
<<6);
2294 if (fwrite(buf
,1,1,fp
) == 0) return -1;
2295 } else if (len
< (1<<14)) {
2296 /* Save a 14 bit len */
2297 buf
[0] = ((len
>>8)&0xFF)|(REDIS_RDB_14BITLEN
<<6);
2299 if (fwrite(buf
,2,1,fp
) == 0) return -1;
2301 /* Save a 32 bit len */
2302 buf
[0] = (REDIS_RDB_32BITLEN
<<6);
2303 if (fwrite(buf
,1,1,fp
) == 0) return -1;
2305 if (fwrite(&len
,4,1,fp
) == 0) return -1;
2310 /* String objects in the form "2391" "-100" without any space and with a
2311 * range of values that can fit in an 8, 16 or 32 bit signed value can be
2312 * encoded as integers to save space */
2313 static int rdbTryIntegerEncoding(sds s
, unsigned char *enc
) {
2315 char *endptr
, buf
[32];
2317 /* Check if it's possible to encode this value as a number */
2318 value
= strtoll(s
, &endptr
, 10);
2319 if (endptr
[0] != '\0') return 0;
2320 snprintf(buf
,32,"%lld",value
);
2322 /* If the number converted back into a string is not identical
2323 * then it's not possible to encode the string as integer */
2324 if (strlen(buf
) != sdslen(s
) || memcmp(buf
,s
,sdslen(s
))) return 0;
2326 /* Finally check if it fits in our ranges */
2327 if (value
>= -(1<<7) && value
<= (1<<7)-1) {
2328 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT8
;
2329 enc
[1] = value
&0xFF;
2331 } else if (value
>= -(1<<15) && value
<= (1<<15)-1) {
2332 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT16
;
2333 enc
[1] = value
&0xFF;
2334 enc
[2] = (value
>>8)&0xFF;
2336 } else if (value
>= -((long long)1<<31) && value
<= ((long long)1<<31)-1) {
2337 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT32
;
2338 enc
[1] = value
&0xFF;
2339 enc
[2] = (value
>>8)&0xFF;
2340 enc
[3] = (value
>>16)&0xFF;
2341 enc
[4] = (value
>>24)&0xFF;
2348 static int rdbSaveLzfStringObject(FILE *fp
, robj
*obj
) {
2349 unsigned int comprlen
, outlen
;
2353 /* We require at least four bytes compression for this to be worth it */
2354 outlen
= sdslen(obj
->ptr
)-4;
2355 if (outlen
<= 0) return 0;
2356 if ((out
= zmalloc(outlen
+1)) == NULL
) return 0;
2357 comprlen
= lzf_compress(obj
->ptr
, sdslen(obj
->ptr
), out
, outlen
);
2358 if (comprlen
== 0) {
2362 /* Data compressed! Let's save it on disk */
2363 byte
= (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_LZF
;
2364 if (fwrite(&byte
,1,1,fp
) == 0) goto writeerr
;
2365 if (rdbSaveLen(fp
,comprlen
) == -1) goto writeerr
;
2366 if (rdbSaveLen(fp
,sdslen(obj
->ptr
)) == -1) goto writeerr
;
2367 if (fwrite(out
,comprlen
,1,fp
) == 0) goto writeerr
;
2376 /* Save a string objet as [len][data] on disk. If the object is a string
2377 * representation of an integer value we try to safe it in a special form */
2378 static int rdbSaveStringObjectRaw(FILE *fp
, robj
*obj
) {
2382 len
= sdslen(obj
->ptr
);
2384 /* Try integer encoding */
2386 unsigned char buf
[5];
2387 if ((enclen
= rdbTryIntegerEncoding(obj
->ptr
,buf
)) > 0) {
2388 if (fwrite(buf
,enclen
,1,fp
) == 0) return -1;
2393 /* Try LZF compression - under 20 bytes it's unable to compress even
2394 * aaaaaaaaaaaaaaaaaa so skip it */
2398 retval
= rdbSaveLzfStringObject(fp
,obj
);
2399 if (retval
== -1) return -1;
2400 if (retval
> 0) return 0;
2401 /* retval == 0 means data can't be compressed, save the old way */
2404 /* Store verbatim */
2405 if (rdbSaveLen(fp
,len
) == -1) return -1;
2406 if (len
&& fwrite(obj
->ptr
,len
,1,fp
) == 0) return -1;
2410 /* Like rdbSaveStringObjectRaw() but handle encoded objects */
2411 static int rdbSaveStringObject(FILE *fp
, robj
*obj
) {
2415 if (obj
->encoding
!= REDIS_ENCODING_RAW
) {
2416 dec
= getDecodedObject(obj
);
2417 retval
= rdbSaveStringObjectRaw(fp
,dec
);
2421 return rdbSaveStringObjectRaw(fp
,obj
);
2425 /* Save a double value. Doubles are saved as strings prefixed by an unsigned
2426 * 8 bit integer specifing the length of the representation.
2427 * This 8 bit integer has special values in order to specify the following
2433 static int rdbSaveDoubleValue(FILE *fp
, double val
) {
2434 unsigned char buf
[128];
2440 } else if (!isfinite(val
)) {
2442 buf
[0] = (val
< 0) ? 255 : 254;
2444 snprintf((char*)buf
+1,sizeof(buf
)-1,"%.17g",val
);
2445 buf
[0] = strlen((char*)buf
);
2448 if (fwrite(buf
,len
,1,fp
) == 0) return -1;
2452 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
2453 static int rdbSave(char *filename
) {
2454 dictIterator
*di
= NULL
;
2459 time_t now
= time(NULL
);
2461 snprintf(tmpfile
,256,"temp-%d.rdb", (int) getpid());
2462 fp
= fopen(tmpfile
,"w");
2464 redisLog(REDIS_WARNING
, "Failed saving the DB: %s", strerror(errno
));
2467 if (fwrite("REDIS0001",9,1,fp
) == 0) goto werr
;
2468 for (j
= 0; j
< server
.dbnum
; j
++) {
2469 redisDb
*db
= server
.db
+j
;
2471 if (dictSize(d
) == 0) continue;
2472 di
= dictGetIterator(d
);
2478 /* Write the SELECT DB opcode */
2479 if (rdbSaveType(fp
,REDIS_SELECTDB
) == -1) goto werr
;
2480 if (rdbSaveLen(fp
,j
) == -1) goto werr
;
2482 /* Iterate this DB writing every entry */
2483 while((de
= dictNext(di
)) != NULL
) {
2484 robj
*key
= dictGetEntryKey(de
);
2485 robj
*o
= dictGetEntryVal(de
);
2486 time_t expiretime
= getExpire(db
,key
);
2488 /* Save the expire time */
2489 if (expiretime
!= -1) {
2490 /* If this key is already expired skip it */
2491 if (expiretime
< now
) continue;
2492 if (rdbSaveType(fp
,REDIS_EXPIRETIME
) == -1) goto werr
;
2493 if (rdbSaveTime(fp
,expiretime
) == -1) goto werr
;
2495 /* Save the key and associated value */
2496 if (rdbSaveType(fp
,o
->type
) == -1) goto werr
;
2497 if (rdbSaveStringObject(fp
,key
) == -1) goto werr
;
2498 if (o
->type
== REDIS_STRING
) {
2499 /* Save a string value */
2500 if (rdbSaveStringObject(fp
,o
) == -1) goto werr
;
2501 } else if (o
->type
== REDIS_LIST
) {
2502 /* Save a list value */
2503 list
*list
= o
->ptr
;
2507 if (rdbSaveLen(fp
,listLength(list
)) == -1) goto werr
;
2508 while((ln
= listYield(list
))) {
2509 robj
*eleobj
= listNodeValue(ln
);
2511 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
2513 } else if (o
->type
== REDIS_SET
) {
2514 /* Save a set value */
2516 dictIterator
*di
= dictGetIterator(set
);
2519 if (rdbSaveLen(fp
,dictSize(set
)) == -1) goto werr
;
2520 while((de
= dictNext(di
)) != NULL
) {
2521 robj
*eleobj
= dictGetEntryKey(de
);
2523 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
2525 dictReleaseIterator(di
);
2526 } else if (o
->type
== REDIS_ZSET
) {
2527 /* Save a set value */
2529 dictIterator
*di
= dictGetIterator(zs
->dict
);
2532 if (rdbSaveLen(fp
,dictSize(zs
->dict
)) == -1) goto werr
;
2533 while((de
= dictNext(di
)) != NULL
) {
2534 robj
*eleobj
= dictGetEntryKey(de
);
2535 double *score
= dictGetEntryVal(de
);
2537 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
2538 if (rdbSaveDoubleValue(fp
,*score
) == -1) goto werr
;
2540 dictReleaseIterator(di
);
2545 dictReleaseIterator(di
);
2548 if (rdbSaveType(fp
,REDIS_EOF
) == -1) goto werr
;
2550 /* Make sure data will not remain on the OS's output buffers */
2555 /* Use RENAME to make sure the DB file is changed atomically only
2556 * if the generate DB file is ok. */
2557 if (rename(tmpfile
,filename
) == -1) {
2558 redisLog(REDIS_WARNING
,"Error moving temp DB file on the final destination: %s", strerror(errno
));
2562 redisLog(REDIS_NOTICE
,"DB saved on disk");
2564 server
.lastsave
= time(NULL
);
2570 redisLog(REDIS_WARNING
,"Write error saving DB on disk: %s", strerror(errno
));
2571 if (di
) dictReleaseIterator(di
);
2575 static int rdbSaveBackground(char *filename
) {
2578 if (server
.bgsaveinprogress
) return REDIS_ERR
;
2579 if ((childpid
= fork()) == 0) {
2582 if (rdbSave(filename
) == REDIS_OK
) {
2589 if (childpid
== -1) {
2590 redisLog(REDIS_WARNING
,"Can't save in background: fork: %s",
2594 redisLog(REDIS_NOTICE
,"Background saving started by pid %d",childpid
);
2595 server
.bgsaveinprogress
= 1;
2596 server
.bgsavechildpid
= childpid
;
2599 return REDIS_OK
; /* unreached */
2602 static void rdbRemoveTempFile(pid_t childpid
) {
2605 snprintf(tmpfile
,256,"temp-%d.rdb", (int) childpid
);
2609 static int rdbLoadType(FILE *fp
) {
2611 if (fread(&type
,1,1,fp
) == 0) return -1;
2615 static time_t rdbLoadTime(FILE *fp
) {
2617 if (fread(&t32
,4,1,fp
) == 0) return -1;
2618 return (time_t) t32
;
2621 /* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
2622 * of this file for a description of how this are stored on disk.
2624 * isencoded is set to 1 if the readed length is not actually a length but
2625 * an "encoding type", check the above comments for more info */
2626 static uint32_t rdbLoadLen(FILE *fp
, int rdbver
, int *isencoded
) {
2627 unsigned char buf
[2];
2630 if (isencoded
) *isencoded
= 0;
2632 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
2637 if (fread(buf
,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2638 type
= (buf
[0]&0xC0)>>6;
2639 if (type
== REDIS_RDB_6BITLEN
) {
2640 /* Read a 6 bit len */
2642 } else if (type
== REDIS_RDB_ENCVAL
) {
2643 /* Read a 6 bit len encoding type */
2644 if (isencoded
) *isencoded
= 1;
2646 } else if (type
== REDIS_RDB_14BITLEN
) {
2647 /* Read a 14 bit len */
2648 if (fread(buf
+1,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2649 return ((buf
[0]&0x3F)<<8)|buf
[1];
2651 /* Read a 32 bit len */
2652 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
2658 static robj
*rdbLoadIntegerObject(FILE *fp
, int enctype
) {
2659 unsigned char enc
[4];
2662 if (enctype
== REDIS_RDB_ENC_INT8
) {
2663 if (fread(enc
,1,1,fp
) == 0) return NULL
;
2664 val
= (signed char)enc
[0];
2665 } else if (enctype
== REDIS_RDB_ENC_INT16
) {
2667 if (fread(enc
,2,1,fp
) == 0) return NULL
;
2668 v
= enc
[0]|(enc
[1]<<8);
2670 } else if (enctype
== REDIS_RDB_ENC_INT32
) {
2672 if (fread(enc
,4,1,fp
) == 0) return NULL
;
2673 v
= enc
[0]|(enc
[1]<<8)|(enc
[2]<<16)|(enc
[3]<<24);
2676 val
= 0; /* anti-warning */
2679 return createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",val
));
2682 static robj
*rdbLoadLzfStringObject(FILE*fp
, int rdbver
) {
2683 unsigned int len
, clen
;
2684 unsigned char *c
= NULL
;
2687 if ((clen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2688 if ((len
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2689 if ((c
= zmalloc(clen
)) == NULL
) goto err
;
2690 if ((val
= sdsnewlen(NULL
,len
)) == NULL
) goto err
;
2691 if (fread(c
,clen
,1,fp
) == 0) goto err
;
2692 if (lzf_decompress(c
,clen
,val
,len
) == 0) goto err
;
2694 return createObject(REDIS_STRING
,val
);
2701 static robj
*rdbLoadStringObject(FILE*fp
, int rdbver
) {
2706 len
= rdbLoadLen(fp
,rdbver
,&isencoded
);
2709 case REDIS_RDB_ENC_INT8
:
2710 case REDIS_RDB_ENC_INT16
:
2711 case REDIS_RDB_ENC_INT32
:
2712 return tryObjectSharing(rdbLoadIntegerObject(fp
,len
));
2713 case REDIS_RDB_ENC_LZF
:
2714 return tryObjectSharing(rdbLoadLzfStringObject(fp
,rdbver
));
2720 if (len
== REDIS_RDB_LENERR
) return NULL
;
2721 val
= sdsnewlen(NULL
,len
);
2722 if (len
&& fread(val
,len
,1,fp
) == 0) {
2726 return tryObjectSharing(createObject(REDIS_STRING
,val
));
2729 /* For information about double serialization check rdbSaveDoubleValue() */
2730 static int rdbLoadDoubleValue(FILE *fp
, double *val
) {
2734 if (fread(&len
,1,1,fp
) == 0) return -1;
2736 case 255: *val
= R_NegInf
; return 0;
2737 case 254: *val
= R_PosInf
; return 0;
2738 case 253: *val
= R_Nan
; return 0;
2740 if (fread(buf
,len
,1,fp
) == 0) return -1;
2741 sscanf(buf
, "%lg", val
);
2746 static int rdbLoad(char *filename
) {
2748 robj
*keyobj
= NULL
;
2750 int type
, retval
, rdbver
;
2751 dict
*d
= server
.db
[0].dict
;
2752 redisDb
*db
= server
.db
+0;
2754 time_t expiretime
= -1, now
= time(NULL
);
2756 fp
= fopen(filename
,"r");
2757 if (!fp
) return REDIS_ERR
;
2758 if (fread(buf
,9,1,fp
) == 0) goto eoferr
;
2760 if (memcmp(buf
,"REDIS",5) != 0) {
2762 redisLog(REDIS_WARNING
,"Wrong signature trying to load DB from file");
2765 rdbver
= atoi(buf
+5);
2768 redisLog(REDIS_WARNING
,"Can't handle RDB format version %d",rdbver
);
2775 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
2776 if (type
== REDIS_EXPIRETIME
) {
2777 if ((expiretime
= rdbLoadTime(fp
)) == -1) goto eoferr
;
2778 /* We read the time so we need to read the object type again */
2779 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
2781 if (type
== REDIS_EOF
) break;
2782 /* Handle SELECT DB opcode as a special case */
2783 if (type
== REDIS_SELECTDB
) {
2784 if ((dbid
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2786 if (dbid
>= (unsigned)server
.dbnum
) {
2787 redisLog(REDIS_WARNING
,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server
.dbnum
);
2790 db
= server
.db
+dbid
;
2795 if ((keyobj
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2797 if (type
== REDIS_STRING
) {
2798 /* Read string value */
2799 if ((o
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2800 tryObjectEncoding(o
);
2801 } else if (type
== REDIS_LIST
|| type
== REDIS_SET
) {
2802 /* Read list/set value */
2805 if ((listlen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2807 o
= (type
== REDIS_LIST
) ? createListObject() : createSetObject();
2808 /* Load every single element of the list/set */
2812 if ((ele
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2813 tryObjectEncoding(ele
);
2814 if (type
== REDIS_LIST
) {
2815 listAddNodeTail((list
*)o
->ptr
,ele
);
2817 dictAdd((dict
*)o
->ptr
,ele
,NULL
);
2820 } else if (type
== REDIS_ZSET
) {
2821 /* Read list/set value */
2825 if ((zsetlen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2827 o
= createZsetObject();
2829 /* Load every single element of the list/set */
2832 double *score
= zmalloc(sizeof(double));
2834 if ((ele
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2835 tryObjectEncoding(ele
);
2836 if (rdbLoadDoubleValue(fp
,score
) == -1) goto eoferr
;
2837 dictAdd(zs
->dict
,ele
,score
);
2838 zslInsert(zs
->zsl
,*score
,ele
);
2839 incrRefCount(ele
); /* added to skiplist */
2844 /* Add the new object in the hash table */
2845 retval
= dictAdd(d
,keyobj
,o
);
2846 if (retval
== DICT_ERR
) {
2847 redisLog(REDIS_WARNING
,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj
->ptr
);
2850 /* Set the expire time if needed */
2851 if (expiretime
!= -1) {
2852 setExpire(db
,keyobj
,expiretime
);
2853 /* Delete this key if already expired */
2854 if (expiretime
< now
) deleteKey(db
,keyobj
);
2862 eoferr
: /* unexpected end of file is handled here with a fatal exit */
2863 if (keyobj
) decrRefCount(keyobj
);
2864 redisLog(REDIS_WARNING
,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
2866 return REDIS_ERR
; /* Just to avoid warning */
2869 /*================================== Commands =============================== */
2871 static void authCommand(redisClient
*c
) {
2872 if (!server
.requirepass
|| !strcmp(c
->argv
[1]->ptr
, server
.requirepass
)) {
2873 c
->authenticated
= 1;
2874 addReply(c
,shared
.ok
);
2876 c
->authenticated
= 0;
2877 addReplySds(c
,sdscatprintf(sdsempty(),"-ERR invalid password\r\n"));
2881 static void pingCommand(redisClient
*c
) {
2882 addReply(c
,shared
.pong
);
2885 static void echoCommand(redisClient
*c
) {
2886 addReplyBulkLen(c
,c
->argv
[1]);
2887 addReply(c
,c
->argv
[1]);
2888 addReply(c
,shared
.crlf
);
2891 /*=================================== Strings =============================== */
2893 static void setGenericCommand(redisClient
*c
, int nx
) {
2896 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2897 if (retval
== DICT_ERR
) {
2899 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2900 incrRefCount(c
->argv
[2]);
2902 addReply(c
,shared
.czero
);
2906 incrRefCount(c
->argv
[1]);
2907 incrRefCount(c
->argv
[2]);
2910 removeExpire(c
->db
,c
->argv
[1]);
2911 addReply(c
, nx
? shared
.cone
: shared
.ok
);
2914 static void setCommand(redisClient
*c
) {
2915 setGenericCommand(c
,0);
2918 static void setnxCommand(redisClient
*c
) {
2919 setGenericCommand(c
,1);
2922 static void getCommand(redisClient
*c
) {
2923 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2926 addReply(c
,shared
.nullbulk
);
2928 if (o
->type
!= REDIS_STRING
) {
2929 addReply(c
,shared
.wrongtypeerr
);
2931 addReplyBulkLen(c
,o
);
2933 addReply(c
,shared
.crlf
);
2938 static void getsetCommand(redisClient
*c
) {
2940 if (dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]) == DICT_ERR
) {
2941 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2943 incrRefCount(c
->argv
[1]);
2945 incrRefCount(c
->argv
[2]);
2947 removeExpire(c
->db
,c
->argv
[1]);
2950 static void mgetCommand(redisClient
*c
) {
2953 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",c
->argc
-1));
2954 for (j
= 1; j
< c
->argc
; j
++) {
2955 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
2957 addReply(c
,shared
.nullbulk
);
2959 if (o
->type
!= REDIS_STRING
) {
2960 addReply(c
,shared
.nullbulk
);
2962 addReplyBulkLen(c
,o
);
2964 addReply(c
,shared
.crlf
);
2970 static void incrDecrCommand(redisClient
*c
, long long incr
) {
2975 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2979 if (o
->type
!= REDIS_STRING
) {
2984 if (o
->encoding
== REDIS_ENCODING_RAW
)
2985 value
= strtoll(o
->ptr
, &eptr
, 10);
2986 else if (o
->encoding
== REDIS_ENCODING_INT
)
2987 value
= (long)o
->ptr
;
2994 o
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",value
));
2995 tryObjectEncoding(o
);
2996 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],o
);
2997 if (retval
== DICT_ERR
) {
2998 dictReplace(c
->db
->dict
,c
->argv
[1],o
);
2999 removeExpire(c
->db
,c
->argv
[1]);
3001 incrRefCount(c
->argv
[1]);
3004 addReply(c
,shared
.colon
);
3006 addReply(c
,shared
.crlf
);
3009 static void incrCommand(redisClient
*c
) {
3010 incrDecrCommand(c
,1);
3013 static void decrCommand(redisClient
*c
) {
3014 incrDecrCommand(c
,-1);
3017 static void incrbyCommand(redisClient
*c
) {
3018 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
3019 incrDecrCommand(c
,incr
);
3022 static void decrbyCommand(redisClient
*c
) {
3023 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
3024 incrDecrCommand(c
,-incr
);
3027 /* ========================= Type agnostic commands ========================= */
3029 static void delCommand(redisClient
*c
) {
3032 for (j
= 1; j
< c
->argc
; j
++) {
3033 if (deleteKey(c
->db
,c
->argv
[j
])) {
3040 addReply(c
,shared
.czero
);
3043 addReply(c
,shared
.cone
);
3046 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",deleted
));
3051 static void existsCommand(redisClient
*c
) {
3052 addReply(c
,lookupKeyRead(c
->db
,c
->argv
[1]) ? shared
.cone
: shared
.czero
);
3055 static void selectCommand(redisClient
*c
) {
3056 int id
= atoi(c
->argv
[1]->ptr
);
3058 if (selectDb(c
,id
) == REDIS_ERR
) {
3059 addReplySds(c
,sdsnew("-ERR invalid DB index\r\n"));
3061 addReply(c
,shared
.ok
);
3065 static void randomkeyCommand(redisClient
*c
) {
3069 de
= dictGetRandomKey(c
->db
->dict
);
3070 if (!de
|| expireIfNeeded(c
->db
,dictGetEntryKey(de
)) == 0) break;
3073 addReply(c
,shared
.plus
);
3074 addReply(c
,shared
.crlf
);
3076 addReply(c
,shared
.plus
);
3077 addReply(c
,dictGetEntryKey(de
));
3078 addReply(c
,shared
.crlf
);
3082 static void keysCommand(redisClient
*c
) {
3085 sds pattern
= c
->argv
[1]->ptr
;
3086 int plen
= sdslen(pattern
);
3087 int numkeys
= 0, keyslen
= 0;
3088 robj
*lenobj
= createObject(REDIS_STRING
,NULL
);
3090 di
= dictGetIterator(c
->db
->dict
);
3092 decrRefCount(lenobj
);
3093 while((de
= dictNext(di
)) != NULL
) {
3094 robj
*keyobj
= dictGetEntryKey(de
);
3096 sds key
= keyobj
->ptr
;
3097 if ((pattern
[0] == '*' && pattern
[1] == '\0') ||
3098 stringmatchlen(pattern
,plen
,key
,sdslen(key
),0)) {
3099 if (expireIfNeeded(c
->db
,keyobj
) == 0) {
3101 addReply(c
,shared
.space
);
3104 keyslen
+= sdslen(key
);
3108 dictReleaseIterator(di
);
3109 lenobj
->ptr
= sdscatprintf(sdsempty(),"$%lu\r\n",keyslen
+(numkeys
? (numkeys
-1) : 0));
3110 addReply(c
,shared
.crlf
);
3113 static void dbsizeCommand(redisClient
*c
) {
3115 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c
->db
->dict
)));
3118 static void lastsaveCommand(redisClient
*c
) {
3120 sdscatprintf(sdsempty(),":%lu\r\n",server
.lastsave
));
3123 static void typeCommand(redisClient
*c
) {
3127 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3132 case REDIS_STRING
: type
= "+string"; break;
3133 case REDIS_LIST
: type
= "+list"; break;
3134 case REDIS_SET
: type
= "+set"; break;
3135 case REDIS_ZSET
: type
= "+zset"; break;
3136 default: type
= "unknown"; break;
3139 addReplySds(c
,sdsnew(type
));
3140 addReply(c
,shared
.crlf
);
3143 static void saveCommand(redisClient
*c
) {
3144 if (server
.bgsaveinprogress
) {
3145 addReplySds(c
,sdsnew("-ERR background save in progress\r\n"));
3148 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
3149 addReply(c
,shared
.ok
);
3151 addReply(c
,shared
.err
);
3155 static void bgsaveCommand(redisClient
*c
) {
3156 if (server
.bgsaveinprogress
) {
3157 addReplySds(c
,sdsnew("-ERR background save already in progress\r\n"));
3160 if (rdbSaveBackground(server
.dbfilename
) == REDIS_OK
) {
3161 addReply(c
,shared
.ok
);
3163 addReply(c
,shared
.err
);
3167 static void shutdownCommand(redisClient
*c
) {
3168 redisLog(REDIS_WARNING
,"User requested shutdown, saving DB...");
3169 /* Kill the saving child if there is a background saving in progress.
3170 We want to avoid race conditions, for instance our saving child may
3171 overwrite the synchronous saving did by SHUTDOWN. */
3172 if (server
.bgsaveinprogress
) {
3173 redisLog(REDIS_WARNING
,"There is a live saving child. Killing it!");
3174 kill(server
.bgsavechildpid
,SIGKILL
);
3175 rdbRemoveTempFile(server
.bgsavechildpid
);
3178 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
3179 if (server
.daemonize
)
3180 unlink(server
.pidfile
);
3181 redisLog(REDIS_WARNING
,"%zu bytes used at exit",zmalloc_used_memory());
3182 redisLog(REDIS_WARNING
,"Server exit now, bye bye...");
3185 /* Ooops.. error saving! The best we can do is to continue operating.
3186 * Note that if there was a background saving process, in the next
3187 * cron() Redis will be notified that the background saving aborted,
3188 * handling special stuff like slaves pending for synchronization... */
3189 redisLog(REDIS_WARNING
,"Error trying to save the DB, can't exit");
3190 addReplySds(c
,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
3194 static void renameGenericCommand(redisClient
*c
, int nx
) {
3197 /* To use the same key as src and dst is probably an error */
3198 if (sdscmp(c
->argv
[1]->ptr
,c
->argv
[2]->ptr
) == 0) {
3199 addReply(c
,shared
.sameobjecterr
);
3203 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3205 addReply(c
,shared
.nokeyerr
);
3209 deleteIfVolatile(c
->db
,c
->argv
[2]);
3210 if (dictAdd(c
->db
->dict
,c
->argv
[2],o
) == DICT_ERR
) {
3213 addReply(c
,shared
.czero
);
3216 dictReplace(c
->db
->dict
,c
->argv
[2],o
);
3218 incrRefCount(c
->argv
[2]);
3220 deleteKey(c
->db
,c
->argv
[1]);
3222 addReply(c
,nx
? shared
.cone
: shared
.ok
);
3225 static void renameCommand(redisClient
*c
) {
3226 renameGenericCommand(c
,0);
3229 static void renamenxCommand(redisClient
*c
) {
3230 renameGenericCommand(c
,1);
3233 static void moveCommand(redisClient
*c
) {
3238 /* Obtain source and target DB pointers */
3241 if (selectDb(c
,atoi(c
->argv
[2]->ptr
)) == REDIS_ERR
) {
3242 addReply(c
,shared
.outofrangeerr
);
3246 selectDb(c
,srcid
); /* Back to the source DB */
3248 /* If the user is moving using as target the same
3249 * DB as the source DB it is probably an error. */
3251 addReply(c
,shared
.sameobjecterr
);
3255 /* Check if the element exists and get a reference */
3256 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3258 addReply(c
,shared
.czero
);
3262 /* Try to add the element to the target DB */
3263 deleteIfVolatile(dst
,c
->argv
[1]);
3264 if (dictAdd(dst
->dict
,c
->argv
[1],o
) == DICT_ERR
) {
3265 addReply(c
,shared
.czero
);
3268 incrRefCount(c
->argv
[1]);
3271 /* OK! key moved, free the entry in the source DB */
3272 deleteKey(src
,c
->argv
[1]);
3274 addReply(c
,shared
.cone
);
3277 /* =================================== Lists ================================ */
3278 static void pushGenericCommand(redisClient
*c
, int where
) {
3282 lobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3284 lobj
= createListObject();
3286 if (where
== REDIS_HEAD
) {
3287 listAddNodeHead(list
,c
->argv
[2]);
3289 listAddNodeTail(list
,c
->argv
[2]);
3291 dictAdd(c
->db
->dict
,c
->argv
[1],lobj
);
3292 incrRefCount(c
->argv
[1]);
3293 incrRefCount(c
->argv
[2]);
3295 if (lobj
->type
!= REDIS_LIST
) {
3296 addReply(c
,shared
.wrongtypeerr
);
3300 if (where
== REDIS_HEAD
) {
3301 listAddNodeHead(list
,c
->argv
[2]);
3303 listAddNodeTail(list
,c
->argv
[2]);
3305 incrRefCount(c
->argv
[2]);
3308 addReply(c
,shared
.ok
);
3311 static void lpushCommand(redisClient
*c
) {
3312 pushGenericCommand(c
,REDIS_HEAD
);
3315 static void rpushCommand(redisClient
*c
) {
3316 pushGenericCommand(c
,REDIS_TAIL
);
3319 static void llenCommand(redisClient
*c
) {
3323 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3325 addReply(c
,shared
.czero
);
3328 if (o
->type
!= REDIS_LIST
) {
3329 addReply(c
,shared
.wrongtypeerr
);
3332 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",listLength(l
)));
3337 static void lindexCommand(redisClient
*c
) {
3339 int index
= atoi(c
->argv
[2]->ptr
);
3341 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3343 addReply(c
,shared
.nullbulk
);
3345 if (o
->type
!= REDIS_LIST
) {
3346 addReply(c
,shared
.wrongtypeerr
);
3348 list
*list
= o
->ptr
;
3351 ln
= listIndex(list
, index
);
3353 addReply(c
,shared
.nullbulk
);
3355 robj
*ele
= listNodeValue(ln
);
3356 addReplyBulkLen(c
,ele
);
3358 addReply(c
,shared
.crlf
);
3364 static void lsetCommand(redisClient
*c
) {
3366 int index
= atoi(c
->argv
[2]->ptr
);
3368 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3370 addReply(c
,shared
.nokeyerr
);
3372 if (o
->type
!= REDIS_LIST
) {
3373 addReply(c
,shared
.wrongtypeerr
);
3375 list
*list
= o
->ptr
;
3378 ln
= listIndex(list
, index
);
3380 addReply(c
,shared
.outofrangeerr
);
3382 robj
*ele
= listNodeValue(ln
);
3385 listNodeValue(ln
) = c
->argv
[3];
3386 incrRefCount(c
->argv
[3]);
3387 addReply(c
,shared
.ok
);
3394 static void popGenericCommand(redisClient
*c
, int where
) {
3397 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3399 addReply(c
,shared
.nullbulk
);
3401 if (o
->type
!= REDIS_LIST
) {
3402 addReply(c
,shared
.wrongtypeerr
);
3404 list
*list
= o
->ptr
;
3407 if (where
== REDIS_HEAD
)
3408 ln
= listFirst(list
);
3410 ln
= listLast(list
);
3413 addReply(c
,shared
.nullbulk
);
3415 robj
*ele
= listNodeValue(ln
);
3416 addReplyBulkLen(c
,ele
);
3418 addReply(c
,shared
.crlf
);
3419 listDelNode(list
,ln
);
3426 static void lpopCommand(redisClient
*c
) {
3427 popGenericCommand(c
,REDIS_HEAD
);
3430 static void rpopCommand(redisClient
*c
) {
3431 popGenericCommand(c
,REDIS_TAIL
);
3434 static void lrangeCommand(redisClient
*c
) {
3436 int start
= atoi(c
->argv
[2]->ptr
);
3437 int end
= atoi(c
->argv
[3]->ptr
);
3439 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3441 addReply(c
,shared
.nullmultibulk
);
3443 if (o
->type
!= REDIS_LIST
) {
3444 addReply(c
,shared
.wrongtypeerr
);
3446 list
*list
= o
->ptr
;
3448 int llen
= listLength(list
);
3452 /* convert negative indexes */
3453 if (start
< 0) start
= llen
+start
;
3454 if (end
< 0) end
= llen
+end
;
3455 if (start
< 0) start
= 0;
3456 if (end
< 0) end
= 0;
3458 /* indexes sanity checks */
3459 if (start
> end
|| start
>= llen
) {
3460 /* Out of range start or start > end result in empty list */
3461 addReply(c
,shared
.emptymultibulk
);
3464 if (end
>= llen
) end
= llen
-1;
3465 rangelen
= (end
-start
)+1;
3467 /* Return the result in form of a multi-bulk reply */
3468 ln
= listIndex(list
, start
);
3469 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",rangelen
));
3470 for (j
= 0; j
< rangelen
; j
++) {
3471 ele
= listNodeValue(ln
);
3472 addReplyBulkLen(c
,ele
);
3474 addReply(c
,shared
.crlf
);
3481 static void ltrimCommand(redisClient
*c
) {
3483 int start
= atoi(c
->argv
[2]->ptr
);
3484 int end
= atoi(c
->argv
[3]->ptr
);
3486 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3488 addReply(c
,shared
.nokeyerr
);
3490 if (o
->type
!= REDIS_LIST
) {
3491 addReply(c
,shared
.wrongtypeerr
);
3493 list
*list
= o
->ptr
;
3495 int llen
= listLength(list
);
3496 int j
, ltrim
, rtrim
;
3498 /* convert negative indexes */
3499 if (start
< 0) start
= llen
+start
;
3500 if (end
< 0) end
= llen
+end
;
3501 if (start
< 0) start
= 0;
3502 if (end
< 0) end
= 0;
3504 /* indexes sanity checks */
3505 if (start
> end
|| start
>= llen
) {
3506 /* Out of range start or start > end result in empty list */
3510 if (end
>= llen
) end
= llen
-1;
3515 /* Remove list elements to perform the trim */
3516 for (j
= 0; j
< ltrim
; j
++) {
3517 ln
= listFirst(list
);
3518 listDelNode(list
,ln
);
3520 for (j
= 0; j
< rtrim
; j
++) {
3521 ln
= listLast(list
);
3522 listDelNode(list
,ln
);
3525 addReply(c
,shared
.ok
);
3530 static void lremCommand(redisClient
*c
) {
3533 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3535 addReply(c
,shared
.czero
);
3537 if (o
->type
!= REDIS_LIST
) {
3538 addReply(c
,shared
.wrongtypeerr
);
3540 list
*list
= o
->ptr
;
3541 listNode
*ln
, *next
;
3542 int toremove
= atoi(c
->argv
[2]->ptr
);
3547 toremove
= -toremove
;
3550 ln
= fromtail
? list
->tail
: list
->head
;
3552 robj
*ele
= listNodeValue(ln
);
3554 next
= fromtail
? ln
->prev
: ln
->next
;
3555 if (compareStringObjects(ele
,c
->argv
[3]) == 0) {
3556 listDelNode(list
,ln
);
3559 if (toremove
&& removed
== toremove
) break;
3563 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",removed
));
3568 /* This is the semantic of this command:
3569 * RPOPLPUSH srclist dstlist:
3570 * IF LLEN(srclist) > 0
3571 * element = RPOP srclist
3572 * LPUSH dstlist element
3579 * The idea is to be able to get an element from a list in a reliable way
3580 * since the element is not just returned but pushed against another list
3581 * as well. This command was originally proposed by Ezra Zygmuntowicz.
3583 static void rpoplpushcommand(redisClient
*c
) {
3586 sobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3588 addReply(c
,shared
.nullbulk
);
3590 if (sobj
->type
!= REDIS_LIST
) {
3591 addReply(c
,shared
.wrongtypeerr
);
3593 list
*srclist
= sobj
->ptr
;
3594 listNode
*ln
= listLast(srclist
);
3597 addReply(c
,shared
.nullbulk
);
3599 robj
*dobj
= lookupKeyWrite(c
->db
,c
->argv
[2]);
3600 robj
*ele
= listNodeValue(ln
);
3605 /* Create the list if the key does not exist */
3606 dobj
= createListObject();
3607 dictAdd(c
->db
->dict
,c
->argv
[2],dobj
);
3608 incrRefCount(c
->argv
[2]);
3609 } else if (dobj
->type
!= REDIS_LIST
) {
3610 addReply(c
,shared
.wrongtypeerr
);
3613 /* Add the element to the target list */
3614 dstlist
= dobj
->ptr
;
3615 listAddNodeHead(dstlist
,ele
);
3618 /* Send the element to the client as reply as well */
3619 addReplyBulkLen(c
,ele
);
3621 addReply(c
,shared
.crlf
);
3623 /* Finally remove the element from the source list */
3624 listDelNode(srclist
,ln
);
3632 /* ==================================== Sets ================================ */
3634 static void saddCommand(redisClient
*c
) {
3637 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3639 set
= createSetObject();
3640 dictAdd(c
->db
->dict
,c
->argv
[1],set
);
3641 incrRefCount(c
->argv
[1]);
3643 if (set
->type
!= REDIS_SET
) {
3644 addReply(c
,shared
.wrongtypeerr
);
3648 if (dictAdd(set
->ptr
,c
->argv
[2],NULL
) == DICT_OK
) {
3649 incrRefCount(c
->argv
[2]);
3651 addReply(c
,shared
.cone
);
3653 addReply(c
,shared
.czero
);
3657 static void sremCommand(redisClient
*c
) {
3660 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3662 addReply(c
,shared
.czero
);
3664 if (set
->type
!= REDIS_SET
) {
3665 addReply(c
,shared
.wrongtypeerr
);
3668 if (dictDelete(set
->ptr
,c
->argv
[2]) == DICT_OK
) {
3670 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
3671 addReply(c
,shared
.cone
);
3673 addReply(c
,shared
.czero
);
3678 static void smoveCommand(redisClient
*c
) {
3679 robj
*srcset
, *dstset
;
3681 srcset
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3682 dstset
= lookupKeyWrite(c
->db
,c
->argv
[2]);
3684 /* If the source key does not exist return 0, if it's of the wrong type
3686 if (srcset
== NULL
|| srcset
->type
!= REDIS_SET
) {
3687 addReply(c
, srcset
? shared
.wrongtypeerr
: shared
.czero
);
3690 /* Error if the destination key is not a set as well */
3691 if (dstset
&& dstset
->type
!= REDIS_SET
) {
3692 addReply(c
,shared
.wrongtypeerr
);
3695 /* Remove the element from the source set */
3696 if (dictDelete(srcset
->ptr
,c
->argv
[3]) == DICT_ERR
) {
3697 /* Key not found in the src set! return zero */
3698 addReply(c
,shared
.czero
);
3702 /* Add the element to the destination set */
3704 dstset
= createSetObject();
3705 dictAdd(c
->db
->dict
,c
->argv
[2],dstset
);
3706 incrRefCount(c
->argv
[2]);
3708 if (dictAdd(dstset
->ptr
,c
->argv
[3],NULL
) == DICT_OK
)
3709 incrRefCount(c
->argv
[3]);
3710 addReply(c
,shared
.cone
);
3713 static void sismemberCommand(redisClient
*c
) {
3716 set
= lookupKeyRead(c
->db
,c
->argv
[1]);
3718 addReply(c
,shared
.czero
);
3720 if (set
->type
!= REDIS_SET
) {
3721 addReply(c
,shared
.wrongtypeerr
);
3724 if (dictFind(set
->ptr
,c
->argv
[2]))
3725 addReply(c
,shared
.cone
);
3727 addReply(c
,shared
.czero
);
3731 static void scardCommand(redisClient
*c
) {
3735 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3737 addReply(c
,shared
.czero
);
3740 if (o
->type
!= REDIS_SET
) {
3741 addReply(c
,shared
.wrongtypeerr
);
3744 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3750 static void spopCommand(redisClient
*c
) {
3754 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3756 addReply(c
,shared
.nullbulk
);
3758 if (set
->type
!= REDIS_SET
) {
3759 addReply(c
,shared
.wrongtypeerr
);
3762 de
= dictGetRandomKey(set
->ptr
);
3764 addReply(c
,shared
.nullbulk
);
3766 robj
*ele
= dictGetEntryKey(de
);
3768 addReplyBulkLen(c
,ele
);
3770 addReply(c
,shared
.crlf
);
3771 dictDelete(set
->ptr
,ele
);
3772 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
3778 static void srandmemberCommand(redisClient
*c
) {
3782 set
= lookupKeyRead(c
->db
,c
->argv
[1]);
3784 addReply(c
,shared
.nullbulk
);
3786 if (set
->type
!= REDIS_SET
) {
3787 addReply(c
,shared
.wrongtypeerr
);
3790 de
= dictGetRandomKey(set
->ptr
);
3792 addReply(c
,shared
.nullbulk
);
3794 robj
*ele
= dictGetEntryKey(de
);
3796 addReplyBulkLen(c
,ele
);
3798 addReply(c
,shared
.crlf
);
3803 static int qsortCompareSetsByCardinality(const void *s1
, const void *s2
) {
3804 dict
**d1
= (void*) s1
, **d2
= (void*) s2
;
3806 return dictSize(*d1
)-dictSize(*d2
);
3809 static void sinterGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
) {
3810 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
3813 robj
*lenobj
= NULL
, *dstset
= NULL
;
3814 int j
, cardinality
= 0;
3816 for (j
= 0; j
< setsnum
; j
++) {
3820 lookupKeyWrite(c
->db
,setskeys
[j
]) :
3821 lookupKeyRead(c
->db
,setskeys
[j
]);
3825 deleteKey(c
->db
,dstkey
);
3826 addReply(c
,shared
.ok
);
3828 addReply(c
,shared
.nullmultibulk
);
3832 if (setobj
->type
!= REDIS_SET
) {
3834 addReply(c
,shared
.wrongtypeerr
);
3837 dv
[j
] = setobj
->ptr
;
3839 /* Sort sets from the smallest to largest, this will improve our
3840 * algorithm's performace */
3841 qsort(dv
,setsnum
,sizeof(dict
*),qsortCompareSetsByCardinality
);
3843 /* The first thing we should output is the total number of elements...
3844 * since this is a multi-bulk write, but at this stage we don't know
3845 * the intersection set size, so we use a trick, append an empty object
3846 * to the output list and save the pointer to later modify it with the
3849 lenobj
= createObject(REDIS_STRING
,NULL
);
3851 decrRefCount(lenobj
);
3853 /* If we have a target key where to store the resulting set
3854 * create this key with an empty set inside */
3855 dstset
= createSetObject();
3858 /* Iterate all the elements of the first (smallest) set, and test
3859 * the element against all the other sets, if at least one set does
3860 * not include the element it is discarded */
3861 di
= dictGetIterator(dv
[0]);
3863 while((de
= dictNext(di
)) != NULL
) {
3866 for (j
= 1; j
< setsnum
; j
++)
3867 if (dictFind(dv
[j
],dictGetEntryKey(de
)) == NULL
) break;
3869 continue; /* at least one set does not contain the member */
3870 ele
= dictGetEntryKey(de
);
3872 addReplyBulkLen(c
,ele
);
3874 addReply(c
,shared
.crlf
);
3877 dictAdd(dstset
->ptr
,ele
,NULL
);
3881 dictReleaseIterator(di
);
3884 /* Store the resulting set into the target */
3885 deleteKey(c
->db
,dstkey
);
3886 dictAdd(c
->db
->dict
,dstkey
,dstset
);
3887 incrRefCount(dstkey
);
3891 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%d\r\n",cardinality
);
3893 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3894 dictSize((dict
*)dstset
->ptr
)));
3900 static void sinterCommand(redisClient
*c
) {
3901 sinterGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
);
3904 static void sinterstoreCommand(redisClient
*c
) {
3905 sinterGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1]);
3908 #define REDIS_OP_UNION 0
3909 #define REDIS_OP_DIFF 1
3911 static void sunionDiffGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
, int op
) {
3912 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
3915 robj
*dstset
= NULL
;
3916 int j
, cardinality
= 0;
3918 for (j
= 0; j
< setsnum
; j
++) {
3922 lookupKeyWrite(c
->db
,setskeys
[j
]) :
3923 lookupKeyRead(c
->db
,setskeys
[j
]);
3928 if (setobj
->type
!= REDIS_SET
) {
3930 addReply(c
,shared
.wrongtypeerr
);
3933 dv
[j
] = setobj
->ptr
;
3936 /* We need a temp set object to store our union. If the dstkey
3937 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
3938 * this set object will be the resulting object to set into the target key*/
3939 dstset
= createSetObject();
3941 /* Iterate all the elements of all the sets, add every element a single
3942 * time to the result set */
3943 for (j
= 0; j
< setsnum
; j
++) {
3944 if (op
== REDIS_OP_DIFF
&& j
== 0 && !dv
[j
]) break; /* result set is empty */
3945 if (!dv
[j
]) continue; /* non existing keys are like empty sets */
3947 di
= dictGetIterator(dv
[j
]);
3949 while((de
= dictNext(di
)) != NULL
) {
3952 /* dictAdd will not add the same element multiple times */
3953 ele
= dictGetEntryKey(de
);
3954 if (op
== REDIS_OP_UNION
|| j
== 0) {
3955 if (dictAdd(dstset
->ptr
,ele
,NULL
) == DICT_OK
) {
3959 } else if (op
== REDIS_OP_DIFF
) {
3960 if (dictDelete(dstset
->ptr
,ele
) == DICT_OK
) {
3965 dictReleaseIterator(di
);
3967 if (op
== REDIS_OP_DIFF
&& cardinality
== 0) break; /* result set is empty */
3970 /* Output the content of the resulting set, if not in STORE mode */
3972 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",cardinality
));
3973 di
= dictGetIterator(dstset
->ptr
);
3974 while((de
= dictNext(di
)) != NULL
) {
3977 ele
= dictGetEntryKey(de
);
3978 addReplyBulkLen(c
,ele
);
3980 addReply(c
,shared
.crlf
);
3982 dictReleaseIterator(di
);
3984 /* If we have a target key where to store the resulting set
3985 * create this key with the result set inside */
3986 deleteKey(c
->db
,dstkey
);
3987 dictAdd(c
->db
->dict
,dstkey
,dstset
);
3988 incrRefCount(dstkey
);
3993 decrRefCount(dstset
);
3995 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3996 dictSize((dict
*)dstset
->ptr
)));
4002 static void sunionCommand(redisClient
*c
) {
4003 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_UNION
);
4006 static void sunionstoreCommand(redisClient
*c
) {
4007 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_UNION
);
4010 static void sdiffCommand(redisClient
*c
) {
4011 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_DIFF
);
4014 static void sdiffstoreCommand(redisClient
*c
) {
4015 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_DIFF
);
4018 /* ==================================== ZSets =============================== */
4020 /* ZSETs are ordered sets using two data structures to hold the same elements
4021 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
4024 * The elements are added to an hash table mapping Redis objects to scores.
4025 * At the same time the elements are added to a skip list mapping scores
4026 * to Redis objects (so objects are sorted by scores in this "view"). */
4028 /* This skiplist implementation is almost a C translation of the original
4029 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
4030 * Alternative to Balanced Trees", modified in three ways:
4031 * a) this implementation allows for repeated values.
4032 * b) the comparison is not just by key (our 'score') but by satellite data.
4033 * c) there is a back pointer, so it's a doubly linked list with the back
4034 * pointers being only at "level 1". This allows to traverse the list
4035 * from tail to head, useful for ZREVRANGE. */
4037 static zskiplistNode
*zslCreateNode(int level
, double score
, robj
*obj
) {
4038 zskiplistNode
*zn
= zmalloc(sizeof(*zn
));
4040 zn
->forward
= zmalloc(sizeof(zskiplistNode
*) * level
);
4046 static zskiplist
*zslCreate(void) {
4050 zsl
= zmalloc(sizeof(*zsl
));
4053 zsl
->header
= zslCreateNode(ZSKIPLIST_MAXLEVEL
,0,NULL
);
4054 for (j
= 0; j
< ZSKIPLIST_MAXLEVEL
; j
++)
4055 zsl
->header
->forward
[j
] = NULL
;
4056 zsl
->header
->backward
= NULL
;
4061 static void zslFreeNode(zskiplistNode
*node
) {
4062 decrRefCount(node
->obj
);
4063 zfree(node
->forward
);
4067 static void zslFree(zskiplist
*zsl
) {
4068 zskiplistNode
*node
= zsl
->header
->forward
[0], *next
;
4070 zfree(zsl
->header
->forward
);
4073 next
= node
->forward
[0];
4080 static int zslRandomLevel(void) {
4082 while ((random()&0xFFFF) < (ZSKIPLIST_P
* 0xFFFF))
4087 static void zslInsert(zskiplist
*zsl
, double score
, robj
*obj
) {
4088 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
4092 for (i
= zsl
->level
-1; i
>= 0; i
--) {
4093 while (x
->forward
[i
] &&
4094 (x
->forward
[i
]->score
< score
||
4095 (x
->forward
[i
]->score
== score
&&
4096 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0)))
4100 /* we assume the key is not already inside, since we allow duplicated
4101 * scores, and the re-insertion of score and redis object should never
4102 * happpen since the caller of zslInsert() should test in the hash table
4103 * if the element is already inside or not. */
4104 level
= zslRandomLevel();
4105 if (level
> zsl
->level
) {
4106 for (i
= zsl
->level
; i
< level
; i
++)
4107 update
[i
] = zsl
->header
;
4110 x
= zslCreateNode(level
,score
,obj
);
4111 for (i
= 0; i
< level
; i
++) {
4112 x
->forward
[i
] = update
[i
]->forward
[i
];
4113 update
[i
]->forward
[i
] = x
;
4115 x
->backward
= (update
[0] == zsl
->header
) ? NULL
: update
[0];
4117 x
->forward
[0]->backward
= x
;
4123 /* Delete an element with matching score/object from the skiplist. */
4124 static int zslDelete(zskiplist
*zsl
, double score
, robj
*obj
) {
4125 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
4129 for (i
= zsl
->level
-1; i
>= 0; i
--) {
4130 while (x
->forward
[i
] &&
4131 (x
->forward
[i
]->score
< score
||
4132 (x
->forward
[i
]->score
== score
&&
4133 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0)))
4137 /* We may have multiple elements with the same score, what we need
4138 * is to find the element with both the right score and object. */
4140 if (x
&& score
== x
->score
&& compareStringObjects(x
->obj
,obj
) == 0) {
4141 for (i
= 0; i
< zsl
->level
; i
++) {
4142 if (update
[i
]->forward
[i
] != x
) break;
4143 update
[i
]->forward
[i
] = x
->forward
[i
];
4145 if (x
->forward
[0]) {
4146 x
->forward
[0]->backward
= (x
->backward
== zsl
->header
) ?
4149 zsl
->tail
= x
->backward
;
4152 while(zsl
->level
> 1 && zsl
->header
->forward
[zsl
->level
-1] == NULL
)
4157 return 0; /* not found */
4159 return 0; /* not found */
4162 /* Delete all the elements with score between min and max from the skiplist.
4163 * Min and mx are inclusive, so a score >= min || score <= max is deleted.
4164 * Note that this function takes the reference to the hash table view of the
4165 * sorted set, in order to remove the elements from the hash table too. */
4166 static unsigned long zslDeleteRange(zskiplist
*zsl
, double min
, double max
, dict
*dict
) {
4167 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
4168 unsigned long removed
= 0;
4172 for (i
= zsl
->level
-1; i
>= 0; i
--) {
4173 while (x
->forward
[i
] && x
->forward
[i
]->score
< min
)
4177 /* We may have multiple elements with the same score, what we need
4178 * is to find the element with both the right score and object. */
4180 while (x
&& x
->score
<= max
) {
4181 zskiplistNode
*next
;
4183 for (i
= 0; i
< zsl
->level
; i
++) {
4184 if (update
[i
]->forward
[i
] != x
) break;
4185 update
[i
]->forward
[i
] = x
->forward
[i
];
4187 if (x
->forward
[0]) {
4188 x
->forward
[0]->backward
= (x
->backward
== zsl
->header
) ?
4191 zsl
->tail
= x
->backward
;
4193 next
= x
->forward
[0];
4194 dictDelete(dict
,x
->obj
);
4196 while(zsl
->level
> 1 && zsl
->header
->forward
[zsl
->level
-1] == NULL
)
4202 return removed
; /* not found */
4205 /* Find the first node having a score equal or greater than the specified one.
4206 * Returns NULL if there is no match. */
4207 static zskiplistNode
*zslFirstWithScore(zskiplist
*zsl
, double score
) {
4212 for (i
= zsl
->level
-1; i
>= 0; i
--) {
4213 while (x
->forward
[i
] && x
->forward
[i
]->score
< score
)
4216 /* We may have multiple elements with the same score, what we need
4217 * is to find the element with both the right score and object. */
4218 return x
->forward
[0];
4221 /* The actual Z-commands implementations */
4223 static void zaddCommand(redisClient
*c
) {
4228 zsetobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4229 if (zsetobj
== NULL
) {
4230 zsetobj
= createZsetObject();
4231 dictAdd(c
->db
->dict
,c
->argv
[1],zsetobj
);
4232 incrRefCount(c
->argv
[1]);
4234 if (zsetobj
->type
!= REDIS_ZSET
) {
4235 addReply(c
,shared
.wrongtypeerr
);
4239 score
= zmalloc(sizeof(double));
4240 *score
= strtod(c
->argv
[2]->ptr
,NULL
);
4242 if (dictAdd(zs
->dict
,c
->argv
[3],score
) == DICT_OK
) {
4243 /* case 1: New element */
4244 incrRefCount(c
->argv
[3]); /* added to hash */
4245 zslInsert(zs
->zsl
,*score
,c
->argv
[3]);
4246 incrRefCount(c
->argv
[3]); /* added to skiplist */
4248 addReply(c
,shared
.cone
);
4253 /* case 2: Score update operation */
4254 de
= dictFind(zs
->dict
,c
->argv
[3]);
4256 oldscore
= dictGetEntryVal(de
);
4257 if (*score
!= *oldscore
) {
4260 deleted
= zslDelete(zs
->zsl
,*oldscore
,c
->argv
[3]);
4261 assert(deleted
!= 0);
4262 zslInsert(zs
->zsl
,*score
,c
->argv
[3]);
4263 incrRefCount(c
->argv
[3]);
4264 dictReplace(zs
->dict
,c
->argv
[3],score
);
4269 addReply(c
,shared
.czero
);
4273 static void zremCommand(redisClient
*c
) {
4277 zsetobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4278 if (zsetobj
== NULL
) {
4279 addReply(c
,shared
.czero
);
4285 if (zsetobj
->type
!= REDIS_ZSET
) {
4286 addReply(c
,shared
.wrongtypeerr
);
4290 de
= dictFind(zs
->dict
,c
->argv
[2]);
4292 addReply(c
,shared
.czero
);
4295 /* Delete from the skiplist */
4296 oldscore
= dictGetEntryVal(de
);
4297 deleted
= zslDelete(zs
->zsl
,*oldscore
,c
->argv
[2]);
4298 assert(deleted
!= 0);
4300 /* Delete from the hash table */
4301 dictDelete(zs
->dict
,c
->argv
[2]);
4302 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
4304 addReply(c
,shared
.cone
);
4308 static void zremrangebyscoreCommand(redisClient
*c
) {
4309 double min
= strtod(c
->argv
[2]->ptr
,NULL
);
4310 double max
= strtod(c
->argv
[3]->ptr
,NULL
);
4314 zsetobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4315 if (zsetobj
== NULL
) {
4316 addReply(c
,shared
.czero
);
4320 if (zsetobj
->type
!= REDIS_ZSET
) {
4321 addReply(c
,shared
.wrongtypeerr
);
4325 deleted
= zslDeleteRange(zs
->zsl
,min
,max
,zs
->dict
);
4326 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
4327 server
.dirty
+= deleted
;
4328 addReplySds(c
,sdscatprintf(sdsempty(),":%lu\r\n",deleted
));
4332 static void zrangeGenericCommand(redisClient
*c
, int reverse
) {
4334 int start
= atoi(c
->argv
[2]->ptr
);
4335 int end
= atoi(c
->argv
[3]->ptr
);
4337 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4339 addReply(c
,shared
.nullmultibulk
);
4341 if (o
->type
!= REDIS_ZSET
) {
4342 addReply(c
,shared
.wrongtypeerr
);
4344 zset
*zsetobj
= o
->ptr
;
4345 zskiplist
*zsl
= zsetobj
->zsl
;
4348 int llen
= zsl
->length
;
4352 /* convert negative indexes */
4353 if (start
< 0) start
= llen
+start
;
4354 if (end
< 0) end
= llen
+end
;
4355 if (start
< 0) start
= 0;
4356 if (end
< 0) end
= 0;
4358 /* indexes sanity checks */
4359 if (start
> end
|| start
>= llen
) {
4360 /* Out of range start or start > end result in empty list */
4361 addReply(c
,shared
.emptymultibulk
);
4364 if (end
>= llen
) end
= llen
-1;
4365 rangelen
= (end
-start
)+1;
4367 /* Return the result in form of a multi-bulk reply */
4373 ln
= zsl
->header
->forward
[0];
4375 ln
= ln
->forward
[0];
4378 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",rangelen
));
4379 for (j
= 0; j
< rangelen
; j
++) {
4381 addReplyBulkLen(c
,ele
);
4383 addReply(c
,shared
.crlf
);
4384 ln
= reverse
? ln
->backward
: ln
->forward
[0];
4390 static void zrangeCommand(redisClient
*c
) {
4391 zrangeGenericCommand(c
,0);
4394 static void zrevrangeCommand(redisClient
*c
) {
4395 zrangeGenericCommand(c
,1);
4398 static void zrangebyscoreCommand(redisClient
*c
) {
4400 double min
= strtod(c
->argv
[2]->ptr
,NULL
);
4401 double max
= strtod(c
->argv
[3]->ptr
,NULL
);
4403 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4405 addReply(c
,shared
.nullmultibulk
);
4407 if (o
->type
!= REDIS_ZSET
) {
4408 addReply(c
,shared
.wrongtypeerr
);
4410 zset
*zsetobj
= o
->ptr
;
4411 zskiplist
*zsl
= zsetobj
->zsl
;
4414 unsigned int rangelen
= 0;
4416 /* Get the first node with the score >= min */
4417 ln
= zslFirstWithScore(zsl
,min
);
4419 /* No element matching the speciifed interval */
4420 addReply(c
,shared
.emptymultibulk
);
4424 /* We don't know in advance how many matching elements there
4425 * are in the list, so we push this object that will represent
4426 * the multi-bulk length in the output buffer, and will "fix"
4428 lenobj
= createObject(REDIS_STRING
,NULL
);
4431 while(ln
&& ln
->score
<= max
) {
4433 addReplyBulkLen(c
,ele
);
4435 addReply(c
,shared
.crlf
);
4436 ln
= ln
->forward
[0];
4439 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%d\r\n",rangelen
);
4444 static void zcardCommand(redisClient
*c
) {
4448 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4450 addReply(c
,shared
.czero
);
4453 if (o
->type
!= REDIS_ZSET
) {
4454 addReply(c
,shared
.wrongtypeerr
);
4457 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",zs
->zsl
->length
));
4462 static void zscoreCommand(redisClient
*c
) {
4466 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4468 addReply(c
,shared
.nullbulk
);
4471 if (o
->type
!= REDIS_ZSET
) {
4472 addReply(c
,shared
.wrongtypeerr
);
4477 de
= dictFind(zs
->dict
,c
->argv
[2]);
4479 addReply(c
,shared
.nullbulk
);
4482 double *score
= dictGetEntryVal(de
);
4484 snprintf(buf
,sizeof(buf
),"%.17g",*score
);
4485 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n%s\r\n",
4492 /* ========================= Non type-specific commands ==================== */
4494 static void flushdbCommand(redisClient
*c
) {
4495 server
.dirty
+= dictSize(c
->db
->dict
);
4496 dictEmpty(c
->db
->dict
);
4497 dictEmpty(c
->db
->expires
);
4498 addReply(c
,shared
.ok
);
4501 static void flushallCommand(redisClient
*c
) {
4502 server
.dirty
+= emptyDb();
4503 addReply(c
,shared
.ok
);
4504 rdbSave(server
.dbfilename
);
4508 static redisSortOperation
*createSortOperation(int type
, robj
*pattern
) {
4509 redisSortOperation
*so
= zmalloc(sizeof(*so
));
4511 so
->pattern
= pattern
;
4515 /* Return the value associated to the key with a name obtained
4516 * substituting the first occurence of '*' in 'pattern' with 'subst' */
4517 static robj
*lookupKeyByPattern(redisDb
*db
, robj
*pattern
, robj
*subst
) {
4521 int prefixlen
, sublen
, postfixlen
;
4522 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
4526 char buf
[REDIS_SORTKEY_MAX
+1];
4529 if (subst
->encoding
== REDIS_ENCODING_RAW
)
4530 incrRefCount(subst
);
4532 subst
= getDecodedObject(subst
);
4535 spat
= pattern
->ptr
;
4537 if (sdslen(spat
)+sdslen(ssub
)-1 > REDIS_SORTKEY_MAX
) return NULL
;
4538 p
= strchr(spat
,'*');
4539 if (!p
) return NULL
;
4542 sublen
= sdslen(ssub
);
4543 postfixlen
= sdslen(spat
)-(prefixlen
+1);
4544 memcpy(keyname
.buf
,spat
,prefixlen
);
4545 memcpy(keyname
.buf
+prefixlen
,ssub
,sublen
);
4546 memcpy(keyname
.buf
+prefixlen
+sublen
,p
+1,postfixlen
);
4547 keyname
.buf
[prefixlen
+sublen
+postfixlen
] = '\0';
4548 keyname
.len
= prefixlen
+sublen
+postfixlen
;
4550 keyobj
.refcount
= 1;
4551 keyobj
.type
= REDIS_STRING
;
4552 keyobj
.ptr
= ((char*)&keyname
)+(sizeof(long)*2);
4554 decrRefCount(subst
);
4556 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
4557 return lookupKeyRead(db
,&keyobj
);
4560 /* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
4561 * the additional parameter is not standard but a BSD-specific we have to
4562 * pass sorting parameters via the global 'server' structure */
4563 static int sortCompare(const void *s1
, const void *s2
) {
4564 const redisSortObject
*so1
= s1
, *so2
= s2
;
4567 if (!server
.sort_alpha
) {
4568 /* Numeric sorting. Here it's trivial as we precomputed scores */
4569 if (so1
->u
.score
> so2
->u
.score
) {
4571 } else if (so1
->u
.score
< so2
->u
.score
) {
4577 /* Alphanumeric sorting */
4578 if (server
.sort_bypattern
) {
4579 if (!so1
->u
.cmpobj
|| !so2
->u
.cmpobj
) {
4580 /* At least one compare object is NULL */
4581 if (so1
->u
.cmpobj
== so2
->u
.cmpobj
)
4583 else if (so1
->u
.cmpobj
== NULL
)
4588 /* We have both the objects, use strcoll */
4589 cmp
= strcoll(so1
->u
.cmpobj
->ptr
,so2
->u
.cmpobj
->ptr
);
4592 /* Compare elements directly */
4593 if (so1
->obj
->encoding
== REDIS_ENCODING_RAW
&&
4594 so2
->obj
->encoding
== REDIS_ENCODING_RAW
) {
4595 cmp
= strcoll(so1
->obj
->ptr
,so2
->obj
->ptr
);
4599 dec1
= so1
->obj
->encoding
== REDIS_ENCODING_RAW
?
4600 so1
->obj
: getDecodedObject(so1
->obj
);
4601 dec2
= so2
->obj
->encoding
== REDIS_ENCODING_RAW
?
4602 so2
->obj
: getDecodedObject(so2
->obj
);
4603 cmp
= strcoll(dec1
->ptr
,dec2
->ptr
);
4604 if (dec1
!= so1
->obj
) decrRefCount(dec1
);
4605 if (dec2
!= so2
->obj
) decrRefCount(dec2
);
4609 return server
.sort_desc
? -cmp
: cmp
;
4612 /* The SORT command is the most complex command in Redis. Warning: this code
4613 * is optimized for speed and a bit less for readability */
4614 static void sortCommand(redisClient
*c
) {
4617 int desc
= 0, alpha
= 0;
4618 int limit_start
= 0, limit_count
= -1, start
, end
;
4619 int j
, dontsort
= 0, vectorlen
;
4620 int getop
= 0; /* GET operation counter */
4621 robj
*sortval
, *sortby
= NULL
, *storekey
= NULL
;
4622 redisSortObject
*vector
; /* Resulting vector to sort */
4624 /* Lookup the key to sort. It must be of the right types */
4625 sortval
= lookupKeyRead(c
->db
,c
->argv
[1]);
4626 if (sortval
== NULL
) {
4627 addReply(c
,shared
.nokeyerr
);
4630 if (sortval
->type
!= REDIS_SET
&& sortval
->type
!= REDIS_LIST
) {
4631 addReply(c
,shared
.wrongtypeerr
);
4635 /* Create a list of operations to perform for every sorted element.
4636 * Operations can be GET/DEL/INCR/DECR */
4637 operations
= listCreate();
4638 listSetFreeMethod(operations
,zfree
);
4641 /* Now we need to protect sortval incrementing its count, in the future
4642 * SORT may have options able to overwrite/delete keys during the sorting
4643 * and the sorted key itself may get destroied */
4644 incrRefCount(sortval
);
4646 /* The SORT command has an SQL-alike syntax, parse it */
4647 while(j
< c
->argc
) {
4648 int leftargs
= c
->argc
-j
-1;
4649 if (!strcasecmp(c
->argv
[j
]->ptr
,"asc")) {
4651 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"desc")) {
4653 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"alpha")) {
4655 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"limit") && leftargs
>= 2) {
4656 limit_start
= atoi(c
->argv
[j
+1]->ptr
);
4657 limit_count
= atoi(c
->argv
[j
+2]->ptr
);
4659 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"store") && leftargs
>= 1) {
4660 storekey
= c
->argv
[j
+1];
4662 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"by") && leftargs
>= 1) {
4663 sortby
= c
->argv
[j
+1];
4664 /* If the BY pattern does not contain '*', i.e. it is constant,
4665 * we don't need to sort nor to lookup the weight keys. */
4666 if (strchr(c
->argv
[j
+1]->ptr
,'*') == NULL
) dontsort
= 1;
4668 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
4669 listAddNodeTail(operations
,createSortOperation(
4670 REDIS_SORT_GET
,c
->argv
[j
+1]));
4674 decrRefCount(sortval
);
4675 listRelease(operations
);
4676 addReply(c
,shared
.syntaxerr
);
4682 /* Load the sorting vector with all the objects to sort */
4683 vectorlen
= (sortval
->type
== REDIS_LIST
) ?
4684 listLength((list
*)sortval
->ptr
) :
4685 dictSize((dict
*)sortval
->ptr
);
4686 vector
= zmalloc(sizeof(redisSortObject
)*vectorlen
);
4688 if (sortval
->type
== REDIS_LIST
) {
4689 list
*list
= sortval
->ptr
;
4693 while((ln
= listYield(list
))) {
4694 robj
*ele
= ln
->value
;
4695 vector
[j
].obj
= ele
;
4696 vector
[j
].u
.score
= 0;
4697 vector
[j
].u
.cmpobj
= NULL
;
4701 dict
*set
= sortval
->ptr
;
4705 di
= dictGetIterator(set
);
4706 while((setele
= dictNext(di
)) != NULL
) {
4707 vector
[j
].obj
= dictGetEntryKey(setele
);
4708 vector
[j
].u
.score
= 0;
4709 vector
[j
].u
.cmpobj
= NULL
;
4712 dictReleaseIterator(di
);
4714 assert(j
== vectorlen
);
4716 /* Now it's time to load the right scores in the sorting vector */
4717 if (dontsort
== 0) {
4718 for (j
= 0; j
< vectorlen
; j
++) {
4722 byval
= lookupKeyByPattern(c
->db
,sortby
,vector
[j
].obj
);
4723 if (!byval
|| byval
->type
!= REDIS_STRING
) continue;
4725 if (byval
->encoding
== REDIS_ENCODING_RAW
) {
4726 vector
[j
].u
.cmpobj
= byval
;
4727 incrRefCount(byval
);
4729 vector
[j
].u
.cmpobj
= getDecodedObject(byval
);
4732 if (byval
->encoding
== REDIS_ENCODING_RAW
) {
4733 vector
[j
].u
.score
= strtod(byval
->ptr
,NULL
);
4735 if (byval
->encoding
== REDIS_ENCODING_INT
) {
4736 vector
[j
].u
.score
= (long)byval
->ptr
;
4743 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_RAW
)
4744 vector
[j
].u
.score
= strtod(vector
[j
].obj
->ptr
,NULL
);
4746 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_INT
)
4747 vector
[j
].u
.score
= (long) vector
[j
].obj
->ptr
;
4756 /* We are ready to sort the vector... perform a bit of sanity check
4757 * on the LIMIT option too. We'll use a partial version of quicksort. */
4758 start
= (limit_start
< 0) ? 0 : limit_start
;
4759 end
= (limit_count
< 0) ? vectorlen
-1 : start
+limit_count
-1;
4760 if (start
>= vectorlen
) {
4761 start
= vectorlen
-1;
4764 if (end
>= vectorlen
) end
= vectorlen
-1;
4766 if (dontsort
== 0) {
4767 server
.sort_desc
= desc
;
4768 server
.sort_alpha
= alpha
;
4769 server
.sort_bypattern
= sortby
? 1 : 0;
4770 if (sortby
&& (start
!= 0 || end
!= vectorlen
-1))
4771 pqsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
, start
,end
);
4773 qsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
);
4776 /* Send command output to the output buffer, performing the specified
4777 * GET/DEL/INCR/DECR operations if any. */
4778 outputlen
= getop
? getop
*(end
-start
+1) : end
-start
+1;
4779 if (storekey
== NULL
) {
4780 /* STORE option not specified, sent the sorting result to client */
4781 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",outputlen
));
4782 for (j
= start
; j
<= end
; j
++) {
4785 addReplyBulkLen(c
,vector
[j
].obj
);
4786 addReply(c
,vector
[j
].obj
);
4787 addReply(c
,shared
.crlf
);
4789 listRewind(operations
);
4790 while((ln
= listYield(operations
))) {
4791 redisSortOperation
*sop
= ln
->value
;
4792 robj
*val
= lookupKeyByPattern(c
->db
,sop
->pattern
,
4795 if (sop
->type
== REDIS_SORT_GET
) {
4796 if (!val
|| val
->type
!= REDIS_STRING
) {
4797 addReply(c
,shared
.nullbulk
);
4799 addReplyBulkLen(c
,val
);
4801 addReply(c
,shared
.crlf
);
4804 assert(sop
->type
== REDIS_SORT_GET
); /* always fails */
4809 robj
*listObject
= createListObject();
4810 list
*listPtr
= (list
*) listObject
->ptr
;
4812 /* STORE option specified, set the sorting result as a List object */
4813 for (j
= start
; j
<= end
; j
++) {
4816 listAddNodeTail(listPtr
,vector
[j
].obj
);
4817 incrRefCount(vector
[j
].obj
);
4819 listRewind(operations
);
4820 while((ln
= listYield(operations
))) {
4821 redisSortOperation
*sop
= ln
->value
;
4822 robj
*val
= lookupKeyByPattern(c
->db
,sop
->pattern
,
4825 if (sop
->type
== REDIS_SORT_GET
) {
4826 if (!val
|| val
->type
!= REDIS_STRING
) {
4827 listAddNodeTail(listPtr
,createStringObject("",0));
4829 listAddNodeTail(listPtr
,val
);
4833 assert(sop
->type
== REDIS_SORT_GET
); /* always fails */
4837 if (dictReplace(c
->db
->dict
,storekey
,listObject
)) {
4838 incrRefCount(storekey
);
4840 /* Note: we add 1 because the DB is dirty anyway since even if the
4841 * SORT result is empty a new key is set and maybe the old content
4843 server
.dirty
+= 1+outputlen
;
4844 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",outputlen
));
4848 decrRefCount(sortval
);
4849 listRelease(operations
);
4850 for (j
= 0; j
< vectorlen
; j
++) {
4851 if (sortby
&& alpha
&& vector
[j
].u
.cmpobj
)
4852 decrRefCount(vector
[j
].u
.cmpobj
);
4857 static void infoCommand(redisClient
*c
) {
4859 time_t uptime
= time(NULL
)-server
.stat_starttime
;
4862 info
= sdscatprintf(sdsempty(),
4863 "redis_version:%s\r\n"
4865 "uptime_in_seconds:%d\r\n"
4866 "uptime_in_days:%d\r\n"
4867 "connected_clients:%d\r\n"
4868 "connected_slaves:%d\r\n"
4869 "used_memory:%zu\r\n"
4870 "changes_since_last_save:%lld\r\n"
4871 "bgsave_in_progress:%d\r\n"
4872 "last_save_time:%d\r\n"
4873 "total_connections_received:%lld\r\n"
4874 "total_commands_processed:%lld\r\n"
4877 (sizeof(long) == 8) ? "64" : "32",
4880 listLength(server
.clients
)-listLength(server
.slaves
),
4881 listLength(server
.slaves
),
4884 server
.bgsaveinprogress
,
4886 server
.stat_numconnections
,
4887 server
.stat_numcommands
,
4888 server
.masterhost
== NULL
? "master" : "slave"
4890 if (server
.masterhost
) {
4891 info
= sdscatprintf(info
,
4892 "master_host:%s\r\n"
4893 "master_port:%d\r\n"
4894 "master_link_status:%s\r\n"
4895 "master_last_io_seconds_ago:%d\r\n"
4898 (server
.replstate
== REDIS_REPL_CONNECTED
) ?
4900 server
.master
? ((int)(time(NULL
)-server
.master
->lastinteraction
)) : -1
4903 for (j
= 0; j
< server
.dbnum
; j
++) {
4904 long long keys
, vkeys
;
4906 keys
= dictSize(server
.db
[j
].dict
);
4907 vkeys
= dictSize(server
.db
[j
].expires
);
4908 if (keys
|| vkeys
) {
4909 info
= sdscatprintf(info
, "db%d: keys=%lld,expires=%lld\r\n",
4913 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(info
)));
4914 addReplySds(c
,info
);
4915 addReply(c
,shared
.crlf
);
4918 static void monitorCommand(redisClient
*c
) {
4919 /* ignore MONITOR if aleady slave or in monitor mode */
4920 if (c
->flags
& REDIS_SLAVE
) return;
4922 c
->flags
|= (REDIS_SLAVE
|REDIS_MONITOR
);
4924 listAddNodeTail(server
.monitors
,c
);
4925 addReply(c
,shared
.ok
);
4928 /* ================================= Expire ================================= */
4929 static int removeExpire(redisDb
*db
, robj
*key
) {
4930 if (dictDelete(db
->expires
,key
) == DICT_OK
) {
4937 static int setExpire(redisDb
*db
, robj
*key
, time_t when
) {
4938 if (dictAdd(db
->expires
,key
,(void*)when
) == DICT_ERR
) {
4946 /* Return the expire time of the specified key, or -1 if no expire
4947 * is associated with this key (i.e. the key is non volatile) */
4948 static time_t getExpire(redisDb
*db
, robj
*key
) {
4951 /* No expire? return ASAP */
4952 if (dictSize(db
->expires
) == 0 ||
4953 (de
= dictFind(db
->expires
,key
)) == NULL
) return -1;
4955 return (time_t) dictGetEntryVal(de
);
4958 static int expireIfNeeded(redisDb
*db
, robj
*key
) {
4962 /* No expire? return ASAP */
4963 if (dictSize(db
->expires
) == 0 ||
4964 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
4966 /* Lookup the expire */
4967 when
= (time_t) dictGetEntryVal(de
);
4968 if (time(NULL
) <= when
) return 0;
4970 /* Delete the key */
4971 dictDelete(db
->expires
,key
);
4972 return dictDelete(db
->dict
,key
) == DICT_OK
;
4975 static int deleteIfVolatile(redisDb
*db
, robj
*key
) {
4978 /* No expire? return ASAP */
4979 if (dictSize(db
->expires
) == 0 ||
4980 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
4982 /* Delete the key */
4984 dictDelete(db
->expires
,key
);
4985 return dictDelete(db
->dict
,key
) == DICT_OK
;
4988 static void expireGenericCommand(redisClient
*c
, robj
*key
, time_t seconds
) {
4991 de
= dictFind(c
->db
->dict
,key
);
4993 addReply(c
,shared
.czero
);
4997 if (deleteKey(c
->db
,key
)) server
.dirty
++;
4998 addReply(c
, shared
.cone
);
5001 time_t when
= time(NULL
)+seconds
;
5002 if (setExpire(c
->db
,key
,when
)) {
5003 addReply(c
,shared
.cone
);
5006 addReply(c
,shared
.czero
);
5012 static void expireCommand(redisClient
*c
) {
5013 expireGenericCommand(c
,c
->argv
[1],strtol(c
->argv
[2]->ptr
,NULL
,10));
5016 static void expireatCommand(redisClient
*c
) {
5017 expireGenericCommand(c
,c
->argv
[1],strtol(c
->argv
[2]->ptr
,NULL
,10)-time(NULL
));
5020 static void ttlCommand(redisClient
*c
) {
5024 expire
= getExpire(c
->db
,c
->argv
[1]);
5026 ttl
= (int) (expire
-time(NULL
));
5027 if (ttl
< 0) ttl
= -1;
5029 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",ttl
));
5032 static void msetGenericCommand(redisClient
*c
, int nx
) {
5035 if ((c
->argc
% 2) == 0) {
5036 addReplySds(c
,sdsnew("-ERR wrong number of arguments\r\n"));
5039 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
5040 * set nothing at all if at least one already key exists. */
5042 for (j
= 1; j
< c
->argc
; j
+= 2) {
5043 if (dictFind(c
->db
->dict
,c
->argv
[j
]) != NULL
) {
5044 addReply(c
, shared
.czero
);
5050 for (j
= 1; j
< c
->argc
; j
+= 2) {
5053 retval
= dictAdd(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
5054 if (retval
== DICT_ERR
) {
5055 dictReplace(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
5056 incrRefCount(c
->argv
[j
+1]);
5058 incrRefCount(c
->argv
[j
]);
5059 incrRefCount(c
->argv
[j
+1]);
5061 removeExpire(c
->db
,c
->argv
[j
]);
5063 server
.dirty
+= (c
->argc
-1)/2;
5064 addReply(c
, nx
? shared
.cone
: shared
.ok
);
5067 static void msetCommand(redisClient
*c
) {
5068 msetGenericCommand(c
,0);
5071 static void msetnxCommand(redisClient
*c
) {
5072 msetGenericCommand(c
,1);
5075 /* =============================== Replication ============================= */
5077 static int syncWrite(int fd
, char *ptr
, ssize_t size
, int timeout
) {
5078 ssize_t nwritten
, ret
= size
;
5079 time_t start
= time(NULL
);
5083 if (aeWait(fd
,AE_WRITABLE
,1000) & AE_WRITABLE
) {
5084 nwritten
= write(fd
,ptr
,size
);
5085 if (nwritten
== -1) return -1;
5089 if ((time(NULL
)-start
) > timeout
) {
5097 static int syncRead(int fd
, char *ptr
, ssize_t size
, int timeout
) {
5098 ssize_t nread
, totread
= 0;
5099 time_t start
= time(NULL
);
5103 if (aeWait(fd
,AE_READABLE
,1000) & AE_READABLE
) {
5104 nread
= read(fd
,ptr
,size
);
5105 if (nread
== -1) return -1;
5110 if ((time(NULL
)-start
) > timeout
) {
5118 static int syncReadLine(int fd
, char *ptr
, ssize_t size
, int timeout
) {
5125 if (syncRead(fd
,&c
,1,timeout
) == -1) return -1;
5128 if (nread
&& *(ptr
-1) == '\r') *(ptr
-1) = '\0';
5139 static void syncCommand(redisClient
*c
) {
5140 /* ignore SYNC if aleady slave or in monitor mode */
5141 if (c
->flags
& REDIS_SLAVE
) return;
5143 /* SYNC can't be issued when the server has pending data to send to
5144 * the client about already issued commands. We need a fresh reply
5145 * buffer registering the differences between the BGSAVE and the current
5146 * dataset, so that we can copy to other slaves if needed. */
5147 if (listLength(c
->reply
) != 0) {
5148 addReplySds(c
,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
5152 redisLog(REDIS_NOTICE
,"Slave ask for synchronization");
5153 /* Here we need to check if there is a background saving operation
5154 * in progress, or if it is required to start one */
5155 if (server
.bgsaveinprogress
) {
5156 /* Ok a background save is in progress. Let's check if it is a good
5157 * one for replication, i.e. if there is another slave that is
5158 * registering differences since the server forked to save */
5162 listRewind(server
.slaves
);
5163 while((ln
= listYield(server
.slaves
))) {
5165 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) break;
5168 /* Perfect, the server is already registering differences for
5169 * another slave. Set the right state, and copy the buffer. */
5170 listRelease(c
->reply
);
5171 c
->reply
= listDup(slave
->reply
);
5172 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
5173 redisLog(REDIS_NOTICE
,"Waiting for end of BGSAVE for SYNC");
5175 /* No way, we need to wait for the next BGSAVE in order to
5176 * register differences */
5177 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
5178 redisLog(REDIS_NOTICE
,"Waiting for next BGSAVE for SYNC");
5181 /* Ok we don't have a BGSAVE in progress, let's start one */
5182 redisLog(REDIS_NOTICE
,"Starting BGSAVE for SYNC");
5183 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
5184 redisLog(REDIS_NOTICE
,"Replication failed, can't BGSAVE");
5185 addReplySds(c
,sdsnew("-ERR Unalbe to perform background save\r\n"));
5188 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
5191 c
->flags
|= REDIS_SLAVE
;
5193 listAddNodeTail(server
.slaves
,c
);
5197 static void sendBulkToSlave(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
5198 redisClient
*slave
= privdata
;
5200 REDIS_NOTUSED(mask
);
5201 char buf
[REDIS_IOBUF_LEN
];
5202 ssize_t nwritten
, buflen
;
5204 if (slave
->repldboff
== 0) {
5205 /* Write the bulk write count before to transfer the DB. In theory here
5206 * we don't know how much room there is in the output buffer of the
5207 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
5208 * operations) will never be smaller than the few bytes we need. */
5211 bulkcount
= sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
5213 if (write(fd
,bulkcount
,sdslen(bulkcount
)) != (signed)sdslen(bulkcount
))
5221 lseek(slave
->repldbfd
,slave
->repldboff
,SEEK_SET
);
5222 buflen
= read(slave
->repldbfd
,buf
,REDIS_IOBUF_LEN
);
5224 redisLog(REDIS_WARNING
,"Read error sending DB to slave: %s",
5225 (buflen
== 0) ? "premature EOF" : strerror(errno
));
5229 if ((nwritten
= write(fd
,buf
,buflen
)) == -1) {
5230 redisLog(REDIS_DEBUG
,"Write error sending DB to slave: %s",
5235 slave
->repldboff
+= nwritten
;
5236 if (slave
->repldboff
== slave
->repldbsize
) {
5237 close(slave
->repldbfd
);
5238 slave
->repldbfd
= -1;
5239 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
5240 slave
->replstate
= REDIS_REPL_ONLINE
;
5241 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
,
5242 sendReplyToClient
, slave
, NULL
) == AE_ERR
) {
5246 addReplySds(slave
,sdsempty());
5247 redisLog(REDIS_NOTICE
,"Synchronization with slave succeeded");
5251 /* This function is called at the end of every backgrond saving.
5252 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
5253 * otherwise REDIS_ERR is passed to the function.
5255 * The goal of this function is to handle slaves waiting for a successful
5256 * background saving in order to perform non-blocking synchronization. */
5257 static void updateSlavesWaitingBgsave(int bgsaveerr
) {
5259 int startbgsave
= 0;
5261 listRewind(server
.slaves
);
5262 while((ln
= listYield(server
.slaves
))) {
5263 redisClient
*slave
= ln
->value
;
5265 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) {
5267 slave
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
5268 } else if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) {
5269 struct redis_stat buf
;
5271 if (bgsaveerr
!= REDIS_OK
) {
5273 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE child returned an error");
5276 if ((slave
->repldbfd
= open(server
.dbfilename
,O_RDONLY
)) == -1 ||
5277 redis_fstat(slave
->repldbfd
,&buf
) == -1) {
5279 redisLog(REDIS_WARNING
,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno
));
5282 slave
->repldboff
= 0;
5283 slave
->repldbsize
= buf
.st_size
;
5284 slave
->replstate
= REDIS_REPL_SEND_BULK
;
5285 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
5286 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
, sendBulkToSlave
, slave
, NULL
) == AE_ERR
) {
5293 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
5294 listRewind(server
.slaves
);
5295 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE failed");
5296 while((ln
= listYield(server
.slaves
))) {
5297 redisClient
*slave
= ln
->value
;
5299 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
)
5306 static int syncWithMaster(void) {
5307 char buf
[1024], tmpfile
[256], authcmd
[1024];
5309 int fd
= anetTcpConnect(NULL
,server
.masterhost
,server
.masterport
);
5313 redisLog(REDIS_WARNING
,"Unable to connect to MASTER: %s",
5318 /* AUTH with the master if required. */
5319 if(server
.masterauth
) {
5320 snprintf(authcmd
, 1024, "AUTH %s\r\n", server
.masterauth
);
5321 if (syncWrite(fd
, authcmd
, strlen(server
.masterauth
)+7, 5) == -1) {
5323 redisLog(REDIS_WARNING
,"Unable to AUTH to MASTER: %s",
5327 /* Read the AUTH result. */
5328 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
5330 redisLog(REDIS_WARNING
,"I/O error reading auth result from MASTER: %s",
5334 if (buf
[0] != '+') {
5336 redisLog(REDIS_WARNING
,"Cannot AUTH to MASTER, is the masterauth password correct?");
5341 /* Issue the SYNC command */
5342 if (syncWrite(fd
,"SYNC \r\n",7,5) == -1) {
5344 redisLog(REDIS_WARNING
,"I/O error writing to MASTER: %s",
5348 /* Read the bulk write count */
5349 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
5351 redisLog(REDIS_WARNING
,"I/O error reading bulk count from MASTER: %s",
5355 if (buf
[0] != '$') {
5357 redisLog(REDIS_WARNING
,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
5360 dumpsize
= atoi(buf
+1);
5361 redisLog(REDIS_NOTICE
,"Receiving %d bytes data dump from MASTER",dumpsize
);
5362 /* Read the bulk write data on a temp file */
5363 snprintf(tmpfile
,256,"temp-%d.%ld.rdb",(int)time(NULL
),(long int)random());
5364 dfd
= open(tmpfile
,O_CREAT
|O_WRONLY
,0644);
5367 redisLog(REDIS_WARNING
,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno
));
5371 int nread
, nwritten
;
5373 nread
= read(fd
,buf
,(dumpsize
< 1024)?dumpsize
:1024);
5375 redisLog(REDIS_WARNING
,"I/O error trying to sync with MASTER: %s",
5381 nwritten
= write(dfd
,buf
,nread
);
5382 if (nwritten
== -1) {
5383 redisLog(REDIS_WARNING
,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno
));
5391 if (rename(tmpfile
,server
.dbfilename
) == -1) {
5392 redisLog(REDIS_WARNING
,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno
));
5398 if (rdbLoad(server
.dbfilename
) != REDIS_OK
) {
5399 redisLog(REDIS_WARNING
,"Failed trying to load the MASTER synchronization DB from disk");
5403 server
.master
= createClient(fd
);
5404 server
.master
->flags
|= REDIS_MASTER
;
5405 server
.replstate
= REDIS_REPL_CONNECTED
;
5409 static void slaveofCommand(redisClient
*c
) {
5410 if (!strcasecmp(c
->argv
[1]->ptr
,"no") &&
5411 !strcasecmp(c
->argv
[2]->ptr
,"one")) {
5412 if (server
.masterhost
) {
5413 sdsfree(server
.masterhost
);
5414 server
.masterhost
= NULL
;
5415 if (server
.master
) freeClient(server
.master
);
5416 server
.replstate
= REDIS_REPL_NONE
;
5417 redisLog(REDIS_NOTICE
,"MASTER MODE enabled (user request)");
5420 sdsfree(server
.masterhost
);
5421 server
.masterhost
= sdsdup(c
->argv
[1]->ptr
);
5422 server
.masterport
= atoi(c
->argv
[2]->ptr
);
5423 if (server
.master
) freeClient(server
.master
);
5424 server
.replstate
= REDIS_REPL_CONNECT
;
5425 redisLog(REDIS_NOTICE
,"SLAVE OF %s:%d enabled (user request)",
5426 server
.masterhost
, server
.masterport
);
5428 addReply(c
,shared
.ok
);
5431 /* ============================ Maxmemory directive ======================== */
5433 /* This function gets called when 'maxmemory' is set on the config file to limit
5434 * the max memory used by the server, and we are out of memory.
5435 * This function will try to, in order:
5437 * - Free objects from the free list
5438 * - Try to remove keys with an EXPIRE set
5440 * It is not possible to free enough memory to reach used-memory < maxmemory
5441 * the server will start refusing commands that will enlarge even more the
5444 static void freeMemoryIfNeeded(void) {
5445 while (server
.maxmemory
&& zmalloc_used_memory() > server
.maxmemory
) {
5446 if (listLength(server
.objfreelist
)) {
5449 listNode
*head
= listFirst(server
.objfreelist
);
5450 o
= listNodeValue(head
);
5451 listDelNode(server
.objfreelist
,head
);
5454 int j
, k
, freed
= 0;
5456 for (j
= 0; j
< server
.dbnum
; j
++) {
5458 robj
*minkey
= NULL
;
5459 struct dictEntry
*de
;
5461 if (dictSize(server
.db
[j
].expires
)) {
5463 /* From a sample of three keys drop the one nearest to
5464 * the natural expire */
5465 for (k
= 0; k
< 3; k
++) {
5468 de
= dictGetRandomKey(server
.db
[j
].expires
);
5469 t
= (time_t) dictGetEntryVal(de
);
5470 if (minttl
== -1 || t
< minttl
) {
5471 minkey
= dictGetEntryKey(de
);
5475 deleteKey(server
.db
+j
,minkey
);
5478 if (!freed
) return; /* nothing to free... */
5483 /* ============================== Append Only file ========================== */
5485 static void feedAppendOnlyFile(struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
) {
5486 sds buf
= sdsempty();
5492 /* The DB this command was targetting is not the same as the last command
5493 * we appendend. To issue a SELECT command is needed. */
5494 if (dictid
!= server
.appendseldb
) {
5497 snprintf(seldb
,sizeof(seldb
),"%d",dictid
);
5498 buf
= sdscatprintf(buf
,"*2\r\n$6\r\nSELECT\r\n$%d\r\n%s\r\n",
5499 strlen(seldb
),seldb
);
5500 server
.appendseldb
= dictid
;
5503 /* "Fix" the argv vector if the command is EXPIRE. We want to translate
5504 * EXPIREs into EXPIREATs calls */
5505 if (cmd
->proc
== expireCommand
) {
5508 tmpargv
[0] = createStringObject("EXPIREAT",8);
5509 tmpargv
[1] = argv
[1];
5510 incrRefCount(argv
[1]);
5511 when
= time(NULL
)+strtol(argv
[2]->ptr
,NULL
,10);
5512 tmpargv
[2] = createObject(REDIS_STRING
,
5513 sdscatprintf(sdsempty(),"%ld",when
));
5517 /* Append the actual command */
5518 buf
= sdscatprintf(buf
,"*%d\r\n",argc
);
5519 for (j
= 0; j
< argc
; j
++) {
5522 if (o
->encoding
!= REDIS_ENCODING_RAW
)
5523 o
= getDecodedObject(o
);
5524 buf
= sdscatprintf(buf
,"$%d\r\n",sdslen(o
->ptr
));
5525 buf
= sdscatlen(buf
,o
->ptr
,sdslen(o
->ptr
));
5526 buf
= sdscatlen(buf
,"\r\n",2);
5531 /* Free the objects from the modified argv for EXPIREAT */
5532 if (cmd
->proc
== expireCommand
) {
5533 for (j
= 0; j
< 3; j
++)
5534 decrRefCount(argv
[j
]);
5537 /* We want to perform a single write. This should be guaranteed atomic
5538 * at least if the filesystem we are writing is a real physical one.
5539 * While this will save us against the server being killed I don't think
5540 * there is much to do about the whole server stopping for power problems
5542 nwritten
= write(server
.appendfd
,buf
,sdslen(buf
));
5543 if (nwritten
!= (signed)sdslen(buf
)) {
5544 /* Ooops, we are in troubles. The best thing to do for now is
5545 * to simply exit instead to give the illusion that everything is
5546 * working as expected. */
5547 if (nwritten
== -1) {
5548 redisLog(REDIS_WARNING
,"Exiting on error writing to the append-only file: %s",strerror(errno
));
5550 redisLog(REDIS_WARNING
,"Exiting on short write while writing to the append-only file: %s",strerror(errno
));
5555 if (server
.appendfsync
== APPENDFSYNC_ALWAYS
||
5556 (server
.appendfsync
== APPENDFSYNC_EVERYSEC
&&
5557 now
-server
.lastfsync
> 1))
5559 fsync(server
.appendfd
); /* Let's try to get this data on the disk */
5560 server
.lastfsync
= now
;
5564 /* In Redis commands are always executed in the context of a client, so in
5565 * order to load the append only file we need to create a fake client. */
5566 static struct redisClient
*createFakeClient(void) {
5567 struct redisClient
*c
= zmalloc(sizeof(*c
));
5571 c
->querybuf
= sdsempty();
5575 /* We set the fake client as a slave waiting for the synchronization
5576 * so that Redis will not try to send replies to this client. */
5577 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
5578 c
->reply
= listCreate();
5579 listSetFreeMethod(c
->reply
,decrRefCount
);
5580 listSetDupMethod(c
->reply
,dupClientReplyValue
);
5584 static void freeFakeClient(struct redisClient
*c
) {
5585 sdsfree(c
->querybuf
);
5586 listRelease(c
->reply
);
5590 /* Replay the append log file. On error REDIS_OK is returned. On non fatal
5591 * error (the append only file is zero-length) REDIS_ERR is returned. On
5592 * fatal error an error message is logged and the program exists. */
5593 int loadAppendOnlyFile(char *filename
) {
5594 struct redisClient
*fakeClient
;
5595 FILE *fp
= fopen(filename
,"r");
5596 struct redis_stat sb
;
5598 if (redis_fstat(fileno(fp
),&sb
) != -1 && sb
.st_size
== 0)
5602 redisLog(REDIS_WARNING
,"Fatal error: can't open the append log file for reading: %s",strerror(errno
));
5606 fakeClient
= createFakeClient();
5613 struct redisCommand
*cmd
;
5615 if (fgets(buf
,sizeof(buf
),fp
) == NULL
) {
5621 if (buf
[0] != '*') goto fmterr
;
5623 argv
= zmalloc(sizeof(robj
*)*argc
);
5624 for (j
= 0; j
< argc
; j
++) {
5625 if (fgets(buf
,sizeof(buf
),fp
) == NULL
) goto readerr
;
5626 if (buf
[0] != '$') goto fmterr
;
5627 len
= strtol(buf
+1,NULL
,10);
5628 argsds
= sdsnewlen(NULL
,len
);
5629 if (fread(argsds
,len
,1,fp
) == 0) goto fmterr
;
5630 argv
[j
] = createObject(REDIS_STRING
,argsds
);
5631 if (fread(buf
,2,1,fp
) == 0) goto fmterr
; /* discard CRLF */
5634 /* Command lookup */
5635 cmd
= lookupCommand(argv
[0]->ptr
);
5637 redisLog(REDIS_WARNING
,"Unknown command '%s' reading the append only file", argv
[0]->ptr
);
5640 /* Try object sharing and encoding */
5641 if (server
.shareobjects
) {
5643 for(j
= 1; j
< argc
; j
++)
5644 argv
[j
] = tryObjectSharing(argv
[j
]);
5646 if (cmd
->flags
& REDIS_CMD_BULK
)
5647 tryObjectEncoding(argv
[argc
-1]);
5648 /* Run the command in the context of a fake client */
5649 fakeClient
->argc
= argc
;
5650 fakeClient
->argv
= argv
;
5651 cmd
->proc(fakeClient
);
5652 /* Discard the reply objects list from the fake client */
5653 while(listLength(fakeClient
->reply
))
5654 listDelNode(fakeClient
->reply
,listFirst(fakeClient
->reply
));
5655 /* Clean up, ready for the next command */
5656 for (j
= 0; j
< argc
; j
++) decrRefCount(argv
[j
]);
5660 freeFakeClient(fakeClient
);
5665 redisLog(REDIS_WARNING
,"Unexpected end of file reading the append only file");
5667 redisLog(REDIS_WARNING
,"Unrecoverable error reading the append only file: %s", strerror(errno
));
5671 redisLog(REDIS_WARNING
,"Bad file format reading the append only file");
5675 /* ================================= Debugging ============================== */
5677 static void debugCommand(redisClient
*c
) {
5678 if (!strcasecmp(c
->argv
[1]->ptr
,"segfault")) {
5680 } else if (!strcasecmp(c
->argv
[1]->ptr
,"object") && c
->argc
== 3) {
5681 dictEntry
*de
= dictFind(c
->db
->dict
,c
->argv
[2]);
5685 addReply(c
,shared
.nokeyerr
);
5688 key
= dictGetEntryKey(de
);
5689 val
= dictGetEntryVal(de
);
5690 addReplySds(c
,sdscatprintf(sdsempty(),
5691 "+Key at:%p refcount:%d, value at:%p refcount:%d encoding:%d\r\n",
5692 key
, key
->refcount
, val
, val
->refcount
, val
->encoding
));
5694 addReplySds(c
,sdsnew(
5695 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>]\r\n"));
5699 /* =================================== Main! ================================ */
5702 int linuxOvercommitMemoryValue(void) {
5703 FILE *fp
= fopen("/proc/sys/vm/overcommit_memory","r");
5707 if (fgets(buf
,64,fp
) == NULL
) {
5716 void linuxOvercommitMemoryWarning(void) {
5717 if (linuxOvercommitMemoryValue() == 0) {
5718 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.");
5721 #endif /* __linux__ */
5723 static void daemonize(void) {
5727 if (fork() != 0) exit(0); /* parent exits */
5728 setsid(); /* create a new session */
5730 /* Every output goes to /dev/null. If Redis is daemonized but
5731 * the 'logfile' is set to 'stdout' in the configuration file
5732 * it will not log at all. */
5733 if ((fd
= open("/dev/null", O_RDWR
, 0)) != -1) {
5734 dup2(fd
, STDIN_FILENO
);
5735 dup2(fd
, STDOUT_FILENO
);
5736 dup2(fd
, STDERR_FILENO
);
5737 if (fd
> STDERR_FILENO
) close(fd
);
5739 /* Try to write the pid file */
5740 fp
= fopen(server
.pidfile
,"w");
5742 fprintf(fp
,"%d\n",getpid());
5747 int main(int argc
, char **argv
) {
5750 resetServerSaveParams();
5751 loadServerConfig(argv
[1]);
5752 } else if (argc
> 2) {
5753 fprintf(stderr
,"Usage: ./redis-server [/path/to/redis.conf]\n");
5756 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'");
5759 if (server
.daemonize
) daemonize();
5760 redisLog(REDIS_NOTICE
,"Server started, Redis version " REDIS_VERSION
);
5762 linuxOvercommitMemoryWarning();
5764 if (server
.appendonly
) {
5765 if (loadAppendOnlyFile(server
.appendfilename
) == REDIS_OK
)
5766 redisLog(REDIS_NOTICE
,"DB loaded from append only file");
5768 if (rdbLoad(server
.dbfilename
) == REDIS_OK
)
5769 redisLog(REDIS_NOTICE
,"DB loaded from disk");
5771 if (aeCreateFileEvent(server
.el
, server
.fd
, AE_READABLE
,
5772 acceptHandler
, NULL
, NULL
) == AE_ERR
) oom("creating file event");
5773 redisLog(REDIS_NOTICE
,"The server is now ready to accept connections on port %d", server
.port
);
5775 aeDeleteEventLoop(server
.el
);
5779 /* ============================= Backtrace support ========================= */
5781 #ifdef HAVE_BACKTRACE
5782 static char *findFuncName(void *pointer
, unsigned long *offset
);
5784 static void *getMcontextEip(ucontext_t
*uc
) {
5785 #if defined(__FreeBSD__)
5786 return (void*) uc
->uc_mcontext
.mc_eip
;
5787 #elif defined(__dietlibc__)
5788 return (void*) uc
->uc_mcontext
.eip
;
5789 #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
5790 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
5791 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
5792 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
5793 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
5795 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
5797 #elif defined(__i386__) || defined(__X86_64__) /* Linux x86 */
5798 return (void*) uc
->uc_mcontext
.gregs
[REG_EIP
];
5799 #elif defined(__ia64__) /* Linux IA64 */
5800 return (void*) uc
->uc_mcontext
.sc_ip
;
5806 static void segvHandler(int sig
, siginfo_t
*info
, void *secret
) {
5808 char **messages
= NULL
;
5809 int i
, trace_size
= 0;
5810 unsigned long offset
=0;
5811 time_t uptime
= time(NULL
)-server
.stat_starttime
;
5812 ucontext_t
*uc
= (ucontext_t
*) secret
;
5813 REDIS_NOTUSED(info
);
5815 redisLog(REDIS_WARNING
,
5816 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION
, sig
);
5817 redisLog(REDIS_WARNING
, "%s", sdscatprintf(sdsempty(),
5818 "redis_version:%s; "
5819 "uptime_in_seconds:%d; "
5820 "connected_clients:%d; "
5821 "connected_slaves:%d; "
5823 "changes_since_last_save:%lld; "
5824 "bgsave_in_progress:%d; "
5825 "last_save_time:%d; "
5826 "total_connections_received:%lld; "
5827 "total_commands_processed:%lld; "
5831 listLength(server
.clients
)-listLength(server
.slaves
),
5832 listLength(server
.slaves
),
5835 server
.bgsaveinprogress
,
5837 server
.stat_numconnections
,
5838 server
.stat_numcommands
,
5839 server
.masterhost
== NULL
? "master" : "slave"
5842 trace_size
= backtrace(trace
, 100);
5843 /* overwrite sigaction with caller's address */
5844 if (getMcontextEip(uc
) != NULL
) {
5845 trace
[1] = getMcontextEip(uc
);
5847 messages
= backtrace_symbols(trace
, trace_size
);
5849 for (i
=1; i
<trace_size
; ++i
) {
5850 char *fn
= findFuncName(trace
[i
], &offset
), *p
;
5852 p
= strchr(messages
[i
],'+');
5853 if (!fn
|| (p
&& ((unsigned long)strtol(p
+1,NULL
,10)) < offset
)) {
5854 redisLog(REDIS_WARNING
,"%s", messages
[i
]);
5856 redisLog(REDIS_WARNING
,"%d redis-server %p %s + %d", i
, trace
[i
], fn
, (unsigned int)offset
);
5863 static void setupSigSegvAction(void) {
5864 struct sigaction act
;
5866 sigemptyset (&act
.sa_mask
);
5867 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
5868 * is used. Otherwise, sa_handler is used */
5869 act
.sa_flags
= SA_NODEFER
| SA_ONSTACK
| SA_RESETHAND
| SA_SIGINFO
;
5870 act
.sa_sigaction
= segvHandler
;
5871 sigaction (SIGSEGV
, &act
, NULL
);
5872 sigaction (SIGBUS
, &act
, NULL
);
5873 sigaction (SIGFPE
, &act
, NULL
);
5874 sigaction (SIGILL
, &act
, NULL
);
5875 sigaction (SIGBUS
, &act
, NULL
);
5879 #include "staticsymbols.h"
5880 /* This function try to convert a pointer into a function name. It's used in
5881 * oreder to provide a backtrace under segmentation fault that's able to
5882 * display functions declared as static (otherwise the backtrace is useless). */
5883 static char *findFuncName(void *pointer
, unsigned long *offset
){
5885 unsigned long off
, minoff
= 0;
5887 /* Try to match against the Symbol with the smallest offset */
5888 for (i
=0; symsTable
[i
].pointer
; i
++) {
5889 unsigned long lp
= (unsigned long) pointer
;
5891 if (lp
!= (unsigned long)-1 && lp
>= symsTable
[i
].pointer
) {
5892 off
=lp
-symsTable
[i
].pointer
;
5893 if (ret
< 0 || off
< minoff
) {
5899 if (ret
== -1) return NULL
;
5901 return symsTable
[ret
].name
;
5903 #else /* HAVE_BACKTRACE */
5904 static void setupSigSegvAction(void) {
5906 #endif /* HAVE_BACKTRACE */