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>
61 #if defined(__sun) && defined(__GNUC__)
62 #include "solarisfixes.h"
66 #include "ae.h" /* Event driven programming library */
67 #include "sds.h" /* Dynamic safe strings */
68 #include "anet.h" /* Networking the easy way */
69 #include "dict.h" /* Hash tables */
70 #include "adlist.h" /* Linked lists */
71 #include "zmalloc.h" /* total memory usage aware version of malloc/free */
72 #include "lzf.h" /* LZF compression library */
73 #include "pqsort.h" /* Partial qsort for SORT+LIMIT */
79 /* Static server configuration */
80 #define REDIS_SERVERPORT 6379 /* TCP port */
81 #define REDIS_MAXIDLETIME (60*5) /* default client timeout */
82 #define REDIS_IOBUF_LEN 1024
83 #define REDIS_LOADBUF_LEN 1024
84 #define REDIS_STATIC_ARGS 4
85 #define REDIS_DEFAULT_DBNUM 16
86 #define REDIS_CONFIGLINE_MAX 1024
87 #define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
88 #define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
89 #define REDIS_EXPIRELOOKUPS_PER_CRON 100 /* try to expire 100 keys/second */
90 #define REDIS_MAX_WRITE_PER_EVENT (1024*64)
91 #define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
93 /* Hash table parameters */
94 #define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
97 #define REDIS_CMD_BULK 1 /* Bulk write command */
98 #define REDIS_CMD_INLINE 2 /* Inline command */
99 /* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
100 this flags will return an error when the 'maxmemory' option is set in the
101 config file and the server is using more than maxmemory bytes of memory.
102 In short this commands are denied on low memory conditions. */
103 #define REDIS_CMD_DENYOOM 4
106 #define REDIS_STRING 0
112 /* Objects encoding */
113 #define REDIS_ENCODING_RAW 0 /* Raw representation */
114 #define REDIS_ENCODING_INT 1 /* Encoded as integer */
116 /* Object types only used for dumping to disk */
117 #define REDIS_EXPIRETIME 253
118 #define REDIS_SELECTDB 254
119 #define REDIS_EOF 255
121 /* Defines related to the dump file format. To store 32 bits lengths for short
122 * keys requires a lot of space, so we check the most significant 2 bits of
123 * the first byte to interpreter the length:
125 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
126 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
127 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
128 * 11|000000 this means: specially encoded object will follow. The six bits
129 * number specify the kind of object that follows.
130 * See the REDIS_RDB_ENC_* defines.
132 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
133 * values, will fit inside. */
134 #define REDIS_RDB_6BITLEN 0
135 #define REDIS_RDB_14BITLEN 1
136 #define REDIS_RDB_32BITLEN 2
137 #define REDIS_RDB_ENCVAL 3
138 #define REDIS_RDB_LENERR UINT_MAX
140 /* When a length of a string object stored on disk has the first two bits
141 * set, the remaining two bits specify a special encoding for the object
142 * accordingly to the following defines: */
143 #define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
144 #define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
145 #define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
146 #define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
149 #define REDIS_CLOSE 1 /* This client connection should be closed ASAP */
150 #define REDIS_SLAVE 2 /* This client is a slave server */
151 #define REDIS_MASTER 4 /* This client is a master server */
152 #define REDIS_MONITOR 8 /* This client is a slave monitor, see MONITOR */
154 /* Slave replication state - slave side */
155 #define REDIS_REPL_NONE 0 /* No active replication */
156 #define REDIS_REPL_CONNECT 1 /* Must connect to master */
157 #define REDIS_REPL_CONNECTED 2 /* Connected to master */
159 /* Slave replication state - from the point of view of master
160 * Note that in SEND_BULK and ONLINE state the slave receives new updates
161 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
162 * to start the next background saving in order to send updates to it. */
163 #define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
164 #define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
165 #define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
166 #define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
168 /* List related stuff */
172 /* Sort operations */
173 #define REDIS_SORT_GET 0
174 #define REDIS_SORT_DEL 1
175 #define REDIS_SORT_INCR 2
176 #define REDIS_SORT_DECR 3
177 #define REDIS_SORT_ASC 4
178 #define REDIS_SORT_DESC 5
179 #define REDIS_SORTKEY_MAX 1024
182 #define REDIS_DEBUG 0
183 #define REDIS_NOTICE 1
184 #define REDIS_WARNING 2
186 /* Anti-warning macro... */
187 #define REDIS_NOTUSED(V) ((void) V)
189 #define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
190 #define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
192 /*================================= Data types ============================== */
194 /* A redis object, that is a type able to hold a string / list / set */
195 typedef struct redisObject
{
198 unsigned char encoding
;
199 unsigned char notused
[2];
203 typedef struct redisDb
{
209 /* With multiplexing we need to take per-clinet state.
210 * Clients are taken in a liked list. */
211 typedef struct redisClient
{
216 robj
**argv
, **mbargv
;
218 int bulklen
; /* bulk read len. -1 if not in bulk read mode */
219 int multibulk
; /* multi bulk command format active */
222 time_t lastinteraction
; /* time of the last interaction, used for timeout */
223 int flags
; /* REDIS_CLOSE | REDIS_SLAVE | REDIS_MONITOR */
224 int slaveseldb
; /* slave selected db, if this client is a slave */
225 int authenticated
; /* when requirepass is non-NULL */
226 int replstate
; /* replication state if this is a slave */
227 int repldbfd
; /* replication DB file descriptor */
228 long repldboff
; /* replication DB file offset */
229 off_t repldbsize
; /* replication DB file size */
237 /* Global server state structure */
243 unsigned int sharingpoolsize
;
244 long long dirty
; /* changes to DB from the last save */
246 list
*slaves
, *monitors
;
247 char neterr
[ANET_ERR_LEN
];
249 int cronloops
; /* number of times the cron function run */
250 list
*objfreelist
; /* A list of freed objects to avoid malloc() */
251 time_t lastsave
; /* Unix time of last save succeeede */
252 size_t usedmemory
; /* Used memory in megabytes */
253 /* Fields used only for stats */
254 time_t stat_starttime
; /* server start time */
255 long long stat_numcommands
; /* number of processed commands */
256 long long stat_numconnections
; /* number of connections received */
264 int bgsaveinprogress
;
265 pid_t bgsavechildpid
;
266 struct saveparam
*saveparams
;
273 /* Replication related */
277 redisClient
*master
; /* client that is master for this slave */
279 unsigned int maxclients
;
280 unsigned long maxmemory
;
281 /* Sort parameters - qsort_r() is only available under BSD so we
282 * have to take this state global, in order to pass it to sortCompare() */
288 typedef void redisCommandProc(redisClient
*c
);
289 struct redisCommand
{
291 redisCommandProc
*proc
;
296 struct redisFunctionSym
{
298 unsigned long pointer
;
301 typedef struct _redisSortObject
{
309 typedef struct _redisSortOperation
{
312 } redisSortOperation
;
314 /* ZSETs use a specialized version of Skiplists */
316 typedef struct zskiplistNode
{
317 struct zskiplistNode
**forward
;
318 struct zskiplistNode
*backward
;
323 typedef struct zskiplist
{
324 struct zskiplistNode
*header
, *tail
;
329 typedef struct zset
{
334 /* Our shared "common" objects */
336 struct sharedObjectsStruct
{
337 robj
*crlf
, *ok
, *err
, *emptybulk
, *czero
, *cone
, *pong
, *space
,
338 *colon
, *nullbulk
, *nullmultibulk
,
339 *emptymultibulk
, *wrongtypeerr
, *nokeyerr
, *syntaxerr
, *sameobjecterr
,
340 *outofrangeerr
, *plus
,
341 *select0
, *select1
, *select2
, *select3
, *select4
,
342 *select5
, *select6
, *select7
, *select8
, *select9
;
345 /* Global vars that are actally used as constants. The following double
346 * values are used for double on-disk serialization, and are initialized
347 * at runtime to avoid strange compiler optimizations. */
349 static double R_Zero
, R_PosInf
, R_NegInf
, R_Nan
;
351 /*================================ Prototypes =============================== */
353 static void freeStringObject(robj
*o
);
354 static void freeListObject(robj
*o
);
355 static void freeSetObject(robj
*o
);
356 static void decrRefCount(void *o
);
357 static robj
*createObject(int type
, void *ptr
);
358 static void freeClient(redisClient
*c
);
359 static int rdbLoad(char *filename
);
360 static void addReply(redisClient
*c
, robj
*obj
);
361 static void addReplySds(redisClient
*c
, sds s
);
362 static void incrRefCount(robj
*o
);
363 static int rdbSaveBackground(char *filename
);
364 static robj
*createStringObject(char *ptr
, size_t len
);
365 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
);
366 static int syncWithMaster(void);
367 static robj
*tryObjectSharing(robj
*o
);
368 static int tryObjectEncoding(robj
*o
);
369 static robj
*getDecodedObject(const robj
*o
);
370 static int removeExpire(redisDb
*db
, robj
*key
);
371 static int expireIfNeeded(redisDb
*db
, robj
*key
);
372 static int deleteIfVolatile(redisDb
*db
, robj
*key
);
373 static int deleteKey(redisDb
*db
, robj
*key
);
374 static time_t getExpire(redisDb
*db
, robj
*key
);
375 static int setExpire(redisDb
*db
, robj
*key
, time_t when
);
376 static void updateSlavesWaitingBgsave(int bgsaveerr
);
377 static void freeMemoryIfNeeded(void);
378 static int processCommand(redisClient
*c
);
379 static void setupSigSegvAction(void);
380 static void rdbRemoveTempFile(pid_t childpid
);
381 static size_t stringObjectLen(robj
*o
);
382 static void processInputBuffer(redisClient
*c
);
383 static zskiplist
*zslCreate(void);
384 static void zslFree(zskiplist
*zsl
);
385 static void zslInsert(zskiplist
*zsl
, double score
, robj
*obj
);
387 static void authCommand(redisClient
*c
);
388 static void pingCommand(redisClient
*c
);
389 static void echoCommand(redisClient
*c
);
390 static void setCommand(redisClient
*c
);
391 static void setnxCommand(redisClient
*c
);
392 static void getCommand(redisClient
*c
);
393 static void delCommand(redisClient
*c
);
394 static void existsCommand(redisClient
*c
);
395 static void incrCommand(redisClient
*c
);
396 static void decrCommand(redisClient
*c
);
397 static void incrbyCommand(redisClient
*c
);
398 static void decrbyCommand(redisClient
*c
);
399 static void selectCommand(redisClient
*c
);
400 static void randomkeyCommand(redisClient
*c
);
401 static void keysCommand(redisClient
*c
);
402 static void dbsizeCommand(redisClient
*c
);
403 static void lastsaveCommand(redisClient
*c
);
404 static void saveCommand(redisClient
*c
);
405 static void bgsaveCommand(redisClient
*c
);
406 static void shutdownCommand(redisClient
*c
);
407 static void moveCommand(redisClient
*c
);
408 static void renameCommand(redisClient
*c
);
409 static void renamenxCommand(redisClient
*c
);
410 static void lpushCommand(redisClient
*c
);
411 static void rpushCommand(redisClient
*c
);
412 static void lpopCommand(redisClient
*c
);
413 static void rpopCommand(redisClient
*c
);
414 static void llenCommand(redisClient
*c
);
415 static void lindexCommand(redisClient
*c
);
416 static void lrangeCommand(redisClient
*c
);
417 static void ltrimCommand(redisClient
*c
);
418 static void typeCommand(redisClient
*c
);
419 static void lsetCommand(redisClient
*c
);
420 static void saddCommand(redisClient
*c
);
421 static void sremCommand(redisClient
*c
);
422 static void smoveCommand(redisClient
*c
);
423 static void sismemberCommand(redisClient
*c
);
424 static void scardCommand(redisClient
*c
);
425 static void spopCommand(redisClient
*c
);
426 static void srandmemberCommand(redisClient
*c
);
427 static void sinterCommand(redisClient
*c
);
428 static void sinterstoreCommand(redisClient
*c
);
429 static void sunionCommand(redisClient
*c
);
430 static void sunionstoreCommand(redisClient
*c
);
431 static void sdiffCommand(redisClient
*c
);
432 static void sdiffstoreCommand(redisClient
*c
);
433 static void syncCommand(redisClient
*c
);
434 static void flushdbCommand(redisClient
*c
);
435 static void flushallCommand(redisClient
*c
);
436 static void sortCommand(redisClient
*c
);
437 static void lremCommand(redisClient
*c
);
438 static void infoCommand(redisClient
*c
);
439 static void mgetCommand(redisClient
*c
);
440 static void monitorCommand(redisClient
*c
);
441 static void expireCommand(redisClient
*c
);
442 static void getsetCommand(redisClient
*c
);
443 static void ttlCommand(redisClient
*c
);
444 static void slaveofCommand(redisClient
*c
);
445 static void debugCommand(redisClient
*c
);
446 static void msetCommand(redisClient
*c
);
447 static void msetnxCommand(redisClient
*c
);
448 static void zaddCommand(redisClient
*c
);
449 static void zrangeCommand(redisClient
*c
);
450 static void zrangebyscoreCommand(redisClient
*c
);
451 static void zrevrangeCommand(redisClient
*c
);
452 static void zlenCommand(redisClient
*c
);
453 static void zremCommand(redisClient
*c
);
454 static void zscoreCommand(redisClient
*c
);
456 /*================================= Globals ================================= */
459 static struct redisServer server
; /* server global state */
460 static struct redisCommand cmdTable
[] = {
461 {"get",getCommand
,2,REDIS_CMD_INLINE
},
462 {"set",setCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
463 {"setnx",setnxCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
464 {"del",delCommand
,-2,REDIS_CMD_INLINE
},
465 {"exists",existsCommand
,2,REDIS_CMD_INLINE
},
466 {"incr",incrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
467 {"decr",decrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
468 {"mget",mgetCommand
,-2,REDIS_CMD_INLINE
},
469 {"rpush",rpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
470 {"lpush",lpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
471 {"rpop",rpopCommand
,2,REDIS_CMD_INLINE
},
472 {"lpop",lpopCommand
,2,REDIS_CMD_INLINE
},
473 {"llen",llenCommand
,2,REDIS_CMD_INLINE
},
474 {"lindex",lindexCommand
,3,REDIS_CMD_INLINE
},
475 {"lset",lsetCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
476 {"lrange",lrangeCommand
,4,REDIS_CMD_INLINE
},
477 {"ltrim",ltrimCommand
,4,REDIS_CMD_INLINE
},
478 {"lrem",lremCommand
,4,REDIS_CMD_BULK
},
479 {"sadd",saddCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
480 {"srem",sremCommand
,3,REDIS_CMD_BULK
},
481 {"smove",smoveCommand
,4,REDIS_CMD_BULK
},
482 {"sismember",sismemberCommand
,3,REDIS_CMD_BULK
},
483 {"scard",scardCommand
,2,REDIS_CMD_INLINE
},
484 {"spop",spopCommand
,2,REDIS_CMD_INLINE
},
485 {"srandmember",srandmemberCommand
,2,REDIS_CMD_INLINE
},
486 {"sinter",sinterCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
487 {"sinterstore",sinterstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
488 {"sunion",sunionCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
489 {"sunionstore",sunionstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
490 {"sdiff",sdiffCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
491 {"sdiffstore",sdiffstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
492 {"smembers",sinterCommand
,2,REDIS_CMD_INLINE
},
493 {"zadd",zaddCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
494 {"zrem",zremCommand
,3,REDIS_CMD_BULK
},
495 {"zrange",zrangeCommand
,4,REDIS_CMD_INLINE
},
496 {"zrangebyscore",zrangebyscoreCommand
,4,REDIS_CMD_INLINE
},
497 {"zrevrange",zrevrangeCommand
,4,REDIS_CMD_INLINE
},
498 {"zlen",zlenCommand
,2,REDIS_CMD_INLINE
},
499 {"zscore",zscoreCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
500 {"incrby",incrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
501 {"decrby",decrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
502 {"getset",getsetCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
503 {"mset",msetCommand
,-3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
504 {"msetnx",msetnxCommand
,-3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
505 {"randomkey",randomkeyCommand
,1,REDIS_CMD_INLINE
},
506 {"select",selectCommand
,2,REDIS_CMD_INLINE
},
507 {"move",moveCommand
,3,REDIS_CMD_INLINE
},
508 {"rename",renameCommand
,3,REDIS_CMD_INLINE
},
509 {"renamenx",renamenxCommand
,3,REDIS_CMD_INLINE
},
510 {"expire",expireCommand
,3,REDIS_CMD_INLINE
},
511 {"keys",keysCommand
,2,REDIS_CMD_INLINE
},
512 {"dbsize",dbsizeCommand
,1,REDIS_CMD_INLINE
},
513 {"auth",authCommand
,2,REDIS_CMD_INLINE
},
514 {"ping",pingCommand
,1,REDIS_CMD_INLINE
},
515 {"echo",echoCommand
,2,REDIS_CMD_BULK
},
516 {"save",saveCommand
,1,REDIS_CMD_INLINE
},
517 {"bgsave",bgsaveCommand
,1,REDIS_CMD_INLINE
},
518 {"shutdown",shutdownCommand
,1,REDIS_CMD_INLINE
},
519 {"lastsave",lastsaveCommand
,1,REDIS_CMD_INLINE
},
520 {"type",typeCommand
,2,REDIS_CMD_INLINE
},
521 {"sync",syncCommand
,1,REDIS_CMD_INLINE
},
522 {"flushdb",flushdbCommand
,1,REDIS_CMD_INLINE
},
523 {"flushall",flushallCommand
,1,REDIS_CMD_INLINE
},
524 {"sort",sortCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
525 {"info",infoCommand
,1,REDIS_CMD_INLINE
},
526 {"monitor",monitorCommand
,1,REDIS_CMD_INLINE
},
527 {"ttl",ttlCommand
,2,REDIS_CMD_INLINE
},
528 {"slaveof",slaveofCommand
,3,REDIS_CMD_INLINE
},
529 {"debug",debugCommand
,-2,REDIS_CMD_INLINE
},
532 /*============================ Utility functions ============================ */
534 /* Glob-style pattern matching. */
535 int stringmatchlen(const char *pattern
, int patternLen
,
536 const char *string
, int stringLen
, int nocase
)
541 while (pattern
[1] == '*') {
546 return 1; /* match */
548 if (stringmatchlen(pattern
+1, patternLen
-1,
549 string
, stringLen
, nocase
))
550 return 1; /* match */
554 return 0; /* no match */
558 return 0; /* no match */
568 not = pattern
[0] == '^';
575 if (pattern
[0] == '\\') {
578 if (pattern
[0] == string
[0])
580 } else if (pattern
[0] == ']') {
582 } else if (patternLen
== 0) {
586 } else if (pattern
[1] == '-' && patternLen
>= 3) {
587 int start
= pattern
[0];
588 int end
= pattern
[2];
596 start
= tolower(start
);
602 if (c
>= start
&& c
<= end
)
606 if (pattern
[0] == string
[0])
609 if (tolower((int)pattern
[0]) == tolower((int)string
[0]))
619 return 0; /* no match */
625 if (patternLen
>= 2) {
632 if (pattern
[0] != string
[0])
633 return 0; /* no match */
635 if (tolower((int)pattern
[0]) != tolower((int)string
[0]))
636 return 0; /* no match */
644 if (stringLen
== 0) {
645 while(*pattern
== '*') {
652 if (patternLen
== 0 && stringLen
== 0)
657 static void redisLog(int level
, const char *fmt
, ...) {
661 fp
= (server
.logfile
== NULL
) ? stdout
: fopen(server
.logfile
,"a");
665 if (level
>= server
.verbosity
) {
671 strftime(buf
,64,"%d %b %H:%M:%S",gmtime(&now
));
672 fprintf(fp
,"%s %c ",buf
,c
[level
]);
673 vfprintf(fp
, fmt
, ap
);
679 if (server
.logfile
) fclose(fp
);
682 /*====================== Hash table type implementation ==================== */
684 /* This is an hash table type that uses the SDS dynamic strings libary as
685 * keys and radis objects as values (objects can hold SDS strings,
688 static void dictVanillaFree(void *privdata
, void *val
)
690 DICT_NOTUSED(privdata
);
694 static int sdsDictKeyCompare(void *privdata
, const void *key1
,
698 DICT_NOTUSED(privdata
);
700 l1
= sdslen((sds
)key1
);
701 l2
= sdslen((sds
)key2
);
702 if (l1
!= l2
) return 0;
703 return memcmp(key1
, key2
, l1
) == 0;
706 static void dictRedisObjectDestructor(void *privdata
, void *val
)
708 DICT_NOTUSED(privdata
);
713 static int dictObjKeyCompare(void *privdata
, const void *key1
,
716 const robj
*o1
= key1
, *o2
= key2
;
717 return sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
720 static unsigned int dictObjHash(const void *key
) {
722 return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
725 static int dictEncObjKeyCompare(void *privdata
, const void *key1
,
728 const robj
*o1
= key1
, *o2
= key2
;
730 if (o1
->encoding
== REDIS_ENCODING_RAW
&&
731 o2
->encoding
== REDIS_ENCODING_RAW
)
732 return sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
737 dec1
= o1
->encoding
!= REDIS_ENCODING_RAW
?
738 getDecodedObject(o1
) : (robj
*)o1
;
739 dec2
= o2
->encoding
!= REDIS_ENCODING_RAW
?
740 getDecodedObject(o2
) : (robj
*)o2
;
741 cmp
= sdsDictKeyCompare(privdata
,dec1
->ptr
,dec2
->ptr
);
742 if (dec1
!= o1
) decrRefCount(dec1
);
743 if (dec2
!= o2
) decrRefCount(dec2
);
748 static unsigned int dictEncObjHash(const void *key
) {
751 if (o
->encoding
== REDIS_ENCODING_RAW
)
752 return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
754 robj
*dec
= getDecodedObject(o
);
755 unsigned int hash
= dictGenHashFunction(dec
->ptr
, sdslen((sds
)dec
->ptr
));
761 static dictType setDictType
= {
762 dictEncObjHash
, /* hash function */
765 dictEncObjKeyCompare
, /* key compare */
766 dictRedisObjectDestructor
, /* key destructor */
767 NULL
/* val destructor */
770 static dictType zsetDictType
= {
771 dictEncObjHash
, /* hash function */
774 dictEncObjKeyCompare
, /* key compare */
775 dictRedisObjectDestructor
, /* key destructor */
776 dictVanillaFree
/* val destructor */
779 static dictType hashDictType
= {
780 dictObjHash
, /* hash function */
783 dictObjKeyCompare
, /* key compare */
784 dictRedisObjectDestructor
, /* key destructor */
785 dictRedisObjectDestructor
/* val destructor */
788 /* ========================= Random utility functions ======================= */
790 /* Redis generally does not try to recover from out of memory conditions
791 * when allocating objects or strings, it is not clear if it will be possible
792 * to report this condition to the client since the networking layer itself
793 * is based on heap allocation for send buffers, so we simply abort.
794 * At least the code will be simpler to read... */
795 static void oom(const char *msg
) {
796 fprintf(stderr
, "%s: Out of memory\n",msg
);
802 /* ====================== Redis server networking stuff ===================== */
803 static void closeTimedoutClients(void) {
806 time_t now
= time(NULL
);
808 listRewind(server
.clients
);
809 while ((ln
= listYield(server
.clients
)) != NULL
) {
810 c
= listNodeValue(ln
);
811 if (!(c
->flags
& REDIS_SLAVE
) && /* no timeout for slaves */
812 !(c
->flags
& REDIS_MASTER
) && /* no timeout for masters */
813 (now
- c
->lastinteraction
> server
.maxidletime
)) {
814 redisLog(REDIS_DEBUG
,"Closing idle client");
820 static int htNeedsResize(dict
*dict
) {
821 long long size
, used
;
823 size
= dictSlots(dict
);
824 used
= dictSize(dict
);
825 return (size
&& used
&& size
> DICT_HT_INITIAL_SIZE
&&
826 (used
*100/size
< REDIS_HT_MINFILL
));
829 /* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
830 * we resize the hash table to save memory */
831 static void tryResizeHashTables(void) {
834 for (j
= 0; j
< server
.dbnum
; j
++) {
835 if (htNeedsResize(server
.db
[j
].dict
)) {
836 redisLog(REDIS_DEBUG
,"The hash table %d is too sparse, resize it...",j
);
837 dictResize(server
.db
[j
].dict
);
838 redisLog(REDIS_DEBUG
,"Hash table %d resized.",j
);
840 if (htNeedsResize(server
.db
[j
].expires
))
841 dictResize(server
.db
[j
].expires
);
845 static int serverCron(struct aeEventLoop
*eventLoop
, long long id
, void *clientData
) {
846 int j
, loops
= server
.cronloops
++;
847 REDIS_NOTUSED(eventLoop
);
849 REDIS_NOTUSED(clientData
);
851 /* Update the global state with the amount of used memory */
852 server
.usedmemory
= zmalloc_used_memory();
854 /* Show some info about non-empty databases */
855 for (j
= 0; j
< server
.dbnum
; j
++) {
856 long long size
, used
, vkeys
;
858 size
= dictSlots(server
.db
[j
].dict
);
859 used
= dictSize(server
.db
[j
].dict
);
860 vkeys
= dictSize(server
.db
[j
].expires
);
861 if (!(loops
% 5) && (used
|| vkeys
)) {
862 redisLog(REDIS_DEBUG
,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j
,used
,vkeys
,size
);
863 /* dictPrintStats(server.dict); */
867 /* We don't want to resize the hash tables while a bacground saving
868 * is in progress: the saving child is created using fork() that is
869 * implemented with a copy-on-write semantic in most modern systems, so
870 * if we resize the HT while there is the saving child at work actually
871 * a lot of memory movements in the parent will cause a lot of pages
873 if (!server
.bgsaveinprogress
) tryResizeHashTables();
875 /* Show information about connected clients */
877 redisLog(REDIS_DEBUG
,"%d clients connected (%d slaves), %zu bytes in use, %d shared objects",
878 listLength(server
.clients
)-listLength(server
.slaves
),
879 listLength(server
.slaves
),
881 dictSize(server
.sharingpool
));
884 /* Close connections of timedout clients */
885 if (server
.maxidletime
&& !(loops
% 10))
886 closeTimedoutClients();
888 /* Check if a background saving in progress terminated */
889 if (server
.bgsaveinprogress
) {
891 if (wait4(-1,&statloc
,WNOHANG
,NULL
)) {
892 int exitcode
= WEXITSTATUS(statloc
);
893 int bysignal
= WIFSIGNALED(statloc
);
895 if (!bysignal
&& exitcode
== 0) {
896 redisLog(REDIS_NOTICE
,
897 "Background saving terminated with success");
899 server
.lastsave
= time(NULL
);
900 } else if (!bysignal
&& exitcode
!= 0) {
901 redisLog(REDIS_WARNING
, "Background saving error");
903 redisLog(REDIS_WARNING
,
904 "Background saving terminated by signal");
905 rdbRemoveTempFile(server
.bgsavechildpid
);
907 server
.bgsaveinprogress
= 0;
908 server
.bgsavechildpid
= -1;
909 updateSlavesWaitingBgsave(exitcode
== 0 ? REDIS_OK
: REDIS_ERR
);
912 /* If there is not a background saving in progress check if
913 * we have to save now */
914 time_t now
= time(NULL
);
915 for (j
= 0; j
< server
.saveparamslen
; j
++) {
916 struct saveparam
*sp
= server
.saveparams
+j
;
918 if (server
.dirty
>= sp
->changes
&&
919 now
-server
.lastsave
> sp
->seconds
) {
920 redisLog(REDIS_NOTICE
,"%d changes in %d seconds. Saving...",
921 sp
->changes
, sp
->seconds
);
922 rdbSaveBackground(server
.dbfilename
);
928 /* Try to expire a few timed out keys */
929 for (j
= 0; j
< server
.dbnum
; j
++) {
930 redisDb
*db
= server
.db
+j
;
931 int num
= dictSize(db
->expires
);
934 time_t now
= time(NULL
);
936 if (num
> REDIS_EXPIRELOOKUPS_PER_CRON
)
937 num
= REDIS_EXPIRELOOKUPS_PER_CRON
;
942 if ((de
= dictGetRandomKey(db
->expires
)) == NULL
) break;
943 t
= (time_t) dictGetEntryVal(de
);
945 deleteKey(db
,dictGetEntryKey(de
));
951 /* Check if we should connect to a MASTER */
952 if (server
.replstate
== REDIS_REPL_CONNECT
) {
953 redisLog(REDIS_NOTICE
,"Connecting to MASTER...");
954 if (syncWithMaster() == REDIS_OK
) {
955 redisLog(REDIS_NOTICE
,"MASTER <-> SLAVE sync succeeded");
961 static void createSharedObjects(void) {
962 shared
.crlf
= createObject(REDIS_STRING
,sdsnew("\r\n"));
963 shared
.ok
= createObject(REDIS_STRING
,sdsnew("+OK\r\n"));
964 shared
.err
= createObject(REDIS_STRING
,sdsnew("-ERR\r\n"));
965 shared
.emptybulk
= createObject(REDIS_STRING
,sdsnew("$0\r\n\r\n"));
966 shared
.czero
= createObject(REDIS_STRING
,sdsnew(":0\r\n"));
967 shared
.cone
= createObject(REDIS_STRING
,sdsnew(":1\r\n"));
968 shared
.nullbulk
= createObject(REDIS_STRING
,sdsnew("$-1\r\n"));
969 shared
.nullmultibulk
= createObject(REDIS_STRING
,sdsnew("*-1\r\n"));
970 shared
.emptymultibulk
= createObject(REDIS_STRING
,sdsnew("*0\r\n"));
972 shared
.pong
= createObject(REDIS_STRING
,sdsnew("+PONG\r\n"));
973 shared
.wrongtypeerr
= createObject(REDIS_STRING
,sdsnew(
974 "-ERR Operation against a key holding the wrong kind of value\r\n"));
975 shared
.nokeyerr
= createObject(REDIS_STRING
,sdsnew(
976 "-ERR no such key\r\n"));
977 shared
.syntaxerr
= createObject(REDIS_STRING
,sdsnew(
978 "-ERR syntax error\r\n"));
979 shared
.sameobjecterr
= createObject(REDIS_STRING
,sdsnew(
980 "-ERR source and destination objects are the same\r\n"));
981 shared
.outofrangeerr
= createObject(REDIS_STRING
,sdsnew(
982 "-ERR index out of range\r\n"));
983 shared
.space
= createObject(REDIS_STRING
,sdsnew(" "));
984 shared
.colon
= createObject(REDIS_STRING
,sdsnew(":"));
985 shared
.plus
= createObject(REDIS_STRING
,sdsnew("+"));
986 shared
.select0
= createStringObject("select 0\r\n",10);
987 shared
.select1
= createStringObject("select 1\r\n",10);
988 shared
.select2
= createStringObject("select 2\r\n",10);
989 shared
.select3
= createStringObject("select 3\r\n",10);
990 shared
.select4
= createStringObject("select 4\r\n",10);
991 shared
.select5
= createStringObject("select 5\r\n",10);
992 shared
.select6
= createStringObject("select 6\r\n",10);
993 shared
.select7
= createStringObject("select 7\r\n",10);
994 shared
.select8
= createStringObject("select 8\r\n",10);
995 shared
.select9
= createStringObject("select 9\r\n",10);
998 static void appendServerSaveParams(time_t seconds
, int changes
) {
999 server
.saveparams
= zrealloc(server
.saveparams
,sizeof(struct saveparam
)*(server
.saveparamslen
+1));
1000 server
.saveparams
[server
.saveparamslen
].seconds
= seconds
;
1001 server
.saveparams
[server
.saveparamslen
].changes
= changes
;
1002 server
.saveparamslen
++;
1005 static void ResetServerSaveParams() {
1006 zfree(server
.saveparams
);
1007 server
.saveparams
= NULL
;
1008 server
.saveparamslen
= 0;
1011 static void initServerConfig() {
1012 server
.dbnum
= REDIS_DEFAULT_DBNUM
;
1013 server
.port
= REDIS_SERVERPORT
;
1014 server
.verbosity
= REDIS_DEBUG
;
1015 server
.maxidletime
= REDIS_MAXIDLETIME
;
1016 server
.saveparams
= NULL
;
1017 server
.logfile
= NULL
; /* NULL = log on standard output */
1018 server
.bindaddr
= NULL
;
1019 server
.glueoutputbuf
= 1;
1020 server
.daemonize
= 0;
1021 server
.pidfile
= "/var/run/redis.pid";
1022 server
.dbfilename
= "dump.rdb";
1023 server
.requirepass
= NULL
;
1024 server
.shareobjects
= 0;
1025 server
.sharingpoolsize
= 1024;
1026 server
.maxclients
= 0;
1027 server
.maxmemory
= 0;
1028 ResetServerSaveParams();
1030 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
1031 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
1032 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1033 /* Replication related */
1035 server
.masterhost
= NULL
;
1036 server
.masterport
= 6379;
1037 server
.master
= NULL
;
1038 server
.replstate
= REDIS_REPL_NONE
;
1040 /* Double constants initialization */
1042 R_PosInf
= 1.0/R_Zero
;
1043 R_NegInf
= -1.0/R_Zero
;
1044 R_Nan
= R_Zero
/R_Zero
;
1047 static void initServer() {
1050 signal(SIGHUP
, SIG_IGN
);
1051 signal(SIGPIPE
, SIG_IGN
);
1052 setupSigSegvAction();
1054 server
.clients
= listCreate();
1055 server
.slaves
= listCreate();
1056 server
.monitors
= listCreate();
1057 server
.objfreelist
= listCreate();
1058 createSharedObjects();
1059 server
.el
= aeCreateEventLoop();
1060 server
.db
= zmalloc(sizeof(redisDb
)*server
.dbnum
);
1061 server
.sharingpool
= dictCreate(&setDictType
,NULL
);
1062 server
.fd
= anetTcpServer(server
.neterr
, server
.port
, server
.bindaddr
);
1063 if (server
.fd
== -1) {
1064 redisLog(REDIS_WARNING
, "Opening TCP port: %s", server
.neterr
);
1067 for (j
= 0; j
< server
.dbnum
; j
++) {
1068 server
.db
[j
].dict
= dictCreate(&hashDictType
,NULL
);
1069 server
.db
[j
].expires
= dictCreate(&setDictType
,NULL
);
1070 server
.db
[j
].id
= j
;
1072 server
.cronloops
= 0;
1073 server
.bgsaveinprogress
= 0;
1074 server
.bgsavechildpid
= -1;
1075 server
.lastsave
= time(NULL
);
1077 server
.usedmemory
= 0;
1078 server
.stat_numcommands
= 0;
1079 server
.stat_numconnections
= 0;
1080 server
.stat_starttime
= time(NULL
);
1081 aeCreateTimeEvent(server
.el
, 1000, serverCron
, NULL
, NULL
);
1084 /* Empty the whole database */
1085 static long long emptyDb() {
1087 long long removed
= 0;
1089 for (j
= 0; j
< server
.dbnum
; j
++) {
1090 removed
+= dictSize(server
.db
[j
].dict
);
1091 dictEmpty(server
.db
[j
].dict
);
1092 dictEmpty(server
.db
[j
].expires
);
1097 static int yesnotoi(char *s
) {
1098 if (!strcasecmp(s
,"yes")) return 1;
1099 else if (!strcasecmp(s
,"no")) return 0;
1103 /* I agree, this is a very rudimental way to load a configuration...
1104 will improve later if the config gets more complex */
1105 static void loadServerConfig(char *filename
) {
1107 char buf
[REDIS_CONFIGLINE_MAX
+1], *err
= NULL
;
1111 if (filename
[0] == '-' && filename
[1] == '\0')
1114 if ((fp
= fopen(filename
,"r")) == NULL
) {
1115 redisLog(REDIS_WARNING
,"Fatal error, can't open config file");
1120 while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) {
1126 line
= sdstrim(line
," \t\r\n");
1128 /* Skip comments and blank lines*/
1129 if (line
[0] == '#' || line
[0] == '\0') {
1134 /* Split into arguments */
1135 argv
= sdssplitlen(line
,sdslen(line
)," ",1,&argc
);
1136 sdstolower(argv
[0]);
1138 /* Execute config directives */
1139 if (!strcasecmp(argv
[0],"timeout") && argc
== 2) {
1140 server
.maxidletime
= atoi(argv
[1]);
1141 if (server
.maxidletime
< 0) {
1142 err
= "Invalid timeout value"; goto loaderr
;
1144 } else if (!strcasecmp(argv
[0],"port") && argc
== 2) {
1145 server
.port
= atoi(argv
[1]);
1146 if (server
.port
< 1 || server
.port
> 65535) {
1147 err
= "Invalid port"; goto loaderr
;
1149 } else if (!strcasecmp(argv
[0],"bind") && argc
== 2) {
1150 server
.bindaddr
= zstrdup(argv
[1]);
1151 } else if (!strcasecmp(argv
[0],"save") && argc
== 3) {
1152 int seconds
= atoi(argv
[1]);
1153 int changes
= atoi(argv
[2]);
1154 if (seconds
< 1 || changes
< 0) {
1155 err
= "Invalid save parameters"; goto loaderr
;
1157 appendServerSaveParams(seconds
,changes
);
1158 } else if (!strcasecmp(argv
[0],"dir") && argc
== 2) {
1159 if (chdir(argv
[1]) == -1) {
1160 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s",
1161 argv
[1], strerror(errno
));
1164 } else if (!strcasecmp(argv
[0],"loglevel") && argc
== 2) {
1165 if (!strcasecmp(argv
[1],"debug")) server
.verbosity
= REDIS_DEBUG
;
1166 else if (!strcasecmp(argv
[1],"notice")) server
.verbosity
= REDIS_NOTICE
;
1167 else if (!strcasecmp(argv
[1],"warning")) server
.verbosity
= REDIS_WARNING
;
1169 err
= "Invalid log level. Must be one of debug, notice, warning";
1172 } else if (!strcasecmp(argv
[0],"logfile") && argc
== 2) {
1175 server
.logfile
= zstrdup(argv
[1]);
1176 if (!strcasecmp(server
.logfile
,"stdout")) {
1177 zfree(server
.logfile
);
1178 server
.logfile
= NULL
;
1180 if (server
.logfile
) {
1181 /* Test if we are able to open the file. The server will not
1182 * be able to abort just for this problem later... */
1183 logfp
= fopen(server
.logfile
,"a");
1184 if (logfp
== NULL
) {
1185 err
= sdscatprintf(sdsempty(),
1186 "Can't open the log file: %s", strerror(errno
));
1191 } else if (!strcasecmp(argv
[0],"databases") && argc
== 2) {
1192 server
.dbnum
= atoi(argv
[1]);
1193 if (server
.dbnum
< 1) {
1194 err
= "Invalid number of databases"; goto loaderr
;
1196 } else if (!strcasecmp(argv
[0],"maxclients") && argc
== 2) {
1197 server
.maxclients
= atoi(argv
[1]);
1198 } else if (!strcasecmp(argv
[0],"maxmemory") && argc
== 2) {
1199 server
.maxmemory
= strtoll(argv
[1], NULL
, 10);
1200 } else if (!strcasecmp(argv
[0],"slaveof") && argc
== 3) {
1201 server
.masterhost
= sdsnew(argv
[1]);
1202 server
.masterport
= atoi(argv
[2]);
1203 server
.replstate
= REDIS_REPL_CONNECT
;
1204 } else if (!strcasecmp(argv
[0],"glueoutputbuf") && argc
== 2) {
1205 if ((server
.glueoutputbuf
= yesnotoi(argv
[1])) == -1) {
1206 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1208 } else if (!strcasecmp(argv
[0],"shareobjects") && argc
== 2) {
1209 if ((server
.shareobjects
= yesnotoi(argv
[1])) == -1) {
1210 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1212 } else if (!strcasecmp(argv
[0],"shareobjectspoolsize") && argc
== 2) {
1213 server
.sharingpoolsize
= atoi(argv
[1]);
1214 if (server
.sharingpoolsize
< 1) {
1215 err
= "invalid object sharing pool size"; goto loaderr
;
1217 } else if (!strcasecmp(argv
[0],"daemonize") && argc
== 2) {
1218 if ((server
.daemonize
= yesnotoi(argv
[1])) == -1) {
1219 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1221 } else if (!strcasecmp(argv
[0],"requirepass") && argc
== 2) {
1222 server
.requirepass
= zstrdup(argv
[1]);
1223 } else if (!strcasecmp(argv
[0],"pidfile") && argc
== 2) {
1224 server
.pidfile
= zstrdup(argv
[1]);
1225 } else if (!strcasecmp(argv
[0],"dbfilename") && argc
== 2) {
1226 server
.dbfilename
= zstrdup(argv
[1]);
1228 err
= "Bad directive or wrong number of arguments"; goto loaderr
;
1230 for (j
= 0; j
< argc
; j
++)
1235 if (fp
!= stdin
) fclose(fp
);
1239 fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n");
1240 fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
);
1241 fprintf(stderr
, ">>> '%s'\n", line
);
1242 fprintf(stderr
, "%s\n", err
);
1246 static void freeClientArgv(redisClient
*c
) {
1249 for (j
= 0; j
< c
->argc
; j
++)
1250 decrRefCount(c
->argv
[j
]);
1251 for (j
= 0; j
< c
->mbargc
; j
++)
1252 decrRefCount(c
->mbargv
[j
]);
1257 static void freeClient(redisClient
*c
) {
1260 aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
);
1261 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1262 sdsfree(c
->querybuf
);
1263 listRelease(c
->reply
);
1266 ln
= listSearchKey(server
.clients
,c
);
1268 listDelNode(server
.clients
,ln
);
1269 if (c
->flags
& REDIS_SLAVE
) {
1270 if (c
->replstate
== REDIS_REPL_SEND_BULK
&& c
->repldbfd
!= -1)
1272 list
*l
= (c
->flags
& REDIS_MONITOR
) ? server
.monitors
: server
.slaves
;
1273 ln
= listSearchKey(l
,c
);
1277 if (c
->flags
& REDIS_MASTER
) {
1278 server
.master
= NULL
;
1279 server
.replstate
= REDIS_REPL_CONNECT
;
1286 static void glueReplyBuffersIfNeeded(redisClient
*c
) {
1291 listRewind(c
->reply
);
1292 while((ln
= listYield(c
->reply
))) {
1294 totlen
+= sdslen(o
->ptr
);
1295 /* This optimization makes more sense if we don't have to copy
1297 if (totlen
> 1024) return;
1303 listRewind(c
->reply
);
1304 while((ln
= listYield(c
->reply
))) {
1306 memcpy(buf
+copylen
,o
->ptr
,sdslen(o
->ptr
));
1307 copylen
+= sdslen(o
->ptr
);
1308 listDelNode(c
->reply
,ln
);
1310 /* Now the output buffer is empty, add the new single element */
1311 o
= createObject(REDIS_STRING
,sdsnewlen(buf
,totlen
));
1312 listAddNodeTail(c
->reply
,o
);
1316 static void sendReplyToClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1317 redisClient
*c
= privdata
;
1318 int nwritten
= 0, totwritten
= 0, objlen
;
1321 REDIS_NOTUSED(mask
);
1323 if (server
.glueoutputbuf
&& listLength(c
->reply
) > 1)
1324 glueReplyBuffersIfNeeded(c
);
1325 while(listLength(c
->reply
)) {
1326 o
= listNodeValue(listFirst(c
->reply
));
1327 objlen
= sdslen(o
->ptr
);
1330 listDelNode(c
->reply
,listFirst(c
->reply
));
1334 if (c
->flags
& REDIS_MASTER
) {
1335 /* Don't reply to a master */
1336 nwritten
= objlen
- c
->sentlen
;
1338 nwritten
= write(fd
, ((char*)o
->ptr
)+c
->sentlen
, objlen
- c
->sentlen
);
1339 if (nwritten
<= 0) break;
1341 c
->sentlen
+= nwritten
;
1342 totwritten
+= nwritten
;
1343 /* If we fully sent the object on head go to the next one */
1344 if (c
->sentlen
== objlen
) {
1345 listDelNode(c
->reply
,listFirst(c
->reply
));
1348 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
1349 * bytes, in a single threaded server it's a good idea to server
1350 * other clients as well, even if a very large request comes from
1351 * super fast link that is always able to accept data (in real world
1352 * terms think to 'KEYS *' against the loopback interfae) */
1353 if (totwritten
> REDIS_MAX_WRITE_PER_EVENT
) break;
1355 if (nwritten
== -1) {
1356 if (errno
== EAGAIN
) {
1359 redisLog(REDIS_DEBUG
,
1360 "Error writing to client: %s", strerror(errno
));
1365 if (totwritten
> 0) c
->lastinteraction
= time(NULL
);
1366 if (listLength(c
->reply
) == 0) {
1368 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1372 static struct redisCommand
*lookupCommand(char *name
) {
1374 while(cmdTable
[j
].name
!= NULL
) {
1375 if (!strcasecmp(name
,cmdTable
[j
].name
)) return &cmdTable
[j
];
1381 /* resetClient prepare the client to process the next command */
1382 static void resetClient(redisClient
*c
) {
1388 /* If this function gets called we already read a whole
1389 * command, argments are in the client argv/argc fields.
1390 * processCommand() execute the command or prepare the
1391 * server for a bulk read from the client.
1393 * If 1 is returned the client is still alive and valid and
1394 * and other operations can be performed by the caller. Otherwise
1395 * if 0 is returned the client was destroied (i.e. after QUIT). */
1396 static int processCommand(redisClient
*c
) {
1397 struct redisCommand
*cmd
;
1400 /* Free some memory if needed (maxmemory setting) */
1401 if (server
.maxmemory
) freeMemoryIfNeeded();
1403 /* Handle the multi bulk command type. This is an alternative protocol
1404 * supported by Redis in order to receive commands that are composed of
1405 * multiple binary-safe "bulk" arguments. The latency of processing is
1406 * a bit higher but this allows things like multi-sets, so if this
1407 * protocol is used only for MSET and similar commands this is a big win. */
1408 if (c
->multibulk
== 0 && c
->argc
== 1 && ((char*)(c
->argv
[0]->ptr
))[0] == '*') {
1409 c
->multibulk
= atoi(((char*)c
->argv
[0]->ptr
)+1);
1410 if (c
->multibulk
<= 0) {
1414 decrRefCount(c
->argv
[c
->argc
-1]);
1418 } else if (c
->multibulk
) {
1419 if (c
->bulklen
== -1) {
1420 if (((char*)c
->argv
[0]->ptr
)[0] != '$') {
1421 addReplySds(c
,sdsnew("-ERR multi bulk protocol error\r\n"));
1425 int bulklen
= atoi(((char*)c
->argv
[0]->ptr
)+1);
1426 decrRefCount(c
->argv
[0]);
1427 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
1429 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
1434 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
1438 c
->mbargv
= zrealloc(c
->mbargv
,(sizeof(robj
*))*(c
->mbargc
+1));
1439 c
->mbargv
[c
->mbargc
] = c
->argv
[0];
1443 if (c
->multibulk
== 0) {
1447 /* Here we need to swap the multi-bulk argc/argv with the
1448 * normal argc/argv of the client structure. */
1450 c
->argv
= c
->mbargv
;
1451 c
->mbargv
= auxargv
;
1454 c
->argc
= c
->mbargc
;
1455 c
->mbargc
= auxargc
;
1457 /* We need to set bulklen to something different than -1
1458 * in order for the code below to process the command without
1459 * to try to read the last argument of a bulk command as
1460 * a special argument. */
1462 /* continue below and process the command */
1469 /* -- end of multi bulk commands processing -- */
1471 /* The QUIT command is handled as a special case. Normal command
1472 * procs are unable to close the client connection safely */
1473 if (!strcasecmp(c
->argv
[0]->ptr
,"quit")) {
1477 cmd
= lookupCommand(c
->argv
[0]->ptr
);
1479 addReplySds(c
,sdsnew("-ERR unknown command\r\n"));
1482 } else if ((cmd
->arity
> 0 && cmd
->arity
!= c
->argc
) ||
1483 (c
->argc
< -cmd
->arity
)) {
1484 addReplySds(c
,sdsnew("-ERR wrong number of arguments\r\n"));
1487 } else if (server
.maxmemory
&& cmd
->flags
& REDIS_CMD_DENYOOM
&& zmalloc_used_memory() > server
.maxmemory
) {
1488 addReplySds(c
,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
1491 } else if (cmd
->flags
& REDIS_CMD_BULK
&& c
->bulklen
== -1) {
1492 int bulklen
= atoi(c
->argv
[c
->argc
-1]->ptr
);
1494 decrRefCount(c
->argv
[c
->argc
-1]);
1495 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
1497 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
1502 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
1503 /* It is possible that the bulk read is already in the
1504 * buffer. Check this condition and handle it accordingly.
1505 * This is just a fast path, alternative to call processInputBuffer().
1506 * It's a good idea since the code is small and this condition
1507 * happens most of the times. */
1508 if ((signed)sdslen(c
->querybuf
) >= c
->bulklen
) {
1509 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
1511 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
1516 /* Let's try to share objects on the command arguments vector */
1517 if (server
.shareobjects
) {
1519 for(j
= 1; j
< c
->argc
; j
++)
1520 c
->argv
[j
] = tryObjectSharing(c
->argv
[j
]);
1522 /* Let's try to encode the bulk object to save space. */
1523 if (cmd
->flags
& REDIS_CMD_BULK
)
1524 tryObjectEncoding(c
->argv
[c
->argc
-1]);
1526 /* Check if the user is authenticated */
1527 if (server
.requirepass
&& !c
->authenticated
&& cmd
->proc
!= authCommand
) {
1528 addReplySds(c
,sdsnew("-ERR operation not permitted\r\n"));
1533 /* Exec the command */
1534 dirty
= server
.dirty
;
1536 if (server
.dirty
-dirty
!= 0 && listLength(server
.slaves
))
1537 replicationFeedSlaves(server
.slaves
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1538 if (listLength(server
.monitors
))
1539 replicationFeedSlaves(server
.monitors
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1540 server
.stat_numcommands
++;
1542 /* Prepare the client for the next command */
1543 if (c
->flags
& REDIS_CLOSE
) {
1551 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
) {
1555 /* (args*2)+1 is enough room for args, spaces, newlines */
1556 robj
*static_outv
[REDIS_STATIC_ARGS
*2+1];
1558 if (argc
<= REDIS_STATIC_ARGS
) {
1561 outv
= zmalloc(sizeof(robj
*)*(argc
*2+1));
1564 for (j
= 0; j
< argc
; j
++) {
1565 if (j
!= 0) outv
[outc
++] = shared
.space
;
1566 if ((cmd
->flags
& REDIS_CMD_BULK
) && j
== argc
-1) {
1569 lenobj
= createObject(REDIS_STRING
,
1570 sdscatprintf(sdsempty(),"%d\r\n",
1571 stringObjectLen(argv
[j
])));
1572 lenobj
->refcount
= 0;
1573 outv
[outc
++] = lenobj
;
1575 outv
[outc
++] = argv
[j
];
1577 outv
[outc
++] = shared
.crlf
;
1579 /* Increment all the refcounts at start and decrement at end in order to
1580 * be sure to free objects if there is no slave in a replication state
1581 * able to be feed with commands */
1582 for (j
= 0; j
< outc
; j
++) incrRefCount(outv
[j
]);
1584 while((ln
= listYield(slaves
))) {
1585 redisClient
*slave
= ln
->value
;
1587 /* Don't feed slaves that are still waiting for BGSAVE to start */
1588 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) continue;
1590 /* Feed all the other slaves, MONITORs and so on */
1591 if (slave
->slaveseldb
!= dictid
) {
1595 case 0: selectcmd
= shared
.select0
; break;
1596 case 1: selectcmd
= shared
.select1
; break;
1597 case 2: selectcmd
= shared
.select2
; break;
1598 case 3: selectcmd
= shared
.select3
; break;
1599 case 4: selectcmd
= shared
.select4
; break;
1600 case 5: selectcmd
= shared
.select5
; break;
1601 case 6: selectcmd
= shared
.select6
; break;
1602 case 7: selectcmd
= shared
.select7
; break;
1603 case 8: selectcmd
= shared
.select8
; break;
1604 case 9: selectcmd
= shared
.select9
; break;
1606 selectcmd
= createObject(REDIS_STRING
,
1607 sdscatprintf(sdsempty(),"select %d\r\n",dictid
));
1608 selectcmd
->refcount
= 0;
1611 addReply(slave
,selectcmd
);
1612 slave
->slaveseldb
= dictid
;
1614 for (j
= 0; j
< outc
; j
++) addReply(slave
,outv
[j
]);
1616 for (j
= 0; j
< outc
; j
++) decrRefCount(outv
[j
]);
1617 if (outv
!= static_outv
) zfree(outv
);
1620 static void processInputBuffer(redisClient
*c
) {
1622 if (c
->bulklen
== -1) {
1623 /* Read the first line of the query */
1624 char *p
= strchr(c
->querybuf
,'\n');
1631 query
= c
->querybuf
;
1632 c
->querybuf
= sdsempty();
1633 querylen
= 1+(p
-(query
));
1634 if (sdslen(query
) > querylen
) {
1635 /* leave data after the first line of the query in the buffer */
1636 c
->querybuf
= sdscatlen(c
->querybuf
,query
+querylen
,sdslen(query
)-querylen
);
1638 *p
= '\0'; /* remove "\n" */
1639 if (*(p
-1) == '\r') *(p
-1) = '\0'; /* and "\r" if any */
1640 sdsupdatelen(query
);
1642 /* Now we can split the query in arguments */
1643 if (sdslen(query
) == 0) {
1644 /* Ignore empty query */
1648 argv
= sdssplitlen(query
,sdslen(query
)," ",1,&argc
);
1651 if (c
->argv
) zfree(c
->argv
);
1652 c
->argv
= zmalloc(sizeof(robj
*)*argc
);
1654 for (j
= 0; j
< argc
; j
++) {
1655 if (sdslen(argv
[j
])) {
1656 c
->argv
[c
->argc
] = createObject(REDIS_STRING
,argv
[j
]);
1663 /* Execute the command. If the client is still valid
1664 * after processCommand() return and there is something
1665 * on the query buffer try to process the next command. */
1666 if (c
->argc
&& processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
1668 } else if (sdslen(c
->querybuf
) >= REDIS_REQUEST_MAX_SIZE
) {
1669 redisLog(REDIS_DEBUG
, "Client protocol error");
1674 /* Bulk read handling. Note that if we are at this point
1675 the client already sent a command terminated with a newline,
1676 we are reading the bulk data that is actually the last
1677 argument of the command. */
1678 int qbl
= sdslen(c
->querybuf
);
1680 if (c
->bulklen
<= qbl
) {
1681 /* Copy everything but the final CRLF as final argument */
1682 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
1684 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
1685 /* Process the command. If the client is still valid after
1686 * the processing and there is more data in the buffer
1687 * try to parse it. */
1688 if (processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
1694 static void readQueryFromClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1695 redisClient
*c
= (redisClient
*) privdata
;
1696 char buf
[REDIS_IOBUF_LEN
];
1699 REDIS_NOTUSED(mask
);
1701 nread
= read(fd
, buf
, REDIS_IOBUF_LEN
);
1703 if (errno
== EAGAIN
) {
1706 redisLog(REDIS_DEBUG
, "Reading from client: %s",strerror(errno
));
1710 } else if (nread
== 0) {
1711 redisLog(REDIS_DEBUG
, "Client closed connection");
1716 c
->querybuf
= sdscatlen(c
->querybuf
, buf
, nread
);
1717 c
->lastinteraction
= time(NULL
);
1721 processInputBuffer(c
);
1724 static int selectDb(redisClient
*c
, int id
) {
1725 if (id
< 0 || id
>= server
.dbnum
)
1727 c
->db
= &server
.db
[id
];
1731 static void *dupClientReplyValue(void *o
) {
1732 incrRefCount((robj
*)o
);
1736 static redisClient
*createClient(int fd
) {
1737 redisClient
*c
= zmalloc(sizeof(*c
));
1739 anetNonBlock(NULL
,fd
);
1740 anetTcpNoDelay(NULL
,fd
);
1741 if (!c
) return NULL
;
1744 c
->querybuf
= sdsempty();
1753 c
->lastinteraction
= time(NULL
);
1754 c
->authenticated
= 0;
1755 c
->replstate
= REDIS_REPL_NONE
;
1756 c
->reply
= listCreate();
1757 listSetFreeMethod(c
->reply
,decrRefCount
);
1758 listSetDupMethod(c
->reply
,dupClientReplyValue
);
1759 if (aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
,
1760 readQueryFromClient
, c
, NULL
) == AE_ERR
) {
1764 listAddNodeTail(server
.clients
,c
);
1768 static void addReply(redisClient
*c
, robj
*obj
) {
1769 if (listLength(c
->reply
) == 0 &&
1770 (c
->replstate
== REDIS_REPL_NONE
||
1771 c
->replstate
== REDIS_REPL_ONLINE
) &&
1772 aeCreateFileEvent(server
.el
, c
->fd
, AE_WRITABLE
,
1773 sendReplyToClient
, c
, NULL
) == AE_ERR
) return;
1774 if (obj
->encoding
!= REDIS_ENCODING_RAW
) {
1775 obj
= getDecodedObject(obj
);
1779 listAddNodeTail(c
->reply
,obj
);
1782 static void addReplySds(redisClient
*c
, sds s
) {
1783 robj
*o
= createObject(REDIS_STRING
,s
);
1788 static void addReplyBulkLen(redisClient
*c
, robj
*obj
) {
1791 if (obj
->encoding
== REDIS_ENCODING_RAW
) {
1792 len
= sdslen(obj
->ptr
);
1794 long n
= (long)obj
->ptr
;
1801 while((n
= n
/10) != 0) {
1805 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",len
));
1808 static void acceptHandler(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1813 REDIS_NOTUSED(mask
);
1814 REDIS_NOTUSED(privdata
);
1816 cfd
= anetAccept(server
.neterr
, fd
, cip
, &cport
);
1817 if (cfd
== AE_ERR
) {
1818 redisLog(REDIS_DEBUG
,"Accepting client connection: %s", server
.neterr
);
1821 redisLog(REDIS_DEBUG
,"Accepted %s:%d", cip
, cport
);
1822 if ((c
= createClient(cfd
)) == NULL
) {
1823 redisLog(REDIS_WARNING
,"Error allocating resoures for the client");
1824 close(cfd
); /* May be already closed, just ingore errors */
1827 /* If maxclient directive is set and this is one client more... close the
1828 * connection. Note that we create the client instead to check before
1829 * for this condition, since now the socket is already set in nonblocking
1830 * mode and we can send an error for free using the Kernel I/O */
1831 if (server
.maxclients
&& listLength(server
.clients
) > server
.maxclients
) {
1832 char *err
= "-ERR max number of clients reached\r\n";
1834 /* That's a best effort error message, don't check write errors */
1835 (void) write(c
->fd
,err
,strlen(err
));
1839 server
.stat_numconnections
++;
1842 /* ======================= Redis objects implementation ===================== */
1844 static robj
*createObject(int type
, void *ptr
) {
1847 if (listLength(server
.objfreelist
)) {
1848 listNode
*head
= listFirst(server
.objfreelist
);
1849 o
= listNodeValue(head
);
1850 listDelNode(server
.objfreelist
,head
);
1852 o
= zmalloc(sizeof(*o
));
1855 o
->encoding
= REDIS_ENCODING_RAW
;
1861 static robj
*createStringObject(char *ptr
, size_t len
) {
1862 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
1865 static robj
*createListObject(void) {
1866 list
*l
= listCreate();
1868 listSetFreeMethod(l
,decrRefCount
);
1869 return createObject(REDIS_LIST
,l
);
1872 static robj
*createSetObject(void) {
1873 dict
*d
= dictCreate(&setDictType
,NULL
);
1874 return createObject(REDIS_SET
,d
);
1877 static robj
*createZsetObject(void) {
1878 zset
*zs
= zmalloc(sizeof(*zs
));
1880 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
1881 zs
->zsl
= zslCreate();
1882 return createObject(REDIS_ZSET
,zs
);
1885 static void freeStringObject(robj
*o
) {
1886 if (o
->encoding
== REDIS_ENCODING_RAW
) {
1891 static void freeListObject(robj
*o
) {
1892 listRelease((list
*) o
->ptr
);
1895 static void freeSetObject(robj
*o
) {
1896 dictRelease((dict
*) o
->ptr
);
1899 static void freeZsetObject(robj
*o
) {
1902 dictRelease(zs
->dict
);
1907 static void freeHashObject(robj
*o
) {
1908 dictRelease((dict
*) o
->ptr
);
1911 static void incrRefCount(robj
*o
) {
1913 #ifdef DEBUG_REFCOUNT
1914 if (o
->type
== REDIS_STRING
)
1915 printf("Increment '%s'(%p), now is: %d\n",o
->ptr
,o
,o
->refcount
);
1919 static void decrRefCount(void *obj
) {
1922 #ifdef DEBUG_REFCOUNT
1923 if (o
->type
== REDIS_STRING
)
1924 printf("Decrement '%s'(%p), now is: %d\n",o
->ptr
,o
,o
->refcount
-1);
1926 if (--(o
->refcount
) == 0) {
1928 case REDIS_STRING
: freeStringObject(o
); break;
1929 case REDIS_LIST
: freeListObject(o
); break;
1930 case REDIS_SET
: freeSetObject(o
); break;
1931 case REDIS_ZSET
: freeZsetObject(o
); break;
1932 case REDIS_HASH
: freeHashObject(o
); break;
1933 default: assert(0 != 0); break;
1935 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
1936 !listAddNodeHead(server
.objfreelist
,o
))
1941 static robj
*lookupKey(redisDb
*db
, robj
*key
) {
1942 dictEntry
*de
= dictFind(db
->dict
,key
);
1943 return de
? dictGetEntryVal(de
) : NULL
;
1946 static robj
*lookupKeyRead(redisDb
*db
, robj
*key
) {
1947 expireIfNeeded(db
,key
);
1948 return lookupKey(db
,key
);
1951 static robj
*lookupKeyWrite(redisDb
*db
, robj
*key
) {
1952 deleteIfVolatile(db
,key
);
1953 return lookupKey(db
,key
);
1956 static int deleteKey(redisDb
*db
, robj
*key
) {
1959 /* We need to protect key from destruction: after the first dictDelete()
1960 * it may happen that 'key' is no longer valid if we don't increment
1961 * it's count. This may happen when we get the object reference directly
1962 * from the hash table with dictRandomKey() or dict iterators */
1964 if (dictSize(db
->expires
)) dictDelete(db
->expires
,key
);
1965 retval
= dictDelete(db
->dict
,key
);
1968 return retval
== DICT_OK
;
1971 /* Try to share an object against the shared objects pool */
1972 static robj
*tryObjectSharing(robj
*o
) {
1973 struct dictEntry
*de
;
1976 if (o
== NULL
|| server
.shareobjects
== 0) return o
;
1978 assert(o
->type
== REDIS_STRING
);
1979 de
= dictFind(server
.sharingpool
,o
);
1981 robj
*shared
= dictGetEntryKey(de
);
1983 c
= ((unsigned long) dictGetEntryVal(de
))+1;
1984 dictGetEntryVal(de
) = (void*) c
;
1985 incrRefCount(shared
);
1989 /* Here we are using a stream algorihtm: Every time an object is
1990 * shared we increment its count, everytime there is a miss we
1991 * recrement the counter of a random object. If this object reaches
1992 * zero we remove the object and put the current object instead. */
1993 if (dictSize(server
.sharingpool
) >=
1994 server
.sharingpoolsize
) {
1995 de
= dictGetRandomKey(server
.sharingpool
);
1997 c
= ((unsigned long) dictGetEntryVal(de
))-1;
1998 dictGetEntryVal(de
) = (void*) c
;
2000 dictDelete(server
.sharingpool
,de
->key
);
2003 c
= 0; /* If the pool is empty we want to add this object */
2008 retval
= dictAdd(server
.sharingpool
,o
,(void*)1);
2009 assert(retval
== DICT_OK
);
2016 /* Check if the nul-terminated string 's' can be represented by a long
2017 * (that is, is a number that fits into long without any other space or
2018 * character before or after the digits).
2020 * If so, the function returns REDIS_OK and *longval is set to the value
2021 * of the number. Otherwise REDIS_ERR is returned */
2022 static int isStringRepresentableAsLong(sds s
, long *longval
) {
2023 char buf
[32], *endptr
;
2027 value
= strtol(s
, &endptr
, 10);
2028 if (endptr
[0] != '\0') return REDIS_ERR
;
2029 slen
= snprintf(buf
,32,"%ld",value
);
2031 /* If the number converted back into a string is not identical
2032 * then it's not possible to encode the string as integer */
2033 if (sdslen(s
) != (unsigned)slen
|| memcmp(buf
,s
,slen
)) return REDIS_ERR
;
2034 if (longval
) *longval
= value
;
2038 /* Try to encode a string object in order to save space */
2039 static int tryObjectEncoding(robj
*o
) {
2043 if (o
->encoding
!= REDIS_ENCODING_RAW
)
2044 return REDIS_ERR
; /* Already encoded */
2046 /* It's not save to encode shared objects: shared objects can be shared
2047 * everywhere in the "object space" of Redis. Encoded objects can only
2048 * appear as "values" (and not, for instance, as keys) */
2049 if (o
->refcount
> 1) return REDIS_ERR
;
2051 /* Currently we try to encode only strings */
2052 assert(o
->type
== REDIS_STRING
);
2054 /* Check if we can represent this string as a long integer */
2055 if (isStringRepresentableAsLong(s
,&value
) == REDIS_ERR
) return REDIS_ERR
;
2057 /* Ok, this object can be encoded */
2058 o
->encoding
= REDIS_ENCODING_INT
;
2060 o
->ptr
= (void*) value
;
2064 /* Get a decoded version of an encoded object (returned as a new object) */
2065 static robj
*getDecodedObject(const robj
*o
) {
2068 assert(o
->encoding
!= REDIS_ENCODING_RAW
);
2069 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
2072 snprintf(buf
,32,"%ld",(long)o
->ptr
);
2073 dec
= createStringObject(buf
,strlen(buf
));
2080 /* Compare two string objects via strcmp() or alike.
2081 * Note that the objects may be integer-encoded. In such a case we
2082 * use snprintf() to get a string representation of the numbers on the stack
2083 * and compare the strings, it's much faster than calling getDecodedObject(). */
2084 static int compareStringObjects(robj
*a
, robj
*b
) {
2085 assert(a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
2086 char bufa
[128], bufb
[128], *astr
, *bstr
;
2089 if (a
== b
) return 0;
2090 if (a
->encoding
!= REDIS_ENCODING_RAW
) {
2091 snprintf(bufa
,sizeof(bufa
),"%ld",(long) a
->ptr
);
2097 if (b
->encoding
!= REDIS_ENCODING_RAW
) {
2098 snprintf(bufb
,sizeof(bufb
),"%ld",(long) b
->ptr
);
2104 return bothsds
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
);
2107 static size_t stringObjectLen(robj
*o
) {
2108 assert(o
->type
== REDIS_STRING
);
2109 if (o
->encoding
== REDIS_ENCODING_RAW
) {
2110 return sdslen(o
->ptr
);
2114 return snprintf(buf
,32,"%ld",(long)o
->ptr
);
2118 /*============================ DB saving/loading ============================ */
2120 static int rdbSaveType(FILE *fp
, unsigned char type
) {
2121 if (fwrite(&type
,1,1,fp
) == 0) return -1;
2125 static int rdbSaveTime(FILE *fp
, time_t t
) {
2126 int32_t t32
= (int32_t) t
;
2127 if (fwrite(&t32
,4,1,fp
) == 0) return -1;
2131 /* check rdbLoadLen() comments for more info */
2132 static int rdbSaveLen(FILE *fp
, uint32_t len
) {
2133 unsigned char buf
[2];
2136 /* Save a 6 bit len */
2137 buf
[0] = (len
&0xFF)|(REDIS_RDB_6BITLEN
<<6);
2138 if (fwrite(buf
,1,1,fp
) == 0) return -1;
2139 } else if (len
< (1<<14)) {
2140 /* Save a 14 bit len */
2141 buf
[0] = ((len
>>8)&0xFF)|(REDIS_RDB_14BITLEN
<<6);
2143 if (fwrite(buf
,2,1,fp
) == 0) return -1;
2145 /* Save a 32 bit len */
2146 buf
[0] = (REDIS_RDB_32BITLEN
<<6);
2147 if (fwrite(buf
,1,1,fp
) == 0) return -1;
2149 if (fwrite(&len
,4,1,fp
) == 0) return -1;
2154 /* String objects in the form "2391" "-100" without any space and with a
2155 * range of values that can fit in an 8, 16 or 32 bit signed value can be
2156 * encoded as integers to save space */
2157 static int rdbTryIntegerEncoding(sds s
, unsigned char *enc
) {
2159 char *endptr
, buf
[32];
2161 /* Check if it's possible to encode this value as a number */
2162 value
= strtoll(s
, &endptr
, 10);
2163 if (endptr
[0] != '\0') return 0;
2164 snprintf(buf
,32,"%lld",value
);
2166 /* If the number converted back into a string is not identical
2167 * then it's not possible to encode the string as integer */
2168 if (strlen(buf
) != sdslen(s
) || memcmp(buf
,s
,sdslen(s
))) return 0;
2170 /* Finally check if it fits in our ranges */
2171 if (value
>= -(1<<7) && value
<= (1<<7)-1) {
2172 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT8
;
2173 enc
[1] = value
&0xFF;
2175 } else if (value
>= -(1<<15) && value
<= (1<<15)-1) {
2176 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT16
;
2177 enc
[1] = value
&0xFF;
2178 enc
[2] = (value
>>8)&0xFF;
2180 } else if (value
>= -((long long)1<<31) && value
<= ((long long)1<<31)-1) {
2181 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT32
;
2182 enc
[1] = value
&0xFF;
2183 enc
[2] = (value
>>8)&0xFF;
2184 enc
[3] = (value
>>16)&0xFF;
2185 enc
[4] = (value
>>24)&0xFF;
2192 static int rdbSaveLzfStringObject(FILE *fp
, robj
*obj
) {
2193 unsigned int comprlen
, outlen
;
2197 /* We require at least four bytes compression for this to be worth it */
2198 outlen
= sdslen(obj
->ptr
)-4;
2199 if (outlen
<= 0) return 0;
2200 if ((out
= zmalloc(outlen
+1)) == NULL
) return 0;
2201 comprlen
= lzf_compress(obj
->ptr
, sdslen(obj
->ptr
), out
, outlen
);
2202 if (comprlen
== 0) {
2206 /* Data compressed! Let's save it on disk */
2207 byte
= (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_LZF
;
2208 if (fwrite(&byte
,1,1,fp
) == 0) goto writeerr
;
2209 if (rdbSaveLen(fp
,comprlen
) == -1) goto writeerr
;
2210 if (rdbSaveLen(fp
,sdslen(obj
->ptr
)) == -1) goto writeerr
;
2211 if (fwrite(out
,comprlen
,1,fp
) == 0) goto writeerr
;
2220 /* Save a string objet as [len][data] on disk. If the object is a string
2221 * representation of an integer value we try to safe it in a special form */
2222 static int rdbSaveStringObjectRaw(FILE *fp
, robj
*obj
) {
2226 len
= sdslen(obj
->ptr
);
2228 /* Try integer encoding */
2230 unsigned char buf
[5];
2231 if ((enclen
= rdbTryIntegerEncoding(obj
->ptr
,buf
)) > 0) {
2232 if (fwrite(buf
,enclen
,1,fp
) == 0) return -1;
2237 /* Try LZF compression - under 20 bytes it's unable to compress even
2238 * aaaaaaaaaaaaaaaaaa so skip it */
2242 retval
= rdbSaveLzfStringObject(fp
,obj
);
2243 if (retval
== -1) return -1;
2244 if (retval
> 0) return 0;
2245 /* retval == 0 means data can't be compressed, save the old way */
2248 /* Store verbatim */
2249 if (rdbSaveLen(fp
,len
) == -1) return -1;
2250 if (len
&& fwrite(obj
->ptr
,len
,1,fp
) == 0) return -1;
2254 /* Like rdbSaveStringObjectRaw() but handle encoded objects */
2255 static int rdbSaveStringObject(FILE *fp
, robj
*obj
) {
2259 if (obj
->encoding
!= REDIS_ENCODING_RAW
) {
2260 dec
= getDecodedObject(obj
);
2261 retval
= rdbSaveStringObjectRaw(fp
,dec
);
2265 return rdbSaveStringObjectRaw(fp
,obj
);
2269 /* Save a double value. Doubles are saved as strings prefixed by an unsigned
2270 * 8 bit integer specifing the length of the representation.
2271 * This 8 bit integer has special values in order to specify the following
2277 static int rdbSaveDoubleValue(FILE *fp
, double val
) {
2278 unsigned char buf
[128];
2284 } else if (!isfinite(val
)) {
2286 buf
[0] = (val
< 0) ? 255 : 254;
2288 snprintf((char*)buf
+1,sizeof(buf
)-1,"%.16g",val
);
2289 buf
[0] = strlen((char*)buf
);
2292 if (fwrite(buf
,len
,1,fp
) == 0) return -1;
2296 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
2297 static int rdbSave(char *filename
) {
2298 dictIterator
*di
= NULL
;
2303 time_t now
= time(NULL
);
2305 snprintf(tmpfile
,256,"temp-%d.rdb", (int) getpid());
2306 fp
= fopen(tmpfile
,"w");
2308 redisLog(REDIS_WARNING
, "Failed saving the DB: %s", strerror(errno
));
2311 if (fwrite("REDIS0001",9,1,fp
) == 0) goto werr
;
2312 for (j
= 0; j
< server
.dbnum
; j
++) {
2313 redisDb
*db
= server
.db
+j
;
2315 if (dictSize(d
) == 0) continue;
2316 di
= dictGetIterator(d
);
2322 /* Write the SELECT DB opcode */
2323 if (rdbSaveType(fp
,REDIS_SELECTDB
) == -1) goto werr
;
2324 if (rdbSaveLen(fp
,j
) == -1) goto werr
;
2326 /* Iterate this DB writing every entry */
2327 while((de
= dictNext(di
)) != NULL
) {
2328 robj
*key
= dictGetEntryKey(de
);
2329 robj
*o
= dictGetEntryVal(de
);
2330 time_t expiretime
= getExpire(db
,key
);
2332 /* Save the expire time */
2333 if (expiretime
!= -1) {
2334 /* If this key is already expired skip it */
2335 if (expiretime
< now
) continue;
2336 if (rdbSaveType(fp
,REDIS_EXPIRETIME
) == -1) goto werr
;
2337 if (rdbSaveTime(fp
,expiretime
) == -1) goto werr
;
2339 /* Save the key and associated value */
2340 if (rdbSaveType(fp
,o
->type
) == -1) goto werr
;
2341 if (rdbSaveStringObject(fp
,key
) == -1) goto werr
;
2342 if (o
->type
== REDIS_STRING
) {
2343 /* Save a string value */
2344 if (rdbSaveStringObject(fp
,o
) == -1) goto werr
;
2345 } else if (o
->type
== REDIS_LIST
) {
2346 /* Save a list value */
2347 list
*list
= o
->ptr
;
2351 if (rdbSaveLen(fp
,listLength(list
)) == -1) goto werr
;
2352 while((ln
= listYield(list
))) {
2353 robj
*eleobj
= listNodeValue(ln
);
2355 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
2357 } else if (o
->type
== REDIS_SET
) {
2358 /* Save a set value */
2360 dictIterator
*di
= dictGetIterator(set
);
2363 if (rdbSaveLen(fp
,dictSize(set
)) == -1) goto werr
;
2364 while((de
= dictNext(di
)) != NULL
) {
2365 robj
*eleobj
= dictGetEntryKey(de
);
2367 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
2369 dictReleaseIterator(di
);
2370 } else if (o
->type
== REDIS_ZSET
) {
2371 /* Save a set value */
2373 dictIterator
*di
= dictGetIterator(zs
->dict
);
2376 if (rdbSaveLen(fp
,dictSize(zs
->dict
)) == -1) goto werr
;
2377 while((de
= dictNext(di
)) != NULL
) {
2378 robj
*eleobj
= dictGetEntryKey(de
);
2379 double *score
= dictGetEntryVal(de
);
2381 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
2382 if (rdbSaveDoubleValue(fp
,*score
) == -1) goto werr
;
2384 dictReleaseIterator(di
);
2389 dictReleaseIterator(di
);
2392 if (rdbSaveType(fp
,REDIS_EOF
) == -1) goto werr
;
2394 /* Make sure data will not remain on the OS's output buffers */
2399 /* Use RENAME to make sure the DB file is changed atomically only
2400 * if the generate DB file is ok. */
2401 if (rename(tmpfile
,filename
) == -1) {
2402 redisLog(REDIS_WARNING
,"Error moving temp DB file on the final destination: %s", strerror(errno
));
2406 redisLog(REDIS_NOTICE
,"DB saved on disk");
2408 server
.lastsave
= time(NULL
);
2414 redisLog(REDIS_WARNING
,"Write error saving DB on disk: %s", strerror(errno
));
2415 if (di
) dictReleaseIterator(di
);
2419 static int rdbSaveBackground(char *filename
) {
2422 if (server
.bgsaveinprogress
) return REDIS_ERR
;
2423 if ((childpid
= fork()) == 0) {
2426 if (rdbSave(filename
) == REDIS_OK
) {
2433 if (childpid
== -1) {
2434 redisLog(REDIS_WARNING
,"Can't save in background: fork: %s",
2438 redisLog(REDIS_NOTICE
,"Background saving started by pid %d",childpid
);
2439 server
.bgsaveinprogress
= 1;
2440 server
.bgsavechildpid
= childpid
;
2443 return REDIS_OK
; /* unreached */
2446 static void rdbRemoveTempFile(pid_t childpid
) {
2449 snprintf(tmpfile
,256,"temp-%d.rdb", (int) childpid
);
2453 static int rdbLoadType(FILE *fp
) {
2455 if (fread(&type
,1,1,fp
) == 0) return -1;
2459 static time_t rdbLoadTime(FILE *fp
) {
2461 if (fread(&t32
,4,1,fp
) == 0) return -1;
2462 return (time_t) t32
;
2465 /* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
2466 * of this file for a description of how this are stored on disk.
2468 * isencoded is set to 1 if the readed length is not actually a length but
2469 * an "encoding type", check the above comments for more info */
2470 static uint32_t rdbLoadLen(FILE *fp
, int rdbver
, int *isencoded
) {
2471 unsigned char buf
[2];
2474 if (isencoded
) *isencoded
= 0;
2476 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
2481 if (fread(buf
,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2482 type
= (buf
[0]&0xC0)>>6;
2483 if (type
== REDIS_RDB_6BITLEN
) {
2484 /* Read a 6 bit len */
2486 } else if (type
== REDIS_RDB_ENCVAL
) {
2487 /* Read a 6 bit len encoding type */
2488 if (isencoded
) *isencoded
= 1;
2490 } else if (type
== REDIS_RDB_14BITLEN
) {
2491 /* Read a 14 bit len */
2492 if (fread(buf
+1,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2493 return ((buf
[0]&0x3F)<<8)|buf
[1];
2495 /* Read a 32 bit len */
2496 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
2502 static robj
*rdbLoadIntegerObject(FILE *fp
, int enctype
) {
2503 unsigned char enc
[4];
2506 if (enctype
== REDIS_RDB_ENC_INT8
) {
2507 if (fread(enc
,1,1,fp
) == 0) return NULL
;
2508 val
= (signed char)enc
[0];
2509 } else if (enctype
== REDIS_RDB_ENC_INT16
) {
2511 if (fread(enc
,2,1,fp
) == 0) return NULL
;
2512 v
= enc
[0]|(enc
[1]<<8);
2514 } else if (enctype
== REDIS_RDB_ENC_INT32
) {
2516 if (fread(enc
,4,1,fp
) == 0) return NULL
;
2517 v
= enc
[0]|(enc
[1]<<8)|(enc
[2]<<16)|(enc
[3]<<24);
2520 val
= 0; /* anti-warning */
2523 return createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",val
));
2526 static robj
*rdbLoadLzfStringObject(FILE*fp
, int rdbver
) {
2527 unsigned int len
, clen
;
2528 unsigned char *c
= NULL
;
2531 if ((clen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2532 if ((len
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2533 if ((c
= zmalloc(clen
)) == NULL
) goto err
;
2534 if ((val
= sdsnewlen(NULL
,len
)) == NULL
) goto err
;
2535 if (fread(c
,clen
,1,fp
) == 0) goto err
;
2536 if (lzf_decompress(c
,clen
,val
,len
) == 0) goto err
;
2538 return createObject(REDIS_STRING
,val
);
2545 static robj
*rdbLoadStringObject(FILE*fp
, int rdbver
) {
2550 len
= rdbLoadLen(fp
,rdbver
,&isencoded
);
2553 case REDIS_RDB_ENC_INT8
:
2554 case REDIS_RDB_ENC_INT16
:
2555 case REDIS_RDB_ENC_INT32
:
2556 return tryObjectSharing(rdbLoadIntegerObject(fp
,len
));
2557 case REDIS_RDB_ENC_LZF
:
2558 return tryObjectSharing(rdbLoadLzfStringObject(fp
,rdbver
));
2564 if (len
== REDIS_RDB_LENERR
) return NULL
;
2565 val
= sdsnewlen(NULL
,len
);
2566 if (len
&& fread(val
,len
,1,fp
) == 0) {
2570 return tryObjectSharing(createObject(REDIS_STRING
,val
));
2573 /* For information about double serialization check rdbSaveDoubleValue() */
2574 static int rdbLoadDoubleValue(FILE *fp
, double *val
) {
2578 if (fread(&len
,1,1,fp
) == 0) return -1;
2580 case 255: *val
= R_NegInf
; return 0;
2581 case 254: *val
= R_PosInf
; return 0;
2582 case 253: *val
= R_Nan
; return 0;
2584 if (fread(buf
,len
,1,fp
) == 0) return -1;
2585 sscanf(buf
, "%lg", val
);
2590 static int rdbLoad(char *filename
) {
2592 robj
*keyobj
= NULL
;
2594 int type
, retval
, rdbver
;
2595 dict
*d
= server
.db
[0].dict
;
2596 redisDb
*db
= server
.db
+0;
2598 time_t expiretime
= -1, now
= time(NULL
);
2600 fp
= fopen(filename
,"r");
2601 if (!fp
) return REDIS_ERR
;
2602 if (fread(buf
,9,1,fp
) == 0) goto eoferr
;
2604 if (memcmp(buf
,"REDIS",5) != 0) {
2606 redisLog(REDIS_WARNING
,"Wrong signature trying to load DB from file");
2609 rdbver
= atoi(buf
+5);
2612 redisLog(REDIS_WARNING
,"Can't handle RDB format version %d",rdbver
);
2619 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
2620 if (type
== REDIS_EXPIRETIME
) {
2621 if ((expiretime
= rdbLoadTime(fp
)) == -1) goto eoferr
;
2622 /* We read the time so we need to read the object type again */
2623 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
2625 if (type
== REDIS_EOF
) break;
2626 /* Handle SELECT DB opcode as a special case */
2627 if (type
== REDIS_SELECTDB
) {
2628 if ((dbid
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2630 if (dbid
>= (unsigned)server
.dbnum
) {
2631 redisLog(REDIS_WARNING
,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server
.dbnum
);
2634 db
= server
.db
+dbid
;
2639 if ((keyobj
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2641 if (type
== REDIS_STRING
) {
2642 /* Read string value */
2643 if ((o
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2644 tryObjectEncoding(o
);
2645 } else if (type
== REDIS_LIST
|| type
== REDIS_SET
) {
2646 /* Read list/set value */
2649 if ((listlen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2651 o
= (type
== REDIS_LIST
) ? createListObject() : createSetObject();
2652 /* Load every single element of the list/set */
2656 if ((ele
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2657 tryObjectEncoding(ele
);
2658 if (type
== REDIS_LIST
) {
2659 listAddNodeTail((list
*)o
->ptr
,ele
);
2661 dictAdd((dict
*)o
->ptr
,ele
,NULL
);
2664 } else if (type
== REDIS_ZSET
) {
2665 /* Read list/set value */
2669 if ((zsetlen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2671 o
= createZsetObject();
2673 /* Load every single element of the list/set */
2676 double *score
= zmalloc(sizeof(double));
2678 if ((ele
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2679 tryObjectEncoding(ele
);
2680 if (rdbLoadDoubleValue(fp
,score
) == -1) goto eoferr
;
2681 dictAdd(zs
->dict
,ele
,score
);
2682 zslInsert(zs
->zsl
,*score
,ele
);
2683 incrRefCount(ele
); /* added to skiplist */
2688 /* Add the new object in the hash table */
2689 retval
= dictAdd(d
,keyobj
,o
);
2690 if (retval
== DICT_ERR
) {
2691 redisLog(REDIS_WARNING
,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj
->ptr
);
2694 /* Set the expire time if needed */
2695 if (expiretime
!= -1) {
2696 setExpire(db
,keyobj
,expiretime
);
2697 /* Delete this key if already expired */
2698 if (expiretime
< now
) deleteKey(db
,keyobj
);
2706 eoferr
: /* unexpected end of file is handled here with a fatal exit */
2707 if (keyobj
) decrRefCount(keyobj
);
2708 redisLog(REDIS_WARNING
,"Short read or OOM loading DB. Unrecoverable error, exiting now.");
2710 return REDIS_ERR
; /* Just to avoid warning */
2713 /*================================== Commands =============================== */
2715 static void authCommand(redisClient
*c
) {
2716 if (!server
.requirepass
|| !strcmp(c
->argv
[1]->ptr
, server
.requirepass
)) {
2717 c
->authenticated
= 1;
2718 addReply(c
,shared
.ok
);
2720 c
->authenticated
= 0;
2721 addReply(c
,shared
.err
);
2725 static void pingCommand(redisClient
*c
) {
2726 addReply(c
,shared
.pong
);
2729 static void echoCommand(redisClient
*c
) {
2730 addReplyBulkLen(c
,c
->argv
[1]);
2731 addReply(c
,c
->argv
[1]);
2732 addReply(c
,shared
.crlf
);
2735 /*=================================== Strings =============================== */
2737 static void setGenericCommand(redisClient
*c
, int nx
) {
2740 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2741 if (retval
== DICT_ERR
) {
2743 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2744 incrRefCount(c
->argv
[2]);
2746 addReply(c
,shared
.czero
);
2750 incrRefCount(c
->argv
[1]);
2751 incrRefCount(c
->argv
[2]);
2754 removeExpire(c
->db
,c
->argv
[1]);
2755 addReply(c
, nx
? shared
.cone
: shared
.ok
);
2758 static void setCommand(redisClient
*c
) {
2759 setGenericCommand(c
,0);
2762 static void setnxCommand(redisClient
*c
) {
2763 setGenericCommand(c
,1);
2766 static void getCommand(redisClient
*c
) {
2767 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2770 addReply(c
,shared
.nullbulk
);
2772 if (o
->type
!= REDIS_STRING
) {
2773 addReply(c
,shared
.wrongtypeerr
);
2775 addReplyBulkLen(c
,o
);
2777 addReply(c
,shared
.crlf
);
2782 static void getsetCommand(redisClient
*c
) {
2784 if (dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]) == DICT_ERR
) {
2785 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2787 incrRefCount(c
->argv
[1]);
2789 incrRefCount(c
->argv
[2]);
2791 removeExpire(c
->db
,c
->argv
[1]);
2794 static void mgetCommand(redisClient
*c
) {
2797 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",c
->argc
-1));
2798 for (j
= 1; j
< c
->argc
; j
++) {
2799 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
2801 addReply(c
,shared
.nullbulk
);
2803 if (o
->type
!= REDIS_STRING
) {
2804 addReply(c
,shared
.nullbulk
);
2806 addReplyBulkLen(c
,o
);
2808 addReply(c
,shared
.crlf
);
2814 static void incrDecrCommand(redisClient
*c
, long long incr
) {
2819 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2823 if (o
->type
!= REDIS_STRING
) {
2828 if (o
->encoding
== REDIS_ENCODING_RAW
)
2829 value
= strtoll(o
->ptr
, &eptr
, 10);
2830 else if (o
->encoding
== REDIS_ENCODING_INT
)
2831 value
= (long)o
->ptr
;
2838 o
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",value
));
2839 tryObjectEncoding(o
);
2840 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],o
);
2841 if (retval
== DICT_ERR
) {
2842 dictReplace(c
->db
->dict
,c
->argv
[1],o
);
2843 removeExpire(c
->db
,c
->argv
[1]);
2845 incrRefCount(c
->argv
[1]);
2848 addReply(c
,shared
.colon
);
2850 addReply(c
,shared
.crlf
);
2853 static void incrCommand(redisClient
*c
) {
2854 incrDecrCommand(c
,1);
2857 static void decrCommand(redisClient
*c
) {
2858 incrDecrCommand(c
,-1);
2861 static void incrbyCommand(redisClient
*c
) {
2862 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
2863 incrDecrCommand(c
,incr
);
2866 static void decrbyCommand(redisClient
*c
) {
2867 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
2868 incrDecrCommand(c
,-incr
);
2871 /* ========================= Type agnostic commands ========================= */
2873 static void delCommand(redisClient
*c
) {
2876 for (j
= 1; j
< c
->argc
; j
++) {
2877 if (deleteKey(c
->db
,c
->argv
[j
])) {
2884 addReply(c
,shared
.czero
);
2887 addReply(c
,shared
.cone
);
2890 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",deleted
));
2895 static void existsCommand(redisClient
*c
) {
2896 addReply(c
,lookupKeyRead(c
->db
,c
->argv
[1]) ? shared
.cone
: shared
.czero
);
2899 static void selectCommand(redisClient
*c
) {
2900 int id
= atoi(c
->argv
[1]->ptr
);
2902 if (selectDb(c
,id
) == REDIS_ERR
) {
2903 addReplySds(c
,sdsnew("-ERR invalid DB index\r\n"));
2905 addReply(c
,shared
.ok
);
2909 static void randomkeyCommand(redisClient
*c
) {
2913 de
= dictGetRandomKey(c
->db
->dict
);
2914 if (!de
|| expireIfNeeded(c
->db
,dictGetEntryKey(de
)) == 0) break;
2917 addReply(c
,shared
.plus
);
2918 addReply(c
,shared
.crlf
);
2920 addReply(c
,shared
.plus
);
2921 addReply(c
,dictGetEntryKey(de
));
2922 addReply(c
,shared
.crlf
);
2926 static void keysCommand(redisClient
*c
) {
2929 sds pattern
= c
->argv
[1]->ptr
;
2930 int plen
= sdslen(pattern
);
2931 int numkeys
= 0, keyslen
= 0;
2932 robj
*lenobj
= createObject(REDIS_STRING
,NULL
);
2934 di
= dictGetIterator(c
->db
->dict
);
2936 decrRefCount(lenobj
);
2937 while((de
= dictNext(di
)) != NULL
) {
2938 robj
*keyobj
= dictGetEntryKey(de
);
2940 sds key
= keyobj
->ptr
;
2941 if ((pattern
[0] == '*' && pattern
[1] == '\0') ||
2942 stringmatchlen(pattern
,plen
,key
,sdslen(key
),0)) {
2943 if (expireIfNeeded(c
->db
,keyobj
) == 0) {
2945 addReply(c
,shared
.space
);
2948 keyslen
+= sdslen(key
);
2952 dictReleaseIterator(di
);
2953 lenobj
->ptr
= sdscatprintf(sdsempty(),"$%lu\r\n",keyslen
+(numkeys
? (numkeys
-1) : 0));
2954 addReply(c
,shared
.crlf
);
2957 static void dbsizeCommand(redisClient
*c
) {
2959 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c
->db
->dict
)));
2962 static void lastsaveCommand(redisClient
*c
) {
2964 sdscatprintf(sdsempty(),":%lu\r\n",server
.lastsave
));
2967 static void typeCommand(redisClient
*c
) {
2971 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2976 case REDIS_STRING
: type
= "+string"; break;
2977 case REDIS_LIST
: type
= "+list"; break;
2978 case REDIS_SET
: type
= "+set"; break;
2979 default: type
= "unknown"; break;
2982 addReplySds(c
,sdsnew(type
));
2983 addReply(c
,shared
.crlf
);
2986 static void saveCommand(redisClient
*c
) {
2987 if (server
.bgsaveinprogress
) {
2988 addReplySds(c
,sdsnew("-ERR background save in progress\r\n"));
2991 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
2992 addReply(c
,shared
.ok
);
2994 addReply(c
,shared
.err
);
2998 static void bgsaveCommand(redisClient
*c
) {
2999 if (server
.bgsaveinprogress
) {
3000 addReplySds(c
,sdsnew("-ERR background save already in progress\r\n"));
3003 if (rdbSaveBackground(server
.dbfilename
) == REDIS_OK
) {
3004 addReply(c
,shared
.ok
);
3006 addReply(c
,shared
.err
);
3010 static void shutdownCommand(redisClient
*c
) {
3011 redisLog(REDIS_WARNING
,"User requested shutdown, saving DB...");
3012 /* Kill the saving child if there is a background saving in progress.
3013 We want to avoid race conditions, for instance our saving child may
3014 overwrite the synchronous saving did by SHUTDOWN. */
3015 if (server
.bgsaveinprogress
) {
3016 redisLog(REDIS_WARNING
,"There is a live saving child. Killing it!");
3017 kill(server
.bgsavechildpid
,SIGKILL
);
3018 rdbRemoveTempFile(server
.bgsavechildpid
);
3021 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
3022 if (server
.daemonize
)
3023 unlink(server
.pidfile
);
3024 redisLog(REDIS_WARNING
,"%zu bytes used at exit",zmalloc_used_memory());
3025 redisLog(REDIS_WARNING
,"Server exit now, bye bye...");
3028 /* Ooops.. error saving! The best we can do is to continue operating.
3029 * Note that if there was a background saving process, in the next
3030 * cron() Redis will be notified that the background saving aborted,
3031 * handling special stuff like slaves pending for synchronization... */
3032 redisLog(REDIS_WARNING
,"Error trying to save the DB, can't exit");
3033 addReplySds(c
,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
3037 static void renameGenericCommand(redisClient
*c
, int nx
) {
3040 /* To use the same key as src and dst is probably an error */
3041 if (sdscmp(c
->argv
[1]->ptr
,c
->argv
[2]->ptr
) == 0) {
3042 addReply(c
,shared
.sameobjecterr
);
3046 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3048 addReply(c
,shared
.nokeyerr
);
3052 deleteIfVolatile(c
->db
,c
->argv
[2]);
3053 if (dictAdd(c
->db
->dict
,c
->argv
[2],o
) == DICT_ERR
) {
3056 addReply(c
,shared
.czero
);
3059 dictReplace(c
->db
->dict
,c
->argv
[2],o
);
3061 incrRefCount(c
->argv
[2]);
3063 deleteKey(c
->db
,c
->argv
[1]);
3065 addReply(c
,nx
? shared
.cone
: shared
.ok
);
3068 static void renameCommand(redisClient
*c
) {
3069 renameGenericCommand(c
,0);
3072 static void renamenxCommand(redisClient
*c
) {
3073 renameGenericCommand(c
,1);
3076 static void moveCommand(redisClient
*c
) {
3081 /* Obtain source and target DB pointers */
3084 if (selectDb(c
,atoi(c
->argv
[2]->ptr
)) == REDIS_ERR
) {
3085 addReply(c
,shared
.outofrangeerr
);
3089 selectDb(c
,srcid
); /* Back to the source DB */
3091 /* If the user is moving using as target the same
3092 * DB as the source DB it is probably an error. */
3094 addReply(c
,shared
.sameobjecterr
);
3098 /* Check if the element exists and get a reference */
3099 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3101 addReply(c
,shared
.czero
);
3105 /* Try to add the element to the target DB */
3106 deleteIfVolatile(dst
,c
->argv
[1]);
3107 if (dictAdd(dst
->dict
,c
->argv
[1],o
) == DICT_ERR
) {
3108 addReply(c
,shared
.czero
);
3111 incrRefCount(c
->argv
[1]);
3114 /* OK! key moved, free the entry in the source DB */
3115 deleteKey(src
,c
->argv
[1]);
3117 addReply(c
,shared
.cone
);
3120 /* =================================== Lists ================================ */
3121 static void pushGenericCommand(redisClient
*c
, int where
) {
3125 lobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3127 lobj
= createListObject();
3129 if (where
== REDIS_HEAD
) {
3130 listAddNodeHead(list
,c
->argv
[2]);
3132 listAddNodeTail(list
,c
->argv
[2]);
3134 dictAdd(c
->db
->dict
,c
->argv
[1],lobj
);
3135 incrRefCount(c
->argv
[1]);
3136 incrRefCount(c
->argv
[2]);
3138 if (lobj
->type
!= REDIS_LIST
) {
3139 addReply(c
,shared
.wrongtypeerr
);
3143 if (where
== REDIS_HEAD
) {
3144 listAddNodeHead(list
,c
->argv
[2]);
3146 listAddNodeTail(list
,c
->argv
[2]);
3148 incrRefCount(c
->argv
[2]);
3151 addReply(c
,shared
.ok
);
3154 static void lpushCommand(redisClient
*c
) {
3155 pushGenericCommand(c
,REDIS_HEAD
);
3158 static void rpushCommand(redisClient
*c
) {
3159 pushGenericCommand(c
,REDIS_TAIL
);
3162 static void llenCommand(redisClient
*c
) {
3166 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3168 addReply(c
,shared
.czero
);
3171 if (o
->type
!= REDIS_LIST
) {
3172 addReply(c
,shared
.wrongtypeerr
);
3175 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",listLength(l
)));
3180 static void lindexCommand(redisClient
*c
) {
3182 int index
= atoi(c
->argv
[2]->ptr
);
3184 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3186 addReply(c
,shared
.nullbulk
);
3188 if (o
->type
!= REDIS_LIST
) {
3189 addReply(c
,shared
.wrongtypeerr
);
3191 list
*list
= o
->ptr
;
3194 ln
= listIndex(list
, index
);
3196 addReply(c
,shared
.nullbulk
);
3198 robj
*ele
= listNodeValue(ln
);
3199 addReplyBulkLen(c
,ele
);
3201 addReply(c
,shared
.crlf
);
3207 static void lsetCommand(redisClient
*c
) {
3209 int index
= atoi(c
->argv
[2]->ptr
);
3211 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3213 addReply(c
,shared
.nokeyerr
);
3215 if (o
->type
!= REDIS_LIST
) {
3216 addReply(c
,shared
.wrongtypeerr
);
3218 list
*list
= o
->ptr
;
3221 ln
= listIndex(list
, index
);
3223 addReply(c
,shared
.outofrangeerr
);
3225 robj
*ele
= listNodeValue(ln
);
3228 listNodeValue(ln
) = c
->argv
[3];
3229 incrRefCount(c
->argv
[3]);
3230 addReply(c
,shared
.ok
);
3237 static void popGenericCommand(redisClient
*c
, int where
) {
3240 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3242 addReply(c
,shared
.nullbulk
);
3244 if (o
->type
!= REDIS_LIST
) {
3245 addReply(c
,shared
.wrongtypeerr
);
3247 list
*list
= o
->ptr
;
3250 if (where
== REDIS_HEAD
)
3251 ln
= listFirst(list
);
3253 ln
= listLast(list
);
3256 addReply(c
,shared
.nullbulk
);
3258 robj
*ele
= listNodeValue(ln
);
3259 addReplyBulkLen(c
,ele
);
3261 addReply(c
,shared
.crlf
);
3262 listDelNode(list
,ln
);
3269 static void lpopCommand(redisClient
*c
) {
3270 popGenericCommand(c
,REDIS_HEAD
);
3273 static void rpopCommand(redisClient
*c
) {
3274 popGenericCommand(c
,REDIS_TAIL
);
3277 static void lrangeCommand(redisClient
*c
) {
3279 int start
= atoi(c
->argv
[2]->ptr
);
3280 int end
= atoi(c
->argv
[3]->ptr
);
3282 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3284 addReply(c
,shared
.nullmultibulk
);
3286 if (o
->type
!= REDIS_LIST
) {
3287 addReply(c
,shared
.wrongtypeerr
);
3289 list
*list
= o
->ptr
;
3291 int llen
= listLength(list
);
3295 /* convert negative indexes */
3296 if (start
< 0) start
= llen
+start
;
3297 if (end
< 0) end
= llen
+end
;
3298 if (start
< 0) start
= 0;
3299 if (end
< 0) end
= 0;
3301 /* indexes sanity checks */
3302 if (start
> end
|| start
>= llen
) {
3303 /* Out of range start or start > end result in empty list */
3304 addReply(c
,shared
.emptymultibulk
);
3307 if (end
>= llen
) end
= llen
-1;
3308 rangelen
= (end
-start
)+1;
3310 /* Return the result in form of a multi-bulk reply */
3311 ln
= listIndex(list
, start
);
3312 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",rangelen
));
3313 for (j
= 0; j
< rangelen
; j
++) {
3314 ele
= listNodeValue(ln
);
3315 addReplyBulkLen(c
,ele
);
3317 addReply(c
,shared
.crlf
);
3324 static void ltrimCommand(redisClient
*c
) {
3326 int start
= atoi(c
->argv
[2]->ptr
);
3327 int end
= atoi(c
->argv
[3]->ptr
);
3329 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3331 addReply(c
,shared
.nokeyerr
);
3333 if (o
->type
!= REDIS_LIST
) {
3334 addReply(c
,shared
.wrongtypeerr
);
3336 list
*list
= o
->ptr
;
3338 int llen
= listLength(list
);
3339 int j
, ltrim
, rtrim
;
3341 /* convert negative indexes */
3342 if (start
< 0) start
= llen
+start
;
3343 if (end
< 0) end
= llen
+end
;
3344 if (start
< 0) start
= 0;
3345 if (end
< 0) end
= 0;
3347 /* indexes sanity checks */
3348 if (start
> end
|| start
>= llen
) {
3349 /* Out of range start or start > end result in empty list */
3353 if (end
>= llen
) end
= llen
-1;
3358 /* Remove list elements to perform the trim */
3359 for (j
= 0; j
< ltrim
; j
++) {
3360 ln
= listFirst(list
);
3361 listDelNode(list
,ln
);
3363 for (j
= 0; j
< rtrim
; j
++) {
3364 ln
= listLast(list
);
3365 listDelNode(list
,ln
);
3368 addReply(c
,shared
.ok
);
3373 static void lremCommand(redisClient
*c
) {
3376 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3378 addReply(c
,shared
.czero
);
3380 if (o
->type
!= REDIS_LIST
) {
3381 addReply(c
,shared
.wrongtypeerr
);
3383 list
*list
= o
->ptr
;
3384 listNode
*ln
, *next
;
3385 int toremove
= atoi(c
->argv
[2]->ptr
);
3390 toremove
= -toremove
;
3393 ln
= fromtail
? list
->tail
: list
->head
;
3395 robj
*ele
= listNodeValue(ln
);
3397 next
= fromtail
? ln
->prev
: ln
->next
;
3398 if (compareStringObjects(ele
,c
->argv
[3]) == 0) {
3399 listDelNode(list
,ln
);
3402 if (toremove
&& removed
== toremove
) break;
3406 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",removed
));
3411 /* ==================================== Sets ================================ */
3413 static void saddCommand(redisClient
*c
) {
3416 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3418 set
= createSetObject();
3419 dictAdd(c
->db
->dict
,c
->argv
[1],set
);
3420 incrRefCount(c
->argv
[1]);
3422 if (set
->type
!= REDIS_SET
) {
3423 addReply(c
,shared
.wrongtypeerr
);
3427 if (dictAdd(set
->ptr
,c
->argv
[2],NULL
) == DICT_OK
) {
3428 incrRefCount(c
->argv
[2]);
3430 addReply(c
,shared
.cone
);
3432 addReply(c
,shared
.czero
);
3436 static void sremCommand(redisClient
*c
) {
3439 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3441 addReply(c
,shared
.czero
);
3443 if (set
->type
!= REDIS_SET
) {
3444 addReply(c
,shared
.wrongtypeerr
);
3447 if (dictDelete(set
->ptr
,c
->argv
[2]) == DICT_OK
) {
3449 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
3450 addReply(c
,shared
.cone
);
3452 addReply(c
,shared
.czero
);
3457 static void smoveCommand(redisClient
*c
) {
3458 robj
*srcset
, *dstset
;
3460 srcset
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3461 dstset
= lookupKeyWrite(c
->db
,c
->argv
[2]);
3463 /* If the source key does not exist return 0, if it's of the wrong type
3465 if (srcset
== NULL
|| srcset
->type
!= REDIS_SET
) {
3466 addReply(c
, srcset
? shared
.wrongtypeerr
: shared
.czero
);
3469 /* Error if the destination key is not a set as well */
3470 if (dstset
&& dstset
->type
!= REDIS_SET
) {
3471 addReply(c
,shared
.wrongtypeerr
);
3474 /* Remove the element from the source set */
3475 if (dictDelete(srcset
->ptr
,c
->argv
[3]) == DICT_ERR
) {
3476 /* Key not found in the src set! return zero */
3477 addReply(c
,shared
.czero
);
3481 /* Add the element to the destination set */
3483 dstset
= createSetObject();
3484 dictAdd(c
->db
->dict
,c
->argv
[2],dstset
);
3485 incrRefCount(c
->argv
[2]);
3487 if (dictAdd(dstset
->ptr
,c
->argv
[3],NULL
) == DICT_OK
)
3488 incrRefCount(c
->argv
[3]);
3489 addReply(c
,shared
.cone
);
3492 static void sismemberCommand(redisClient
*c
) {
3495 set
= lookupKeyRead(c
->db
,c
->argv
[1]);
3497 addReply(c
,shared
.czero
);
3499 if (set
->type
!= REDIS_SET
) {
3500 addReply(c
,shared
.wrongtypeerr
);
3503 if (dictFind(set
->ptr
,c
->argv
[2]))
3504 addReply(c
,shared
.cone
);
3506 addReply(c
,shared
.czero
);
3510 static void scardCommand(redisClient
*c
) {
3514 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3516 addReply(c
,shared
.czero
);
3519 if (o
->type
!= REDIS_SET
) {
3520 addReply(c
,shared
.wrongtypeerr
);
3523 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3529 static void spopCommand(redisClient
*c
) {
3533 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3535 addReply(c
,shared
.nullbulk
);
3537 if (set
->type
!= REDIS_SET
) {
3538 addReply(c
,shared
.wrongtypeerr
);
3541 de
= dictGetRandomKey(set
->ptr
);
3543 addReply(c
,shared
.nullbulk
);
3545 robj
*ele
= dictGetEntryKey(de
);
3547 addReplyBulkLen(c
,ele
);
3549 addReply(c
,shared
.crlf
);
3550 dictDelete(set
->ptr
,ele
);
3551 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
3557 static void srandmemberCommand(redisClient
*c
) {
3561 set
= lookupKeyRead(c
->db
,c
->argv
[1]);
3563 addReply(c
,shared
.nullbulk
);
3565 if (set
->type
!= REDIS_SET
) {
3566 addReply(c
,shared
.wrongtypeerr
);
3569 de
= dictGetRandomKey(set
->ptr
);
3571 addReply(c
,shared
.nullbulk
);
3573 robj
*ele
= dictGetEntryKey(de
);
3575 addReplyBulkLen(c
,ele
);
3577 addReply(c
,shared
.crlf
);
3582 static int qsortCompareSetsByCardinality(const void *s1
, const void *s2
) {
3583 dict
**d1
= (void*) s1
, **d2
= (void*) s2
;
3585 return dictSize(*d1
)-dictSize(*d2
);
3588 static void sinterGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
) {
3589 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
3592 robj
*lenobj
= NULL
, *dstset
= NULL
;
3593 int j
, cardinality
= 0;
3595 for (j
= 0; j
< setsnum
; j
++) {
3599 lookupKeyWrite(c
->db
,setskeys
[j
]) :
3600 lookupKeyRead(c
->db
,setskeys
[j
]);
3604 deleteKey(c
->db
,dstkey
);
3605 addReply(c
,shared
.ok
);
3607 addReply(c
,shared
.nullmultibulk
);
3611 if (setobj
->type
!= REDIS_SET
) {
3613 addReply(c
,shared
.wrongtypeerr
);
3616 dv
[j
] = setobj
->ptr
;
3618 /* Sort sets from the smallest to largest, this will improve our
3619 * algorithm's performace */
3620 qsort(dv
,setsnum
,sizeof(dict
*),qsortCompareSetsByCardinality
);
3622 /* The first thing we should output is the total number of elements...
3623 * since this is a multi-bulk write, but at this stage we don't know
3624 * the intersection set size, so we use a trick, append an empty object
3625 * to the output list and save the pointer to later modify it with the
3628 lenobj
= createObject(REDIS_STRING
,NULL
);
3630 decrRefCount(lenobj
);
3632 /* If we have a target key where to store the resulting set
3633 * create this key with an empty set inside */
3634 dstset
= createSetObject();
3637 /* Iterate all the elements of the first (smallest) set, and test
3638 * the element against all the other sets, if at least one set does
3639 * not include the element it is discarded */
3640 di
= dictGetIterator(dv
[0]);
3642 while((de
= dictNext(di
)) != NULL
) {
3645 for (j
= 1; j
< setsnum
; j
++)
3646 if (dictFind(dv
[j
],dictGetEntryKey(de
)) == NULL
) break;
3648 continue; /* at least one set does not contain the member */
3649 ele
= dictGetEntryKey(de
);
3651 addReplyBulkLen(c
,ele
);
3653 addReply(c
,shared
.crlf
);
3656 dictAdd(dstset
->ptr
,ele
,NULL
);
3660 dictReleaseIterator(di
);
3663 /* Store the resulting set into the target */
3664 deleteKey(c
->db
,dstkey
);
3665 dictAdd(c
->db
->dict
,dstkey
,dstset
);
3666 incrRefCount(dstkey
);
3670 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%d\r\n",cardinality
);
3672 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3673 dictSize((dict
*)dstset
->ptr
)));
3679 static void sinterCommand(redisClient
*c
) {
3680 sinterGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
);
3683 static void sinterstoreCommand(redisClient
*c
) {
3684 sinterGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1]);
3687 #define REDIS_OP_UNION 0
3688 #define REDIS_OP_DIFF 1
3690 static void sunionDiffGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
, int op
) {
3691 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
3694 robj
*dstset
= NULL
;
3695 int j
, cardinality
= 0;
3697 for (j
= 0; j
< setsnum
; j
++) {
3701 lookupKeyWrite(c
->db
,setskeys
[j
]) :
3702 lookupKeyRead(c
->db
,setskeys
[j
]);
3707 if (setobj
->type
!= REDIS_SET
) {
3709 addReply(c
,shared
.wrongtypeerr
);
3712 dv
[j
] = setobj
->ptr
;
3715 /* We need a temp set object to store our union. If the dstkey
3716 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
3717 * this set object will be the resulting object to set into the target key*/
3718 dstset
= createSetObject();
3720 /* Iterate all the elements of all the sets, add every element a single
3721 * time to the result set */
3722 for (j
= 0; j
< setsnum
; j
++) {
3723 if (op
== REDIS_OP_DIFF
&& j
== 0 && !dv
[j
]) break; /* result set is empty */
3724 if (!dv
[j
]) continue; /* non existing keys are like empty sets */
3726 di
= dictGetIterator(dv
[j
]);
3728 while((de
= dictNext(di
)) != NULL
) {
3731 /* dictAdd will not add the same element multiple times */
3732 ele
= dictGetEntryKey(de
);
3733 if (op
== REDIS_OP_UNION
|| j
== 0) {
3734 if (dictAdd(dstset
->ptr
,ele
,NULL
) == DICT_OK
) {
3738 } else if (op
== REDIS_OP_DIFF
) {
3739 if (dictDelete(dstset
->ptr
,ele
) == DICT_OK
) {
3744 dictReleaseIterator(di
);
3746 if (op
== REDIS_OP_DIFF
&& cardinality
== 0) break; /* result set is empty */
3749 /* Output the content of the resulting set, if not in STORE mode */
3751 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",cardinality
));
3752 di
= dictGetIterator(dstset
->ptr
);
3753 while((de
= dictNext(di
)) != NULL
) {
3756 ele
= dictGetEntryKey(de
);
3757 addReplyBulkLen(c
,ele
);
3759 addReply(c
,shared
.crlf
);
3761 dictReleaseIterator(di
);
3763 /* If we have a target key where to store the resulting set
3764 * create this key with the result set inside */
3765 deleteKey(c
->db
,dstkey
);
3766 dictAdd(c
->db
->dict
,dstkey
,dstset
);
3767 incrRefCount(dstkey
);
3772 decrRefCount(dstset
);
3774 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3775 dictSize((dict
*)dstset
->ptr
)));
3781 static void sunionCommand(redisClient
*c
) {
3782 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_UNION
);
3785 static void sunionstoreCommand(redisClient
*c
) {
3786 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_UNION
);
3789 static void sdiffCommand(redisClient
*c
) {
3790 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_DIFF
);
3793 static void sdiffstoreCommand(redisClient
*c
) {
3794 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_DIFF
);
3797 /* ==================================== ZSets =============================== */
3799 /* ZSETs are ordered sets using two data structures to hold the same elements
3800 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
3803 * The elements are added to an hash table mapping Redis objects to scores.
3804 * At the same time the elements are added to a skip list mapping scores
3805 * to Redis objects (so objects are sorted by scores in this "view"). */
3807 /* This skiplist implementation is almost a C translation of the original
3808 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
3809 * Alternative to Balanced Trees", modified in three ways:
3810 * a) this implementation allows for repeated values.
3811 * b) the comparison is not just by key (our 'score') but by satellite data.
3812 * c) there is a back pointer, so it's a doubly linked list with the back
3813 * pointers being only at "level 1". This allows to traverse the list
3814 * from tail to head, useful for ZREVRANGE. */
3816 static zskiplistNode
*zslCreateNode(int level
, double score
, robj
*obj
) {
3817 zskiplistNode
*zn
= zmalloc(sizeof(*zn
));
3819 zn
->forward
= zmalloc(sizeof(zskiplistNode
*) * level
);
3825 static zskiplist
*zslCreate(void) {
3829 zsl
= zmalloc(sizeof(*zsl
));
3832 zsl
->header
= zslCreateNode(ZSKIPLIST_MAXLEVEL
,0,NULL
);
3833 for (j
= 0; j
< ZSKIPLIST_MAXLEVEL
; j
++)
3834 zsl
->header
->forward
[j
] = NULL
;
3835 zsl
->header
->backward
= NULL
;
3840 static void zslFreeNode(zskiplistNode
*node
) {
3841 decrRefCount(node
->obj
);
3842 zfree(node
->forward
);
3846 static void zslFree(zskiplist
*zsl
) {
3847 zskiplistNode
*node
= zsl
->header
->forward
[0], *next
;
3849 zfree(zsl
->header
->forward
);
3852 next
= node
->forward
[0];
3859 static int zslRandomLevel(void) {
3861 while ((random()&0xFFFF) < (ZSKIPLIST_P
* 0xFFFF))
3866 static void zslInsert(zskiplist
*zsl
, double score
, robj
*obj
) {
3867 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
3871 for (i
= zsl
->level
-1; i
>= 0; i
--) {
3872 while (x
->forward
[i
] &&
3873 (x
->forward
[i
]->score
< score
||
3874 (x
->forward
[i
]->score
== score
&&
3875 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0)))
3879 /* we assume the key is not already inside, since we allow duplicated
3880 * scores, and the re-insertion of score and redis object should never
3881 * happpen since the caller of zslInsert() should test in the hash table
3882 * if the element is already inside or not. */
3883 level
= zslRandomLevel();
3884 if (level
> zsl
->level
) {
3885 for (i
= zsl
->level
; i
< level
; i
++)
3886 update
[i
] = zsl
->header
;
3889 x
= zslCreateNode(level
,score
,obj
);
3890 for (i
= 0; i
< level
; i
++) {
3891 x
->forward
[i
] = update
[i
]->forward
[i
];
3892 update
[i
]->forward
[i
] = x
;
3894 x
->backward
= (update
[0] == zsl
->header
) ? NULL
: update
[0];
3896 x
->forward
[0]->backward
= x
;
3902 /* Delete an element with matching score/object from the skiplist. */
3903 static int zslDelete(zskiplist
*zsl
, double score
, robj
*obj
) {
3904 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
3908 for (i
= zsl
->level
-1; i
>= 0; i
--) {
3909 while (x
->forward
[i
] &&
3910 (x
->forward
[i
]->score
< score
||
3911 (x
->forward
[i
]->score
== score
&&
3912 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0)))
3916 /* We may have multiple elements with the same score, what we need
3917 * is to find the element with both the right score and object. */
3919 if (x
&& score
== x
->score
&& compareStringObjects(x
->obj
,obj
) == 0) {
3920 for (i
= 0; i
< zsl
->level
; i
++) {
3921 if (update
[i
]->forward
[i
] != x
) break;
3922 update
[i
]->forward
[i
] = x
->forward
[i
];
3924 if (x
->forward
[0]) {
3925 x
->forward
[0]->backward
= (x
->backward
== zsl
->header
) ?
3928 zsl
->tail
= x
->backward
;
3931 while(zsl
->level
> 1 && zsl
->header
->forward
[zsl
->level
-1] == NULL
)
3936 return 0; /* not found */
3938 return 0; /* not found */
3941 /* Find the first node having a score equal or greater than the specified one.
3942 * Returns NULL if there is no match. */
3943 static zskiplistNode
*zslFirstWithScore(zskiplist
*zsl
, double score
) {
3948 for (i
= zsl
->level
-1; i
>= 0; i
--) {
3949 while (x
->forward
[i
] && x
->forward
[i
]->score
< score
)
3952 /* We may have multiple elements with the same score, what we need
3953 * is to find the element with both the right score and object. */
3954 return x
->forward
[0];
3957 /* The actual Z-commands implementations */
3959 static void zaddCommand(redisClient
*c
) {
3964 zsetobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3965 if (zsetobj
== NULL
) {
3966 zsetobj
= createZsetObject();
3967 dictAdd(c
->db
->dict
,c
->argv
[1],zsetobj
);
3968 incrRefCount(c
->argv
[1]);
3970 if (zsetobj
->type
!= REDIS_ZSET
) {
3971 addReply(c
,shared
.wrongtypeerr
);
3975 score
= zmalloc(sizeof(double));
3976 *score
= strtod(c
->argv
[2]->ptr
,NULL
);
3978 if (dictAdd(zs
->dict
,c
->argv
[3],score
) == DICT_OK
) {
3979 /* case 1: New element */
3980 incrRefCount(c
->argv
[3]); /* added to hash */
3981 zslInsert(zs
->zsl
,*score
,c
->argv
[3]);
3982 incrRefCount(c
->argv
[3]); /* added to skiplist */
3984 addReply(c
,shared
.cone
);
3989 /* case 2: Score update operation */
3990 de
= dictFind(zs
->dict
,c
->argv
[3]);
3992 oldscore
= dictGetEntryVal(de
);
3993 if (*score
!= *oldscore
) {
3996 deleted
= zslDelete(zs
->zsl
,*oldscore
,c
->argv
[3]);
3997 assert(deleted
!= 0);
3998 zslInsert(zs
->zsl
,*score
,c
->argv
[3]);
3999 incrRefCount(c
->argv
[3]);
4000 dictReplace(zs
->dict
,c
->argv
[3],score
);
4005 addReply(c
,shared
.czero
);
4009 static void zremCommand(redisClient
*c
) {
4013 zsetobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4014 if (zsetobj
== NULL
) {
4015 addReply(c
,shared
.czero
);
4021 if (zsetobj
->type
!= REDIS_ZSET
) {
4022 addReply(c
,shared
.wrongtypeerr
);
4026 de
= dictFind(zs
->dict
,c
->argv
[2]);
4028 addReply(c
,shared
.czero
);
4031 /* Delete from the skiplist */
4032 oldscore
= dictGetEntryVal(de
);
4033 deleted
= zslDelete(zs
->zsl
,*oldscore
,c
->argv
[2]);
4034 assert(deleted
!= 0);
4036 /* Delete from the hash table */
4037 dictDelete(zs
->dict
,c
->argv
[2]);
4038 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
4040 addReply(c
,shared
.cone
);
4044 static void zrangeGenericCommand(redisClient
*c
, int reverse
) {
4046 int start
= atoi(c
->argv
[2]->ptr
);
4047 int end
= atoi(c
->argv
[3]->ptr
);
4049 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4051 addReply(c
,shared
.nullmultibulk
);
4053 if (o
->type
!= REDIS_ZSET
) {
4054 addReply(c
,shared
.wrongtypeerr
);
4056 zset
*zsetobj
= o
->ptr
;
4057 zskiplist
*zsl
= zsetobj
->zsl
;
4060 int llen
= zsl
->length
;
4064 /* convert negative indexes */
4065 if (start
< 0) start
= llen
+start
;
4066 if (end
< 0) end
= llen
+end
;
4067 if (start
< 0) start
= 0;
4068 if (end
< 0) end
= 0;
4070 /* indexes sanity checks */
4071 if (start
> end
|| start
>= llen
) {
4072 /* Out of range start or start > end result in empty list */
4073 addReply(c
,shared
.emptymultibulk
);
4076 if (end
>= llen
) end
= llen
-1;
4077 rangelen
= (end
-start
)+1;
4079 /* Return the result in form of a multi-bulk reply */
4085 ln
= zsl
->header
->forward
[0];
4087 ln
= ln
->forward
[0];
4090 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",rangelen
));
4091 for (j
= 0; j
< rangelen
; j
++) {
4093 addReplyBulkLen(c
,ele
);
4095 addReply(c
,shared
.crlf
);
4096 ln
= reverse
? ln
->backward
: ln
->forward
[0];
4102 static void zrangeCommand(redisClient
*c
) {
4103 zrangeGenericCommand(c
,0);
4106 static void zrevrangeCommand(redisClient
*c
) {
4107 zrangeGenericCommand(c
,1);
4110 static void zrangebyscoreCommand(redisClient
*c
) {
4112 double min
= strtod(c
->argv
[2]->ptr
,NULL
);
4113 double max
= strtod(c
->argv
[3]->ptr
,NULL
);
4115 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4117 addReply(c
,shared
.nullmultibulk
);
4119 if (o
->type
!= REDIS_ZSET
) {
4120 addReply(c
,shared
.wrongtypeerr
);
4122 zset
*zsetobj
= o
->ptr
;
4123 zskiplist
*zsl
= zsetobj
->zsl
;
4126 unsigned int rangelen
= 0;
4128 /* Get the first node with the score >= min */
4129 ln
= zslFirstWithScore(zsl
,min
);
4131 /* No element matching the speciifed interval */
4132 addReply(c
,shared
.emptymultibulk
);
4136 /* We don't know in advance how many matching elements there
4137 * are in the list, so we push this object that will represent
4138 * the multi-bulk length in the output buffer, and will "fix"
4140 lenobj
= createObject(REDIS_STRING
,NULL
);
4143 while(ln
&& ln
->score
<= max
) {
4145 addReplyBulkLen(c
,ele
);
4147 addReply(c
,shared
.crlf
);
4148 ln
= ln
->forward
[0];
4151 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%d\r\n",rangelen
);
4156 static void zlenCommand(redisClient
*c
) {
4160 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4162 addReply(c
,shared
.czero
);
4165 if (o
->type
!= REDIS_ZSET
) {
4166 addReply(c
,shared
.wrongtypeerr
);
4169 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",zs
->zsl
->length
));
4174 static void zscoreCommand(redisClient
*c
) {
4178 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4180 addReply(c
,shared
.czero
);
4183 if (o
->type
!= REDIS_ZSET
) {
4184 addReply(c
,shared
.wrongtypeerr
);
4189 de
= dictFind(zs
->dict
,c
->argv
[2]);
4191 addReply(c
,shared
.nullbulk
);
4194 double *score
= dictGetEntryVal(de
);
4196 snprintf(buf
,sizeof(buf
),"%.16g",*score
);
4197 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n%s\r\n",
4204 /* ========================= Non type-specific commands ==================== */
4206 static void flushdbCommand(redisClient
*c
) {
4207 server
.dirty
+= dictSize(c
->db
->dict
);
4208 dictEmpty(c
->db
->dict
);
4209 dictEmpty(c
->db
->expires
);
4210 addReply(c
,shared
.ok
);
4213 static void flushallCommand(redisClient
*c
) {
4214 server
.dirty
+= emptyDb();
4215 addReply(c
,shared
.ok
);
4216 rdbSave(server
.dbfilename
);
4220 static redisSortOperation
*createSortOperation(int type
, robj
*pattern
) {
4221 redisSortOperation
*so
= zmalloc(sizeof(*so
));
4223 so
->pattern
= pattern
;
4227 /* Return the value associated to the key with a name obtained
4228 * substituting the first occurence of '*' in 'pattern' with 'subst' */
4229 static robj
*lookupKeyByPattern(redisDb
*db
, robj
*pattern
, robj
*subst
) {
4233 int prefixlen
, sublen
, postfixlen
;
4234 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
4238 char buf
[REDIS_SORTKEY_MAX
+1];
4241 if (subst
->encoding
== REDIS_ENCODING_RAW
)
4242 incrRefCount(subst
);
4244 subst
= getDecodedObject(subst
);
4247 spat
= pattern
->ptr
;
4249 if (sdslen(spat
)+sdslen(ssub
)-1 > REDIS_SORTKEY_MAX
) return NULL
;
4250 p
= strchr(spat
,'*');
4251 if (!p
) return NULL
;
4254 sublen
= sdslen(ssub
);
4255 postfixlen
= sdslen(spat
)-(prefixlen
+1);
4256 memcpy(keyname
.buf
,spat
,prefixlen
);
4257 memcpy(keyname
.buf
+prefixlen
,ssub
,sublen
);
4258 memcpy(keyname
.buf
+prefixlen
+sublen
,p
+1,postfixlen
);
4259 keyname
.buf
[prefixlen
+sublen
+postfixlen
] = '\0';
4260 keyname
.len
= prefixlen
+sublen
+postfixlen
;
4262 keyobj
.refcount
= 1;
4263 keyobj
.type
= REDIS_STRING
;
4264 keyobj
.ptr
= ((char*)&keyname
)+(sizeof(long)*2);
4266 decrRefCount(subst
);
4268 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
4269 return lookupKeyRead(db
,&keyobj
);
4272 /* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
4273 * the additional parameter is not standard but a BSD-specific we have to
4274 * pass sorting parameters via the global 'server' structure */
4275 static int sortCompare(const void *s1
, const void *s2
) {
4276 const redisSortObject
*so1
= s1
, *so2
= s2
;
4279 if (!server
.sort_alpha
) {
4280 /* Numeric sorting. Here it's trivial as we precomputed scores */
4281 if (so1
->u
.score
> so2
->u
.score
) {
4283 } else if (so1
->u
.score
< so2
->u
.score
) {
4289 /* Alphanumeric sorting */
4290 if (server
.sort_bypattern
) {
4291 if (!so1
->u
.cmpobj
|| !so2
->u
.cmpobj
) {
4292 /* At least one compare object is NULL */
4293 if (so1
->u
.cmpobj
== so2
->u
.cmpobj
)
4295 else if (so1
->u
.cmpobj
== NULL
)
4300 /* We have both the objects, use strcoll */
4301 cmp
= strcoll(so1
->u
.cmpobj
->ptr
,so2
->u
.cmpobj
->ptr
);
4304 /* Compare elements directly */
4305 if (so1
->obj
->encoding
== REDIS_ENCODING_RAW
&&
4306 so2
->obj
->encoding
== REDIS_ENCODING_RAW
) {
4307 cmp
= strcoll(so1
->obj
->ptr
,so2
->obj
->ptr
);
4311 dec1
= so1
->obj
->encoding
== REDIS_ENCODING_RAW
?
4312 so1
->obj
: getDecodedObject(so1
->obj
);
4313 dec2
= so2
->obj
->encoding
== REDIS_ENCODING_RAW
?
4314 so2
->obj
: getDecodedObject(so2
->obj
);
4315 cmp
= strcoll(dec1
->ptr
,dec2
->ptr
);
4316 if (dec1
!= so1
->obj
) decrRefCount(dec1
);
4317 if (dec2
!= so2
->obj
) decrRefCount(dec2
);
4321 return server
.sort_desc
? -cmp
: cmp
;
4324 /* The SORT command is the most complex command in Redis. Warning: this code
4325 * is optimized for speed and a bit less for readability */
4326 static void sortCommand(redisClient
*c
) {
4329 int desc
= 0, alpha
= 0;
4330 int limit_start
= 0, limit_count
= -1, start
, end
;
4331 int j
, dontsort
= 0, vectorlen
;
4332 int getop
= 0; /* GET operation counter */
4333 robj
*sortval
, *sortby
= NULL
;
4334 redisSortObject
*vector
; /* Resulting vector to sort */
4336 /* Lookup the key to sort. It must be of the right types */
4337 sortval
= lookupKeyRead(c
->db
,c
->argv
[1]);
4338 if (sortval
== NULL
) {
4339 addReply(c
,shared
.nokeyerr
);
4342 if (sortval
->type
!= REDIS_SET
&& sortval
->type
!= REDIS_LIST
) {
4343 addReply(c
,shared
.wrongtypeerr
);
4347 /* Create a list of operations to perform for every sorted element.
4348 * Operations can be GET/DEL/INCR/DECR */
4349 operations
= listCreate();
4350 listSetFreeMethod(operations
,zfree
);
4353 /* Now we need to protect sortval incrementing its count, in the future
4354 * SORT may have options able to overwrite/delete keys during the sorting
4355 * and the sorted key itself may get destroied */
4356 incrRefCount(sortval
);
4358 /* The SORT command has an SQL-alike syntax, parse it */
4359 while(j
< c
->argc
) {
4360 int leftargs
= c
->argc
-j
-1;
4361 if (!strcasecmp(c
->argv
[j
]->ptr
,"asc")) {
4363 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"desc")) {
4365 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"alpha")) {
4367 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"limit") && leftargs
>= 2) {
4368 limit_start
= atoi(c
->argv
[j
+1]->ptr
);
4369 limit_count
= atoi(c
->argv
[j
+2]->ptr
);
4371 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"by") && leftargs
>= 1) {
4372 sortby
= c
->argv
[j
+1];
4373 /* If the BY pattern does not contain '*', i.e. it is constant,
4374 * we don't need to sort nor to lookup the weight keys. */
4375 if (strchr(c
->argv
[j
+1]->ptr
,'*') == NULL
) dontsort
= 1;
4377 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
4378 listAddNodeTail(operations
,createSortOperation(
4379 REDIS_SORT_GET
,c
->argv
[j
+1]));
4382 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"del") && leftargs
>= 1) {
4383 listAddNodeTail(operations
,createSortOperation(
4384 REDIS_SORT_DEL
,c
->argv
[j
+1]));
4386 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"incr") && leftargs
>= 1) {
4387 listAddNodeTail(operations
,createSortOperation(
4388 REDIS_SORT_INCR
,c
->argv
[j
+1]));
4390 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
4391 listAddNodeTail(operations
,createSortOperation(
4392 REDIS_SORT_DECR
,c
->argv
[j
+1]));
4395 decrRefCount(sortval
);
4396 listRelease(operations
);
4397 addReply(c
,shared
.syntaxerr
);
4403 /* Load the sorting vector with all the objects to sort */
4404 vectorlen
= (sortval
->type
== REDIS_LIST
) ?
4405 listLength((list
*)sortval
->ptr
) :
4406 dictSize((dict
*)sortval
->ptr
);
4407 vector
= zmalloc(sizeof(redisSortObject
)*vectorlen
);
4409 if (sortval
->type
== REDIS_LIST
) {
4410 list
*list
= sortval
->ptr
;
4414 while((ln
= listYield(list
))) {
4415 robj
*ele
= ln
->value
;
4416 vector
[j
].obj
= ele
;
4417 vector
[j
].u
.score
= 0;
4418 vector
[j
].u
.cmpobj
= NULL
;
4422 dict
*set
= sortval
->ptr
;
4426 di
= dictGetIterator(set
);
4427 while((setele
= dictNext(di
)) != NULL
) {
4428 vector
[j
].obj
= dictGetEntryKey(setele
);
4429 vector
[j
].u
.score
= 0;
4430 vector
[j
].u
.cmpobj
= NULL
;
4433 dictReleaseIterator(di
);
4435 assert(j
== vectorlen
);
4437 /* Now it's time to load the right scores in the sorting vector */
4438 if (dontsort
== 0) {
4439 for (j
= 0; j
< vectorlen
; j
++) {
4443 byval
= lookupKeyByPattern(c
->db
,sortby
,vector
[j
].obj
);
4444 if (!byval
|| byval
->type
!= REDIS_STRING
) continue;
4446 if (byval
->encoding
== REDIS_ENCODING_RAW
) {
4447 vector
[j
].u
.cmpobj
= byval
;
4448 incrRefCount(byval
);
4450 vector
[j
].u
.cmpobj
= getDecodedObject(byval
);
4453 if (byval
->encoding
== REDIS_ENCODING_RAW
) {
4454 vector
[j
].u
.score
= strtod(byval
->ptr
,NULL
);
4456 if (byval
->encoding
== REDIS_ENCODING_INT
) {
4457 vector
[j
].u
.score
= (long)byval
->ptr
;
4464 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_RAW
)
4465 vector
[j
].u
.score
= strtod(vector
[j
].obj
->ptr
,NULL
);
4467 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_INT
)
4468 vector
[j
].u
.score
= (long) vector
[j
].obj
->ptr
;
4477 /* We are ready to sort the vector... perform a bit of sanity check
4478 * on the LIMIT option too. We'll use a partial version of quicksort. */
4479 start
= (limit_start
< 0) ? 0 : limit_start
;
4480 end
= (limit_count
< 0) ? vectorlen
-1 : start
+limit_count
-1;
4481 if (start
>= vectorlen
) {
4482 start
= vectorlen
-1;
4485 if (end
>= vectorlen
) end
= vectorlen
-1;
4487 if (dontsort
== 0) {
4488 server
.sort_desc
= desc
;
4489 server
.sort_alpha
= alpha
;
4490 server
.sort_bypattern
= sortby
? 1 : 0;
4491 if (sortby
&& (start
!= 0 || end
!= vectorlen
-1))
4492 pqsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
, start
,end
);
4494 qsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
);
4497 /* Send command output to the output buffer, performing the specified
4498 * GET/DEL/INCR/DECR operations if any. */
4499 outputlen
= getop
? getop
*(end
-start
+1) : end
-start
+1;
4500 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",outputlen
));
4501 for (j
= start
; j
<= end
; j
++) {
4504 addReplyBulkLen(c
,vector
[j
].obj
);
4505 addReply(c
,vector
[j
].obj
);
4506 addReply(c
,shared
.crlf
);
4508 listRewind(operations
);
4509 while((ln
= listYield(operations
))) {
4510 redisSortOperation
*sop
= ln
->value
;
4511 robj
*val
= lookupKeyByPattern(c
->db
,sop
->pattern
,
4514 if (sop
->type
== REDIS_SORT_GET
) {
4515 if (!val
|| val
->type
!= REDIS_STRING
) {
4516 addReply(c
,shared
.nullbulk
);
4518 addReplyBulkLen(c
,val
);
4520 addReply(c
,shared
.crlf
);
4522 } else if (sop
->type
== REDIS_SORT_DEL
) {
4529 decrRefCount(sortval
);
4530 listRelease(operations
);
4531 for (j
= 0; j
< vectorlen
; j
++) {
4532 if (sortby
&& alpha
&& vector
[j
].u
.cmpobj
)
4533 decrRefCount(vector
[j
].u
.cmpobj
);
4538 static void infoCommand(redisClient
*c
) {
4540 time_t uptime
= time(NULL
)-server
.stat_starttime
;
4543 info
= sdscatprintf(sdsempty(),
4544 "redis_version:%s\r\n"
4546 "uptime_in_seconds:%d\r\n"
4547 "uptime_in_days:%d\r\n"
4548 "connected_clients:%d\r\n"
4549 "connected_slaves:%d\r\n"
4550 "used_memory:%zu\r\n"
4551 "changes_since_last_save:%lld\r\n"
4552 "bgsave_in_progress:%d\r\n"
4553 "last_save_time:%d\r\n"
4554 "total_connections_received:%lld\r\n"
4555 "total_commands_processed:%lld\r\n"
4558 (sizeof(long) == 8) ? "64" : "32",
4561 listLength(server
.clients
)-listLength(server
.slaves
),
4562 listLength(server
.slaves
),
4565 server
.bgsaveinprogress
,
4567 server
.stat_numconnections
,
4568 server
.stat_numcommands
,
4569 server
.masterhost
== NULL
? "master" : "slave"
4571 if (server
.masterhost
) {
4572 info
= sdscatprintf(info
,
4573 "master_host:%s\r\n"
4574 "master_port:%d\r\n"
4575 "master_link_status:%s\r\n"
4576 "master_last_io_seconds_ago:%d\r\n"
4579 (server
.replstate
== REDIS_REPL_CONNECTED
) ?
4581 (int)(time(NULL
)-server
.master
->lastinteraction
)
4584 for (j
= 0; j
< server
.dbnum
; j
++) {
4585 long long keys
, vkeys
;
4587 keys
= dictSize(server
.db
[j
].dict
);
4588 vkeys
= dictSize(server
.db
[j
].expires
);
4589 if (keys
|| vkeys
) {
4590 info
= sdscatprintf(info
, "db%d: keys=%lld,expires=%lld\r\n",
4594 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(info
)));
4595 addReplySds(c
,info
);
4596 addReply(c
,shared
.crlf
);
4599 static void monitorCommand(redisClient
*c
) {
4600 /* ignore MONITOR if aleady slave or in monitor mode */
4601 if (c
->flags
& REDIS_SLAVE
) return;
4603 c
->flags
|= (REDIS_SLAVE
|REDIS_MONITOR
);
4605 listAddNodeTail(server
.monitors
,c
);
4606 addReply(c
,shared
.ok
);
4609 /* ================================= Expire ================================= */
4610 static int removeExpire(redisDb
*db
, robj
*key
) {
4611 if (dictDelete(db
->expires
,key
) == DICT_OK
) {
4618 static int setExpire(redisDb
*db
, robj
*key
, time_t when
) {
4619 if (dictAdd(db
->expires
,key
,(void*)when
) == DICT_ERR
) {
4627 /* Return the expire time of the specified key, or -1 if no expire
4628 * is associated with this key (i.e. the key is non volatile) */
4629 static time_t getExpire(redisDb
*db
, robj
*key
) {
4632 /* No expire? return ASAP */
4633 if (dictSize(db
->expires
) == 0 ||
4634 (de
= dictFind(db
->expires
,key
)) == NULL
) return -1;
4636 return (time_t) dictGetEntryVal(de
);
4639 static int expireIfNeeded(redisDb
*db
, robj
*key
) {
4643 /* No expire? return ASAP */
4644 if (dictSize(db
->expires
) == 0 ||
4645 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
4647 /* Lookup the expire */
4648 when
= (time_t) dictGetEntryVal(de
);
4649 if (time(NULL
) <= when
) return 0;
4651 /* Delete the key */
4652 dictDelete(db
->expires
,key
);
4653 return dictDelete(db
->dict
,key
) == DICT_OK
;
4656 static int deleteIfVolatile(redisDb
*db
, robj
*key
) {
4659 /* No expire? return ASAP */
4660 if (dictSize(db
->expires
) == 0 ||
4661 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
4663 /* Delete the key */
4665 dictDelete(db
->expires
,key
);
4666 return dictDelete(db
->dict
,key
) == DICT_OK
;
4669 static void expireCommand(redisClient
*c
) {
4671 int seconds
= atoi(c
->argv
[2]->ptr
);
4673 de
= dictFind(c
->db
->dict
,c
->argv
[1]);
4675 addReply(c
,shared
.czero
);
4679 addReply(c
, shared
.czero
);
4682 time_t when
= time(NULL
)+seconds
;
4683 if (setExpire(c
->db
,c
->argv
[1],when
)) {
4684 addReply(c
,shared
.cone
);
4687 addReply(c
,shared
.czero
);
4693 static void ttlCommand(redisClient
*c
) {
4697 expire
= getExpire(c
->db
,c
->argv
[1]);
4699 ttl
= (int) (expire
-time(NULL
));
4700 if (ttl
< 0) ttl
= -1;
4702 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",ttl
));
4705 static void msetGenericCommand(redisClient
*c
, int nx
) {
4708 if ((c
->argc
% 2) == 0) {
4709 addReplySds(c
,sdsnew("-ERR wrong number of arguments\r\n"));
4712 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
4713 * set nothing at all if at least one already key exists. */
4715 for (j
= 1; j
< c
->argc
; j
+= 2) {
4716 if (dictFind(c
->db
->dict
,c
->argv
[j
]) != NULL
) {
4717 addReply(c
, shared
.czero
);
4723 for (j
= 1; j
< c
->argc
; j
+= 2) {
4726 retval
= dictAdd(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
4727 if (retval
== DICT_ERR
) {
4728 dictReplace(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
4729 incrRefCount(c
->argv
[j
+1]);
4731 incrRefCount(c
->argv
[j
]);
4732 incrRefCount(c
->argv
[j
+1]);
4734 removeExpire(c
->db
,c
->argv
[j
]);
4736 server
.dirty
+= (c
->argc
-1)/2;
4737 addReply(c
, nx
? shared
.cone
: shared
.ok
);
4740 static void msetCommand(redisClient
*c
) {
4741 msetGenericCommand(c
,0);
4744 static void msetnxCommand(redisClient
*c
) {
4745 msetGenericCommand(c
,1);
4748 /* =============================== Replication ============================= */
4750 static int syncWrite(int fd
, char *ptr
, ssize_t size
, int timeout
) {
4751 ssize_t nwritten
, ret
= size
;
4752 time_t start
= time(NULL
);
4756 if (aeWait(fd
,AE_WRITABLE
,1000) & AE_WRITABLE
) {
4757 nwritten
= write(fd
,ptr
,size
);
4758 if (nwritten
== -1) return -1;
4762 if ((time(NULL
)-start
) > timeout
) {
4770 static int syncRead(int fd
, char *ptr
, ssize_t size
, int timeout
) {
4771 ssize_t nread
, totread
= 0;
4772 time_t start
= time(NULL
);
4776 if (aeWait(fd
,AE_READABLE
,1000) & AE_READABLE
) {
4777 nread
= read(fd
,ptr
,size
);
4778 if (nread
== -1) return -1;
4783 if ((time(NULL
)-start
) > timeout
) {
4791 static int syncReadLine(int fd
, char *ptr
, ssize_t size
, int timeout
) {
4798 if (syncRead(fd
,&c
,1,timeout
) == -1) return -1;
4801 if (nread
&& *(ptr
-1) == '\r') *(ptr
-1) = '\0';
4812 static void syncCommand(redisClient
*c
) {
4813 /* ignore SYNC if aleady slave or in monitor mode */
4814 if (c
->flags
& REDIS_SLAVE
) return;
4816 /* SYNC can't be issued when the server has pending data to send to
4817 * the client about already issued commands. We need a fresh reply
4818 * buffer registering the differences between the BGSAVE and the current
4819 * dataset, so that we can copy to other slaves if needed. */
4820 if (listLength(c
->reply
) != 0) {
4821 addReplySds(c
,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
4825 redisLog(REDIS_NOTICE
,"Slave ask for synchronization");
4826 /* Here we need to check if there is a background saving operation
4827 * in progress, or if it is required to start one */
4828 if (server
.bgsaveinprogress
) {
4829 /* Ok a background save is in progress. Let's check if it is a good
4830 * one for replication, i.e. if there is another slave that is
4831 * registering differences since the server forked to save */
4835 listRewind(server
.slaves
);
4836 while((ln
= listYield(server
.slaves
))) {
4838 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) break;
4841 /* Perfect, the server is already registering differences for
4842 * another slave. Set the right state, and copy the buffer. */
4843 listRelease(c
->reply
);
4844 c
->reply
= listDup(slave
->reply
);
4845 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
4846 redisLog(REDIS_NOTICE
,"Waiting for end of BGSAVE for SYNC");
4848 /* No way, we need to wait for the next BGSAVE in order to
4849 * register differences */
4850 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
4851 redisLog(REDIS_NOTICE
,"Waiting for next BGSAVE for SYNC");
4854 /* Ok we don't have a BGSAVE in progress, let's start one */
4855 redisLog(REDIS_NOTICE
,"Starting BGSAVE for SYNC");
4856 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
4857 redisLog(REDIS_NOTICE
,"Replication failed, can't BGSAVE");
4858 addReplySds(c
,sdsnew("-ERR Unalbe to perform background save\r\n"));
4861 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
4864 c
->flags
|= REDIS_SLAVE
;
4866 listAddNodeTail(server
.slaves
,c
);
4870 static void sendBulkToSlave(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
4871 redisClient
*slave
= privdata
;
4873 REDIS_NOTUSED(mask
);
4874 char buf
[REDIS_IOBUF_LEN
];
4875 ssize_t nwritten
, buflen
;
4877 if (slave
->repldboff
== 0) {
4878 /* Write the bulk write count before to transfer the DB. In theory here
4879 * we don't know how much room there is in the output buffer of the
4880 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
4881 * operations) will never be smaller than the few bytes we need. */
4884 bulkcount
= sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
4886 if (write(fd
,bulkcount
,sdslen(bulkcount
)) != (signed)sdslen(bulkcount
))
4894 lseek(slave
->repldbfd
,slave
->repldboff
,SEEK_SET
);
4895 buflen
= read(slave
->repldbfd
,buf
,REDIS_IOBUF_LEN
);
4897 redisLog(REDIS_WARNING
,"Read error sending DB to slave: %s",
4898 (buflen
== 0) ? "premature EOF" : strerror(errno
));
4902 if ((nwritten
= write(fd
,buf
,buflen
)) == -1) {
4903 redisLog(REDIS_DEBUG
,"Write error sending DB to slave: %s",
4908 slave
->repldboff
+= nwritten
;
4909 if (slave
->repldboff
== slave
->repldbsize
) {
4910 close(slave
->repldbfd
);
4911 slave
->repldbfd
= -1;
4912 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
4913 slave
->replstate
= REDIS_REPL_ONLINE
;
4914 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
,
4915 sendReplyToClient
, slave
, NULL
) == AE_ERR
) {
4919 addReplySds(slave
,sdsempty());
4920 redisLog(REDIS_NOTICE
,"Synchronization with slave succeeded");
4924 /* This function is called at the end of every backgrond saving.
4925 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
4926 * otherwise REDIS_ERR is passed to the function.
4928 * The goal of this function is to handle slaves waiting for a successful
4929 * background saving in order to perform non-blocking synchronization. */
4930 static void updateSlavesWaitingBgsave(int bgsaveerr
) {
4932 int startbgsave
= 0;
4934 listRewind(server
.slaves
);
4935 while((ln
= listYield(server
.slaves
))) {
4936 redisClient
*slave
= ln
->value
;
4938 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) {
4940 slave
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
4941 } else if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) {
4942 struct redis_stat buf
;
4944 if (bgsaveerr
!= REDIS_OK
) {
4946 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE child returned an error");
4949 if ((slave
->repldbfd
= open(server
.dbfilename
,O_RDONLY
)) == -1 ||
4950 redis_fstat(slave
->repldbfd
,&buf
) == -1) {
4952 redisLog(REDIS_WARNING
,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno
));
4955 slave
->repldboff
= 0;
4956 slave
->repldbsize
= buf
.st_size
;
4957 slave
->replstate
= REDIS_REPL_SEND_BULK
;
4958 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
4959 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
, sendBulkToSlave
, slave
, NULL
) == AE_ERR
) {
4966 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
4967 listRewind(server
.slaves
);
4968 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE failed");
4969 while((ln
= listYield(server
.slaves
))) {
4970 redisClient
*slave
= ln
->value
;
4972 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
)
4979 static int syncWithMaster(void) {
4980 char buf
[1024], tmpfile
[256];
4982 int fd
= anetTcpConnect(NULL
,server
.masterhost
,server
.masterport
);
4986 redisLog(REDIS_WARNING
,"Unable to connect to MASTER: %s",
4990 /* Issue the SYNC command */
4991 if (syncWrite(fd
,"SYNC \r\n",7,5) == -1) {
4993 redisLog(REDIS_WARNING
,"I/O error writing to MASTER: %s",
4997 /* Read the bulk write count */
4998 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
5000 redisLog(REDIS_WARNING
,"I/O error reading bulk count from MASTER: %s",
5004 dumpsize
= atoi(buf
+1);
5005 redisLog(REDIS_NOTICE
,"Receiving %d bytes data dump from MASTER",dumpsize
);
5006 /* Read the bulk write data on a temp file */
5007 snprintf(tmpfile
,256,"temp-%d.%ld.rdb",(int)time(NULL
),(long int)random());
5008 dfd
= open(tmpfile
,O_CREAT
|O_WRONLY
,0644);
5011 redisLog(REDIS_WARNING
,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno
));
5015 int nread
, nwritten
;
5017 nread
= read(fd
,buf
,(dumpsize
< 1024)?dumpsize
:1024);
5019 redisLog(REDIS_WARNING
,"I/O error trying to sync with MASTER: %s",
5025 nwritten
= write(dfd
,buf
,nread
);
5026 if (nwritten
== -1) {
5027 redisLog(REDIS_WARNING
,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno
));
5035 if (rename(tmpfile
,server
.dbfilename
) == -1) {
5036 redisLog(REDIS_WARNING
,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno
));
5042 if (rdbLoad(server
.dbfilename
) != REDIS_OK
) {
5043 redisLog(REDIS_WARNING
,"Failed trying to load the MASTER synchronization DB from disk");
5047 server
.master
= createClient(fd
);
5048 server
.master
->flags
|= REDIS_MASTER
;
5049 server
.replstate
= REDIS_REPL_CONNECTED
;
5053 static void slaveofCommand(redisClient
*c
) {
5054 if (!strcasecmp(c
->argv
[1]->ptr
,"no") &&
5055 !strcasecmp(c
->argv
[2]->ptr
,"one")) {
5056 if (server
.masterhost
) {
5057 sdsfree(server
.masterhost
);
5058 server
.masterhost
= NULL
;
5059 if (server
.master
) freeClient(server
.master
);
5060 server
.replstate
= REDIS_REPL_NONE
;
5061 redisLog(REDIS_NOTICE
,"MASTER MODE enabled (user request)");
5064 sdsfree(server
.masterhost
);
5065 server
.masterhost
= sdsdup(c
->argv
[1]->ptr
);
5066 server
.masterport
= atoi(c
->argv
[2]->ptr
);
5067 if (server
.master
) freeClient(server
.master
);
5068 server
.replstate
= REDIS_REPL_CONNECT
;
5069 redisLog(REDIS_NOTICE
,"SLAVE OF %s:%d enabled (user request)",
5070 server
.masterhost
, server
.masterport
);
5072 addReply(c
,shared
.ok
);
5075 /* ============================ Maxmemory directive ======================== */
5077 /* This function gets called when 'maxmemory' is set on the config file to limit
5078 * the max memory used by the server, and we are out of memory.
5079 * This function will try to, in order:
5081 * - Free objects from the free list
5082 * - Try to remove keys with an EXPIRE set
5084 * It is not possible to free enough memory to reach used-memory < maxmemory
5085 * the server will start refusing commands that will enlarge even more the
5088 static void freeMemoryIfNeeded(void) {
5089 while (server
.maxmemory
&& zmalloc_used_memory() > server
.maxmemory
) {
5090 if (listLength(server
.objfreelist
)) {
5093 listNode
*head
= listFirst(server
.objfreelist
);
5094 o
= listNodeValue(head
);
5095 listDelNode(server
.objfreelist
,head
);
5098 int j
, k
, freed
= 0;
5100 for (j
= 0; j
< server
.dbnum
; j
++) {
5102 robj
*minkey
= NULL
;
5103 struct dictEntry
*de
;
5105 if (dictSize(server
.db
[j
].expires
)) {
5107 /* From a sample of three keys drop the one nearest to
5108 * the natural expire */
5109 for (k
= 0; k
< 3; k
++) {
5112 de
= dictGetRandomKey(server
.db
[j
].expires
);
5113 t
= (time_t) dictGetEntryVal(de
);
5114 if (minttl
== -1 || t
< minttl
) {
5115 minkey
= dictGetEntryKey(de
);
5119 deleteKey(server
.db
+j
,minkey
);
5122 if (!freed
) return; /* nothing to free... */
5127 /* ================================= Debugging ============================== */
5129 static void debugCommand(redisClient
*c
) {
5130 if (!strcasecmp(c
->argv
[1]->ptr
,"segfault")) {
5132 } else if (!strcasecmp(c
->argv
[1]->ptr
,"object") && c
->argc
== 3) {
5133 dictEntry
*de
= dictFind(c
->db
->dict
,c
->argv
[2]);
5137 addReply(c
,shared
.nokeyerr
);
5140 key
= dictGetEntryKey(de
);
5141 val
= dictGetEntryVal(de
);
5142 addReplySds(c
,sdscatprintf(sdsempty(),
5143 "+Key at:%p refcount:%d, value at:%p refcount:%d encoding:%d\r\n",
5144 key
, key
->refcount
, val
, val
->refcount
, val
->encoding
));
5146 addReplySds(c
,sdsnew(
5147 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>]\r\n"));
5151 #ifdef HAVE_BACKTRACE
5152 static struct redisFunctionSym symsTable
[] = {
5153 {"compareStringObjects", (unsigned long)compareStringObjects
},
5154 {"isStringRepresentableAsLong", (unsigned long)isStringRepresentableAsLong
},
5155 {"dictEncObjKeyCompare", (unsigned long)dictEncObjKeyCompare
},
5156 {"dictEncObjHash", (unsigned long)dictEncObjHash
},
5157 {"incrDecrCommand", (unsigned long)incrDecrCommand
},
5158 {"freeStringObject", (unsigned long)freeStringObject
},
5159 {"freeListObject", (unsigned long)freeListObject
},
5160 {"freeSetObject", (unsigned long)freeSetObject
},
5161 {"decrRefCount", (unsigned long)decrRefCount
},
5162 {"createObject", (unsigned long)createObject
},
5163 {"freeClient", (unsigned long)freeClient
},
5164 {"rdbLoad", (unsigned long)rdbLoad
},
5165 {"rdbSaveStringObject", (unsigned long)rdbSaveStringObject
},
5166 {"rdbSaveStringObjectRaw", (unsigned long)rdbSaveStringObjectRaw
},
5167 {"addReply", (unsigned long)addReply
},
5168 {"addReplySds", (unsigned long)addReplySds
},
5169 {"incrRefCount", (unsigned long)incrRefCount
},
5170 {"rdbSaveBackground", (unsigned long)rdbSaveBackground
},
5171 {"createStringObject", (unsigned long)createStringObject
},
5172 {"replicationFeedSlaves", (unsigned long)replicationFeedSlaves
},
5173 {"syncWithMaster", (unsigned long)syncWithMaster
},
5174 {"tryObjectSharing", (unsigned long)tryObjectSharing
},
5175 {"tryObjectEncoding", (unsigned long)tryObjectEncoding
},
5176 {"getDecodedObject", (unsigned long)getDecodedObject
},
5177 {"removeExpire", (unsigned long)removeExpire
},
5178 {"expireIfNeeded", (unsigned long)expireIfNeeded
},
5179 {"deleteIfVolatile", (unsigned long)deleteIfVolatile
},
5180 {"deleteKey", (unsigned long)deleteKey
},
5181 {"getExpire", (unsigned long)getExpire
},
5182 {"setExpire", (unsigned long)setExpire
},
5183 {"updateSlavesWaitingBgsave", (unsigned long)updateSlavesWaitingBgsave
},
5184 {"freeMemoryIfNeeded", (unsigned long)freeMemoryIfNeeded
},
5185 {"authCommand", (unsigned long)authCommand
},
5186 {"pingCommand", (unsigned long)pingCommand
},
5187 {"echoCommand", (unsigned long)echoCommand
},
5188 {"setCommand", (unsigned long)setCommand
},
5189 {"setnxCommand", (unsigned long)setnxCommand
},
5190 {"getCommand", (unsigned long)getCommand
},
5191 {"delCommand", (unsigned long)delCommand
},
5192 {"existsCommand", (unsigned long)existsCommand
},
5193 {"incrCommand", (unsigned long)incrCommand
},
5194 {"decrCommand", (unsigned long)decrCommand
},
5195 {"incrbyCommand", (unsigned long)incrbyCommand
},
5196 {"decrbyCommand", (unsigned long)decrbyCommand
},
5197 {"selectCommand", (unsigned long)selectCommand
},
5198 {"randomkeyCommand", (unsigned long)randomkeyCommand
},
5199 {"keysCommand", (unsigned long)keysCommand
},
5200 {"dbsizeCommand", (unsigned long)dbsizeCommand
},
5201 {"lastsaveCommand", (unsigned long)lastsaveCommand
},
5202 {"saveCommand", (unsigned long)saveCommand
},
5203 {"bgsaveCommand", (unsigned long)bgsaveCommand
},
5204 {"shutdownCommand", (unsigned long)shutdownCommand
},
5205 {"moveCommand", (unsigned long)moveCommand
},
5206 {"renameCommand", (unsigned long)renameCommand
},
5207 {"renamenxCommand", (unsigned long)renamenxCommand
},
5208 {"lpushCommand", (unsigned long)lpushCommand
},
5209 {"rpushCommand", (unsigned long)rpushCommand
},
5210 {"lpopCommand", (unsigned long)lpopCommand
},
5211 {"rpopCommand", (unsigned long)rpopCommand
},
5212 {"llenCommand", (unsigned long)llenCommand
},
5213 {"lindexCommand", (unsigned long)lindexCommand
},
5214 {"lrangeCommand", (unsigned long)lrangeCommand
},
5215 {"ltrimCommand", (unsigned long)ltrimCommand
},
5216 {"typeCommand", (unsigned long)typeCommand
},
5217 {"lsetCommand", (unsigned long)lsetCommand
},
5218 {"saddCommand", (unsigned long)saddCommand
},
5219 {"sremCommand", (unsigned long)sremCommand
},
5220 {"smoveCommand", (unsigned long)smoveCommand
},
5221 {"sismemberCommand", (unsigned long)sismemberCommand
},
5222 {"scardCommand", (unsigned long)scardCommand
},
5223 {"spopCommand", (unsigned long)spopCommand
},
5224 {"srandmemberCommand", (unsigned long)srandmemberCommand
},
5225 {"sinterCommand", (unsigned long)sinterCommand
},
5226 {"sinterstoreCommand", (unsigned long)sinterstoreCommand
},
5227 {"sunionCommand", (unsigned long)sunionCommand
},
5228 {"sunionstoreCommand", (unsigned long)sunionstoreCommand
},
5229 {"sdiffCommand", (unsigned long)sdiffCommand
},
5230 {"sdiffstoreCommand", (unsigned long)sdiffstoreCommand
},
5231 {"syncCommand", (unsigned long)syncCommand
},
5232 {"flushdbCommand", (unsigned long)flushdbCommand
},
5233 {"flushallCommand", (unsigned long)flushallCommand
},
5234 {"sortCommand", (unsigned long)sortCommand
},
5235 {"lremCommand", (unsigned long)lremCommand
},
5236 {"infoCommand", (unsigned long)infoCommand
},
5237 {"mgetCommand", (unsigned long)mgetCommand
},
5238 {"monitorCommand", (unsigned long)monitorCommand
},
5239 {"expireCommand", (unsigned long)expireCommand
},
5240 {"getsetCommand", (unsigned long)getsetCommand
},
5241 {"ttlCommand", (unsigned long)ttlCommand
},
5242 {"slaveofCommand", (unsigned long)slaveofCommand
},
5243 {"debugCommand", (unsigned long)debugCommand
},
5244 {"processCommand", (unsigned long)processCommand
},
5245 {"setupSigSegvAction", (unsigned long)setupSigSegvAction
},
5246 {"readQueryFromClient", (unsigned long)readQueryFromClient
},
5247 {"rdbRemoveTempFile", (unsigned long)rdbRemoveTempFile
},
5248 {"msetGenericCommand", (unsigned long)msetGenericCommand
},
5249 {"msetCommand", (unsigned long)msetCommand
},
5250 {"msetnxCommand", (unsigned long)msetnxCommand
},
5251 {"zslCreateNode", (unsigned long)zslCreateNode
},
5252 {"zslCreate", (unsigned long)zslCreate
},
5253 {"zslFreeNode",(unsigned long)zslFreeNode
},
5254 {"zslFree",(unsigned long)zslFree
},
5255 {"zslRandomLevel",(unsigned long)zslRandomLevel
},
5256 {"zslInsert",(unsigned long)zslInsert
},
5257 {"zslDelete",(unsigned long)zslDelete
},
5258 {"createZsetObject",(unsigned long)createZsetObject
},
5259 {"zaddCommand",(unsigned long)zaddCommand
},
5260 {"zrangeGenericCommand",(unsigned long)zrangeGenericCommand
},
5261 {"zrangeCommand",(unsigned long)zrangeCommand
},
5262 {"zrevrangeCommand",(unsigned long)zrevrangeCommand
},
5263 {"zremCommand",(unsigned long)zremCommand
},
5264 {"rdbSaveDoubleValue",(unsigned long)rdbSaveDoubleValue
},
5265 {"rdbLoadDoubleValue",(unsigned long)rdbLoadDoubleValue
},
5269 /* This function try to convert a pointer into a function name. It's used in
5270 * oreder to provide a backtrace under segmentation fault that's able to
5271 * display functions declared as static (otherwise the backtrace is useless). */
5272 static char *findFuncName(void *pointer
, unsigned long *offset
){
5274 unsigned long off
, minoff
= 0;
5276 /* Try to match against the Symbol with the smallest offset */
5277 for (i
=0; symsTable
[i
].pointer
; i
++) {
5278 unsigned long lp
= (unsigned long) pointer
;
5280 if (lp
!= (unsigned long)-1 && lp
>= symsTable
[i
].pointer
) {
5281 off
=lp
-symsTable
[i
].pointer
;
5282 if (ret
< 0 || off
< minoff
) {
5288 if (ret
== -1) return NULL
;
5290 return symsTable
[ret
].name
;
5293 static void *getMcontextEip(ucontext_t
*uc
) {
5294 #if defined(__FreeBSD__)
5295 return (void*) uc
->uc_mcontext
.mc_eip
;
5296 #elif defined(__dietlibc__)
5297 return (void*) uc
->uc_mcontext
.eip
;
5298 #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
5299 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
5300 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
5301 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
5302 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
5304 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
5306 #elif defined(__i386__) || defined(__X86_64__) /* Linux x86 */
5307 return (void*) uc
->uc_mcontext
.gregs
[REG_EIP
];
5308 #elif defined(__ia64__) /* Linux IA64 */
5309 return (void*) uc
->uc_mcontext
.sc_ip
;
5315 static void segvHandler(int sig
, siginfo_t
*info
, void *secret
) {
5317 char **messages
= NULL
;
5318 int i
, trace_size
= 0;
5319 unsigned long offset
=0;
5320 time_t uptime
= time(NULL
)-server
.stat_starttime
;
5321 ucontext_t
*uc
= (ucontext_t
*) secret
;
5322 REDIS_NOTUSED(info
);
5324 redisLog(REDIS_WARNING
,
5325 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION
, sig
);
5326 redisLog(REDIS_WARNING
, "%s", sdscatprintf(sdsempty(),
5327 "redis_version:%s; "
5328 "uptime_in_seconds:%d; "
5329 "connected_clients:%d; "
5330 "connected_slaves:%d; "
5332 "changes_since_last_save:%lld; "
5333 "bgsave_in_progress:%d; "
5334 "last_save_time:%d; "
5335 "total_connections_received:%lld; "
5336 "total_commands_processed:%lld; "
5340 listLength(server
.clients
)-listLength(server
.slaves
),
5341 listLength(server
.slaves
),
5344 server
.bgsaveinprogress
,
5346 server
.stat_numconnections
,
5347 server
.stat_numcommands
,
5348 server
.masterhost
== NULL
? "master" : "slave"
5351 trace_size
= backtrace(trace
, 100);
5352 /* overwrite sigaction with caller's address */
5353 if (getMcontextEip(uc
) != NULL
) {
5354 trace
[1] = getMcontextEip(uc
);
5356 messages
= backtrace_symbols(trace
, trace_size
);
5358 for (i
=1; i
<trace_size
; ++i
) {
5359 char *fn
= findFuncName(trace
[i
], &offset
), *p
;
5361 p
= strchr(messages
[i
],'+');
5362 if (!fn
|| (p
&& ((unsigned long)strtol(p
+1,NULL
,10)) < offset
)) {
5363 redisLog(REDIS_WARNING
,"%s", messages
[i
]);
5365 redisLog(REDIS_WARNING
,"%d redis-server %p %s + %d", i
, trace
[i
], fn
, (unsigned int)offset
);
5372 static void setupSigSegvAction(void) {
5373 struct sigaction act
;
5375 sigemptyset (&act
.sa_mask
);
5376 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
5377 * is used. Otherwise, sa_handler is used */
5378 act
.sa_flags
= SA_NODEFER
| SA_ONSTACK
| SA_RESETHAND
| SA_SIGINFO
;
5379 act
.sa_sigaction
= segvHandler
;
5380 sigaction (SIGSEGV
, &act
, NULL
);
5381 sigaction (SIGBUS
, &act
, NULL
);
5382 sigaction (SIGFPE
, &act
, NULL
);
5383 sigaction (SIGILL
, &act
, NULL
);
5384 sigaction (SIGBUS
, &act
, NULL
);
5387 #else /* HAVE_BACKTRACE */
5388 static void setupSigSegvAction(void) {
5390 #endif /* HAVE_BACKTRACE */
5392 /* =================================== Main! ================================ */
5395 int linuxOvercommitMemoryValue(void) {
5396 FILE *fp
= fopen("/proc/sys/vm/overcommit_memory","r");
5400 if (fgets(buf
,64,fp
) == NULL
) {
5409 void linuxOvercommitMemoryWarning(void) {
5410 if (linuxOvercommitMemoryValue() == 0) {
5411 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.");
5414 #endif /* __linux__ */
5416 static void daemonize(void) {
5420 if (fork() != 0) exit(0); /* parent exits */
5421 setsid(); /* create a new session */
5423 /* Every output goes to /dev/null. If Redis is daemonized but
5424 * the 'logfile' is set to 'stdout' in the configuration file
5425 * it will not log at all. */
5426 if ((fd
= open("/dev/null", O_RDWR
, 0)) != -1) {
5427 dup2(fd
, STDIN_FILENO
);
5428 dup2(fd
, STDOUT_FILENO
);
5429 dup2(fd
, STDERR_FILENO
);
5430 if (fd
> STDERR_FILENO
) close(fd
);
5432 /* Try to write the pid file */
5433 fp
= fopen(server
.pidfile
,"w");
5435 fprintf(fp
,"%d\n",getpid());
5440 int main(int argc
, char **argv
) {
5443 ResetServerSaveParams();
5444 loadServerConfig(argv
[1]);
5445 } else if (argc
> 2) {
5446 fprintf(stderr
,"Usage: ./redis-server [/path/to/redis.conf]\n");
5449 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'");
5452 if (server
.daemonize
) daemonize();
5453 redisLog(REDIS_NOTICE
,"Server started, Redis version " REDIS_VERSION
);
5455 linuxOvercommitMemoryWarning();
5457 if (rdbLoad(server
.dbfilename
) == REDIS_OK
)
5458 redisLog(REDIS_NOTICE
,"DB loaded from disk");
5459 if (aeCreateFileEvent(server
.el
, server
.fd
, AE_READABLE
,
5460 acceptHandler
, NULL
, NULL
) == AE_ERR
) oom("creating file event");
5461 redisLog(REDIS_NOTICE
,"The server is now ready to accept connections on port %d", server
.port
);
5463 aeDeleteEventLoop(server
.el
);