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 "0.101"
39 #define __USE_POSIX199309
49 #include <arpa/inet.h>
53 #include <sys/resource.h>
58 #include "ae.h" /* Event driven programming library */
59 #include "sds.h" /* Dynamic safe strings */
60 #include "anet.h" /* Networking the easy way */
61 #include "dict.h" /* Hash tables */
62 #include "adlist.h" /* Linked lists */
63 #include "zmalloc.h" /* total memory usage aware version of malloc/free */
64 #include "lzf.h" /* LZF compression library */
65 #include "pqsort.h" /* Partial qsort for SORT+LIMIT */
73 /* Static server configuration */
74 #define REDIS_SERVERPORT 6379 /* TCP port */
75 #define REDIS_MAXIDLETIME (60*5) /* default client timeout */
76 #define REDIS_IOBUF_LEN 1024
77 #define REDIS_LOADBUF_LEN 1024
78 #define REDIS_STATIC_ARGS 4
79 #define REDIS_DEFAULT_DBNUM 16
80 #define REDIS_CONFIGLINE_MAX 1024
81 #define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
82 #define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
83 #define REDIS_EXPIRELOOKUPS_PER_CRON 100 /* try to expire 100 keys/second */
84 #define REDIS_MAX_WRITE_PER_EVENT (1024*64)
86 /* Hash table parameters */
87 #define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
88 #define REDIS_HT_MINSLOTS 16384 /* Never resize the HT under this */
91 #define REDIS_CMD_BULK 1 /* Bulk write command */
92 #define REDIS_CMD_INLINE 2 /* Inline command */
93 /* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
94 this flags will return an error when the 'maxmemory' option is set in the
95 config file and the server is using more than maxmemory bytes of memory.
96 In short this commands are denied on low memory conditions. */
97 #define REDIS_CMD_DENYOOM 4
100 #define REDIS_STRING 0
105 /* Object types only used for dumping to disk */
106 #define REDIS_EXPIRETIME 253
107 #define REDIS_SELECTDB 254
108 #define REDIS_EOF 255
110 /* Defines related to the dump file format. To store 32 bits lengths for short
111 * keys requires a lot of space, so we check the most significant 2 bits of
112 * the first byte to interpreter the length:
114 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
115 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
116 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
117 * 11|000000 this means: specially encoded object will follow. The six bits
118 * number specify the kind of object that follows.
119 * See the REDIS_RDB_ENC_* defines.
121 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
122 * values, will fit inside. */
123 #define REDIS_RDB_6BITLEN 0
124 #define REDIS_RDB_14BITLEN 1
125 #define REDIS_RDB_32BITLEN 2
126 #define REDIS_RDB_ENCVAL 3
127 #define REDIS_RDB_LENERR UINT_MAX
129 /* When a length of a string object stored on disk has the first two bits
130 * set, the remaining two bits specify a special encoding for the object
131 * accordingly to the following defines: */
132 #define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
133 #define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
134 #define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
135 #define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
138 #define REDIS_CLOSE 1 /* This client connection should be closed ASAP */
139 #define REDIS_SLAVE 2 /* This client is a slave server */
140 #define REDIS_MASTER 4 /* This client is a master server */
141 #define REDIS_MONITOR 8 /* This client is a slave monitor, see MONITOR */
143 /* Slave replication state - slave side */
144 #define REDIS_REPL_NONE 0 /* No active replication */
145 #define REDIS_REPL_CONNECT 1 /* Must connect to master */
146 #define REDIS_REPL_CONNECTED 2 /* Connected to master */
148 /* Slave replication state - from the point of view of master
149 * Note that in SEND_BULK and ONLINE state the slave receives new updates
150 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
151 * to start the next background saving in order to send updates to it. */
152 #define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
153 #define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
154 #define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
155 #define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
157 /* List related stuff */
161 /* Sort operations */
162 #define REDIS_SORT_GET 0
163 #define REDIS_SORT_DEL 1
164 #define REDIS_SORT_INCR 2
165 #define REDIS_SORT_DECR 3
166 #define REDIS_SORT_ASC 4
167 #define REDIS_SORT_DESC 5
168 #define REDIS_SORTKEY_MAX 1024
171 #define REDIS_DEBUG 0
172 #define REDIS_NOTICE 1
173 #define REDIS_WARNING 2
175 /* Anti-warning macro... */
176 #define REDIS_NOTUSED(V) ((void) V)
179 /*================================= Data types ============================== */
181 /* A redis object, that is a type able to hold a string / list / set */
182 typedef struct redisObject
{
188 typedef struct redisDb
{
194 /* With multiplexing we need to take per-clinet state.
195 * Clients are taken in a liked list. */
196 typedef struct redisClient
{
203 int bulklen
; /* bulk read len. -1 if not in bulk read mode */
206 time_t lastinteraction
; /* time of the last interaction, used for timeout */
207 int flags
; /* REDIS_CLOSE | REDIS_SLAVE | REDIS_MONITOR */
208 int slaveseldb
; /* slave selected db, if this client is a slave */
209 int authenticated
; /* when requirepass is non-NULL */
210 int replstate
; /* replication state if this is a slave */
211 int repldbfd
; /* replication DB file descriptor */
212 long repldboff
; /* replication DB file offset */
213 off_t repldbsize
; /* replication DB file size */
221 /* Global server state structure */
227 unsigned int sharingpoolsize
;
228 long long dirty
; /* changes to DB from the last save */
230 list
*slaves
, *monitors
;
231 char neterr
[ANET_ERR_LEN
];
233 int cronloops
; /* number of times the cron function run */
234 list
*objfreelist
; /* A list of freed objects to avoid malloc() */
235 time_t lastsave
; /* Unix time of last save succeeede */
236 size_t usedmemory
; /* Used memory in megabytes */
237 /* Fields used only for stats */
238 time_t stat_starttime
; /* server start time */
239 long long stat_numcommands
; /* number of processed commands */
240 long long stat_numconnections
; /* number of connections received */
248 int bgsaveinprogress
;
249 pid_t bgsavechildpid
;
250 struct saveparam
*saveparams
;
257 /* Replication related */
261 redisClient
*master
; /* client that is master for this slave */
263 unsigned int maxclients
;
264 unsigned int maxmemory
;
265 /* Sort parameters - qsort_r() is only available under BSD so we
266 * have to take this state global, in order to pass it to sortCompare() */
272 typedef void redisCommandProc(redisClient
*c
);
273 struct redisCommand
{
275 redisCommandProc
*proc
;
280 struct redisFunctionSym
{
282 unsigned long pointer
;
285 typedef struct _redisSortObject
{
293 typedef struct _redisSortOperation
{
296 } redisSortOperation
;
298 struct sharedObjectsStruct
{
299 robj
*crlf
, *ok
, *err
, *emptybulk
, *czero
, *cone
, *pong
, *space
,
300 *colon
, *nullbulk
, *nullmultibulk
,
301 *emptymultibulk
, *wrongtypeerr
, *nokeyerr
, *syntaxerr
, *sameobjecterr
,
302 *outofrangeerr
, *plus
,
303 *select0
, *select1
, *select2
, *select3
, *select4
,
304 *select5
, *select6
, *select7
, *select8
, *select9
;
307 /*================================ Prototypes =============================== */
309 static void freeStringObject(robj
*o
);
310 static void freeListObject(robj
*o
);
311 static void freeSetObject(robj
*o
);
312 static void decrRefCount(void *o
);
313 static robj
*createObject(int type
, void *ptr
);
314 static void freeClient(redisClient
*c
);
315 static int rdbLoad(char *filename
);
316 static void addReply(redisClient
*c
, robj
*obj
);
317 static void addReplySds(redisClient
*c
, sds s
);
318 static void incrRefCount(robj
*o
);
319 static int rdbSaveBackground(char *filename
);
320 static robj
*createStringObject(char *ptr
, size_t len
);
321 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
);
322 static int syncWithMaster(void);
323 static robj
*tryObjectSharing(robj
*o
);
324 static int removeExpire(redisDb
*db
, robj
*key
);
325 static int expireIfNeeded(redisDb
*db
, robj
*key
);
326 static int deleteIfVolatile(redisDb
*db
, robj
*key
);
327 static int deleteKey(redisDb
*db
, robj
*key
);
328 static time_t getExpire(redisDb
*db
, robj
*key
);
329 static int setExpire(redisDb
*db
, robj
*key
, time_t when
);
330 static void updateSalvesWaitingBgsave(int bgsaveerr
);
331 static void freeMemoryIfNeeded(void);
332 static int processCommand(redisClient
*c
);
333 static void segvHandler(int sig
, siginfo_t
*info
, void *secret
);
334 static void setupSigSegvAction(void);
336 static void authCommand(redisClient
*c
);
337 static void pingCommand(redisClient
*c
);
338 static void echoCommand(redisClient
*c
);
339 static void setCommand(redisClient
*c
);
340 static void setnxCommand(redisClient
*c
);
341 static void getCommand(redisClient
*c
);
342 static void delCommand(redisClient
*c
);
343 static void existsCommand(redisClient
*c
);
344 static void incrCommand(redisClient
*c
);
345 static void decrCommand(redisClient
*c
);
346 static void incrbyCommand(redisClient
*c
);
347 static void decrbyCommand(redisClient
*c
);
348 static void selectCommand(redisClient
*c
);
349 static void randomkeyCommand(redisClient
*c
);
350 static void keysCommand(redisClient
*c
);
351 static void dbsizeCommand(redisClient
*c
);
352 static void lastsaveCommand(redisClient
*c
);
353 static void saveCommand(redisClient
*c
);
354 static void bgsaveCommand(redisClient
*c
);
355 static void shutdownCommand(redisClient
*c
);
356 static void moveCommand(redisClient
*c
);
357 static void renameCommand(redisClient
*c
);
358 static void renamenxCommand(redisClient
*c
);
359 static void lpushCommand(redisClient
*c
);
360 static void rpushCommand(redisClient
*c
);
361 static void lpopCommand(redisClient
*c
);
362 static void rpopCommand(redisClient
*c
);
363 static void llenCommand(redisClient
*c
);
364 static void lindexCommand(redisClient
*c
);
365 static void lrangeCommand(redisClient
*c
);
366 static void ltrimCommand(redisClient
*c
);
367 static void typeCommand(redisClient
*c
);
368 static void lsetCommand(redisClient
*c
);
369 static void saddCommand(redisClient
*c
);
370 static void sremCommand(redisClient
*c
);
371 static void smoveCommand(redisClient
*c
);
372 static void sismemberCommand(redisClient
*c
);
373 static void scardCommand(redisClient
*c
);
374 static void sinterCommand(redisClient
*c
);
375 static void sinterstoreCommand(redisClient
*c
);
376 static void sunionCommand(redisClient
*c
);
377 static void sunionstoreCommand(redisClient
*c
);
378 static void sdiffCommand(redisClient
*c
);
379 static void sdiffstoreCommand(redisClient
*c
);
380 static void syncCommand(redisClient
*c
);
381 static void flushdbCommand(redisClient
*c
);
382 static void flushallCommand(redisClient
*c
);
383 static void sortCommand(redisClient
*c
);
384 static void lremCommand(redisClient
*c
);
385 static void infoCommand(redisClient
*c
);
386 static void mgetCommand(redisClient
*c
);
387 static void monitorCommand(redisClient
*c
);
388 static void expireCommand(redisClient
*c
);
389 static void getSetCommand(redisClient
*c
);
390 static void ttlCommand(redisClient
*c
);
391 static void slaveofCommand(redisClient
*c
);
392 static void debugCommand(redisClient
*c
);
393 /*================================= Globals ================================= */
396 static struct redisServer server
; /* server global state */
397 static struct redisCommand cmdTable
[] = {
398 {"get",getCommand
,2,REDIS_CMD_INLINE
},
399 {"set",setCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
400 {"setnx",setnxCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
401 {"del",delCommand
,-2,REDIS_CMD_INLINE
},
402 {"exists",existsCommand
,2,REDIS_CMD_INLINE
},
403 {"incr",incrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
404 {"decr",decrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
405 {"mget",mgetCommand
,-2,REDIS_CMD_INLINE
},
406 {"rpush",rpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
407 {"lpush",lpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
408 {"rpop",rpopCommand
,2,REDIS_CMD_INLINE
},
409 {"lpop",lpopCommand
,2,REDIS_CMD_INLINE
},
410 {"llen",llenCommand
,2,REDIS_CMD_INLINE
},
411 {"lindex",lindexCommand
,3,REDIS_CMD_INLINE
},
412 {"lset",lsetCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
413 {"lrange",lrangeCommand
,4,REDIS_CMD_INLINE
},
414 {"ltrim",ltrimCommand
,4,REDIS_CMD_INLINE
},
415 {"lrem",lremCommand
,4,REDIS_CMD_BULK
},
416 {"sadd",saddCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
417 {"srem",sremCommand
,3,REDIS_CMD_BULK
},
418 {"smove",smoveCommand
,4,REDIS_CMD_BULK
},
419 {"sismember",sismemberCommand
,3,REDIS_CMD_BULK
},
420 {"scard",scardCommand
,2,REDIS_CMD_INLINE
},
421 {"sinter",sinterCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
422 {"sinterstore",sinterstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
423 {"sunion",sunionCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
424 {"sunionstore",sunionstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
425 {"sdiff",sdiffCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
426 {"sdiffstore",sdiffstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
427 {"smembers",sinterCommand
,2,REDIS_CMD_INLINE
},
428 {"incrby",incrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
429 {"decrby",decrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
430 {"getset",getSetCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
431 {"randomkey",randomkeyCommand
,1,REDIS_CMD_INLINE
},
432 {"select",selectCommand
,2,REDIS_CMD_INLINE
},
433 {"move",moveCommand
,3,REDIS_CMD_INLINE
},
434 {"rename",renameCommand
,3,REDIS_CMD_INLINE
},
435 {"renamenx",renamenxCommand
,3,REDIS_CMD_INLINE
},
436 {"expire",expireCommand
,3,REDIS_CMD_INLINE
},
437 {"keys",keysCommand
,2,REDIS_CMD_INLINE
},
438 {"dbsize",dbsizeCommand
,1,REDIS_CMD_INLINE
},
439 {"auth",authCommand
,2,REDIS_CMD_INLINE
},
440 {"ping",pingCommand
,1,REDIS_CMD_INLINE
},
441 {"echo",echoCommand
,2,REDIS_CMD_BULK
},
442 {"save",saveCommand
,1,REDIS_CMD_INLINE
},
443 {"bgsave",bgsaveCommand
,1,REDIS_CMD_INLINE
},
444 {"shutdown",shutdownCommand
,1,REDIS_CMD_INLINE
},
445 {"lastsave",lastsaveCommand
,1,REDIS_CMD_INLINE
},
446 {"type",typeCommand
,2,REDIS_CMD_INLINE
},
447 {"sync",syncCommand
,1,REDIS_CMD_INLINE
},
448 {"flushdb",flushdbCommand
,1,REDIS_CMD_INLINE
},
449 {"flushall",flushallCommand
,1,REDIS_CMD_INLINE
},
450 {"sort",sortCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
451 {"info",infoCommand
,1,REDIS_CMD_INLINE
},
452 {"monitor",monitorCommand
,1,REDIS_CMD_INLINE
},
453 {"ttl",ttlCommand
,2,REDIS_CMD_INLINE
},
454 {"slaveof",slaveofCommand
,3,REDIS_CMD_INLINE
},
455 {"debug",debugCommand
,-2,REDIS_CMD_INLINE
},
458 /*============================ Utility functions ============================ */
460 /* Glob-style pattern matching. */
461 int stringmatchlen(const char *pattern
, int patternLen
,
462 const char *string
, int stringLen
, int nocase
)
467 while (pattern
[1] == '*') {
472 return 1; /* match */
474 if (stringmatchlen(pattern
+1, patternLen
-1,
475 string
, stringLen
, nocase
))
476 return 1; /* match */
480 return 0; /* no match */
484 return 0; /* no match */
494 not = pattern
[0] == '^';
501 if (pattern
[0] == '\\') {
504 if (pattern
[0] == string
[0])
506 } else if (pattern
[0] == ']') {
508 } else if (patternLen
== 0) {
512 } else if (pattern
[1] == '-' && patternLen
>= 3) {
513 int start
= pattern
[0];
514 int end
= pattern
[2];
522 start
= tolower(start
);
528 if (c
>= start
&& c
<= end
)
532 if (pattern
[0] == string
[0])
535 if (tolower((int)pattern
[0]) == tolower((int)string
[0]))
545 return 0; /* no match */
551 if (patternLen
>= 2) {
558 if (pattern
[0] != string
[0])
559 return 0; /* no match */
561 if (tolower((int)pattern
[0]) != tolower((int)string
[0]))
562 return 0; /* no match */
570 if (stringLen
== 0) {
571 while(*pattern
== '*') {
578 if (patternLen
== 0 && stringLen
== 0)
583 static void redisLog(int level
, const char *fmt
, ...) {
587 fp
= (server
.logfile
== NULL
) ? stdout
: fopen(server
.logfile
,"a");
591 if (level
>= server
.verbosity
) {
597 strftime(buf
,64,"%d %b %H:%M:%S",gmtime(&now
));
598 fprintf(fp
,"%s %c ",buf
,c
[level
]);
599 vfprintf(fp
, fmt
, ap
);
605 if (server
.logfile
) fclose(fp
);
608 /*====================== Hash table type implementation ==================== */
610 /* This is an hash table type that uses the SDS dynamic strings libary as
611 * keys and radis objects as values (objects can hold SDS strings,
614 static int sdsDictKeyCompare(void *privdata
, const void *key1
,
618 DICT_NOTUSED(privdata
);
620 l1
= sdslen((sds
)key1
);
621 l2
= sdslen((sds
)key2
);
622 if (l1
!= l2
) return 0;
623 return memcmp(key1
, key2
, l1
) == 0;
626 static void dictRedisObjectDestructor(void *privdata
, void *val
)
628 DICT_NOTUSED(privdata
);
633 static int dictSdsKeyCompare(void *privdata
, const void *key1
,
636 const robj
*o1
= key1
, *o2
= key2
;
637 return sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
640 static unsigned int dictSdsHash(const void *key
) {
642 return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
645 static dictType setDictType
= {
646 dictSdsHash
, /* hash function */
649 dictSdsKeyCompare
, /* key compare */
650 dictRedisObjectDestructor
, /* key destructor */
651 NULL
/* val destructor */
654 static dictType hashDictType
= {
655 dictSdsHash
, /* hash function */
658 dictSdsKeyCompare
, /* key compare */
659 dictRedisObjectDestructor
, /* key destructor */
660 dictRedisObjectDestructor
/* val destructor */
663 /* ========================= Random utility functions ======================= */
665 /* Redis generally does not try to recover from out of memory conditions
666 * when allocating objects or strings, it is not clear if it will be possible
667 * to report this condition to the client since the networking layer itself
668 * is based on heap allocation for send buffers, so we simply abort.
669 * At least the code will be simpler to read... */
670 static void oom(const char *msg
) {
671 fprintf(stderr
, "%s: Out of memory\n",msg
);
677 /* ====================== Redis server networking stuff ===================== */
678 static void closeTimedoutClients(void) {
681 time_t now
= time(NULL
);
683 listRewind(server
.clients
);
684 while ((ln
= listYield(server
.clients
)) != NULL
) {
685 c
= listNodeValue(ln
);
686 if (!(c
->flags
& REDIS_SLAVE
) && /* no timeout for slaves */
687 !(c
->flags
& REDIS_MASTER
) && /* no timeout for masters */
688 (now
- c
->lastinteraction
> server
.maxidletime
)) {
689 redisLog(REDIS_DEBUG
,"Closing idle client");
695 /* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
696 * we resize the hash table to save memory */
697 static void tryResizeHashTables(void) {
700 for (j
= 0; j
< server
.dbnum
; j
++) {
701 long long size
, used
;
703 size
= dictSlots(server
.db
[j
].dict
);
704 used
= dictSize(server
.db
[j
].dict
);
705 if (size
&& used
&& size
> REDIS_HT_MINSLOTS
&&
706 (used
*100/size
< REDIS_HT_MINFILL
)) {
707 redisLog(REDIS_NOTICE
,"The hash table %d is too sparse, resize it...",j
);
708 dictResize(server
.db
[j
].dict
);
709 redisLog(REDIS_NOTICE
,"Hash table %d resized.",j
);
714 static int serverCron(struct aeEventLoop
*eventLoop
, long long id
, void *clientData
) {
715 int j
, loops
= server
.cronloops
++;
716 REDIS_NOTUSED(eventLoop
);
718 REDIS_NOTUSED(clientData
);
720 /* Update the global state with the amount of used memory */
721 server
.usedmemory
= zmalloc_used_memory();
723 /* Show some info about non-empty databases */
724 for (j
= 0; j
< server
.dbnum
; j
++) {
725 long long size
, used
, vkeys
;
727 size
= dictSlots(server
.db
[j
].dict
);
728 used
= dictSize(server
.db
[j
].dict
);
729 vkeys
= dictSize(server
.db
[j
].expires
);
730 if (!(loops
% 5) && used
> 0) {
731 redisLog(REDIS_DEBUG
,"DB %d: %d keys (%d volatile) in %d slots HT.",j
,used
,vkeys
,size
);
732 /* dictPrintStats(server.dict); */
736 /* We don't want to resize the hash tables while a bacground saving
737 * is in progress: the saving child is created using fork() that is
738 * implemented with a copy-on-write semantic in most modern systems, so
739 * if we resize the HT while there is the saving child at work actually
740 * a lot of memory movements in the parent will cause a lot of pages
742 if (!server
.bgsaveinprogress
) tryResizeHashTables();
744 /* Show information about connected clients */
746 redisLog(REDIS_DEBUG
,"%d clients connected (%d slaves), %zu bytes in use",
747 listLength(server
.clients
)-listLength(server
.slaves
),
748 listLength(server
.slaves
),
750 dictSize(server
.sharingpool
));
753 /* Close connections of timedout clients */
754 if (server
.maxidletime
&& !(loops
% 10))
755 closeTimedoutClients();
757 /* Check if a background saving in progress terminated */
758 if (server
.bgsaveinprogress
) {
760 /* XXX: TODO handle the case of the saving child killed */
761 if (wait4(-1,&statloc
,WNOHANG
,NULL
)) {
762 int exitcode
= WEXITSTATUS(statloc
);
763 int bysignal
= WIFSIGNALED(statloc
);
765 if (!bysignal
&& exitcode
== 0) {
766 redisLog(REDIS_NOTICE
,
767 "Background saving terminated with success");
769 server
.lastsave
= time(NULL
);
770 } else if (!bysignal
&& exitcode
!= 0) {
771 redisLog(REDIS_WARNING
, "Background saving error");
773 redisLog(REDIS_WARNING
,
774 "Background saving terminated by signal");
776 server
.bgsaveinprogress
= 0;
777 server
.bgsavechildpid
= -1;
778 updateSalvesWaitingBgsave(exitcode
== 0 ? REDIS_OK
: REDIS_ERR
);
781 /* If there is not a background saving in progress check if
782 * we have to save now */
783 time_t now
= time(NULL
);
784 for (j
= 0; j
< server
.saveparamslen
; j
++) {
785 struct saveparam
*sp
= server
.saveparams
+j
;
787 if (server
.dirty
>= sp
->changes
&&
788 now
-server
.lastsave
> sp
->seconds
) {
789 redisLog(REDIS_NOTICE
,"%d changes in %d seconds. Saving...",
790 sp
->changes
, sp
->seconds
);
791 rdbSaveBackground(server
.dbfilename
);
797 /* Try to expire a few timed out keys */
798 for (j
= 0; j
< server
.dbnum
; j
++) {
799 redisDb
*db
= server
.db
+j
;
800 int num
= dictSize(db
->expires
);
803 time_t now
= time(NULL
);
805 if (num
> REDIS_EXPIRELOOKUPS_PER_CRON
)
806 num
= REDIS_EXPIRELOOKUPS_PER_CRON
;
811 if ((de
= dictGetRandomKey(db
->expires
)) == NULL
) break;
812 t
= (time_t) dictGetEntryVal(de
);
814 deleteKey(db
,dictGetEntryKey(de
));
820 /* Check if we should connect to a MASTER */
821 if (server
.replstate
== REDIS_REPL_CONNECT
) {
822 redisLog(REDIS_NOTICE
,"Connecting to MASTER...");
823 if (syncWithMaster() == REDIS_OK
) {
824 redisLog(REDIS_NOTICE
,"MASTER <-> SLAVE sync succeeded");
830 static void createSharedObjects(void) {
831 shared
.crlf
= createObject(REDIS_STRING
,sdsnew("\r\n"));
832 shared
.ok
= createObject(REDIS_STRING
,sdsnew("+OK\r\n"));
833 shared
.err
= createObject(REDIS_STRING
,sdsnew("-ERR\r\n"));
834 shared
.emptybulk
= createObject(REDIS_STRING
,sdsnew("$0\r\n\r\n"));
835 shared
.czero
= createObject(REDIS_STRING
,sdsnew(":0\r\n"));
836 shared
.cone
= createObject(REDIS_STRING
,sdsnew(":1\r\n"));
837 shared
.nullbulk
= createObject(REDIS_STRING
,sdsnew("$-1\r\n"));
838 shared
.nullmultibulk
= createObject(REDIS_STRING
,sdsnew("*-1\r\n"));
839 shared
.emptymultibulk
= createObject(REDIS_STRING
,sdsnew("*0\r\n"));
841 shared
.pong
= createObject(REDIS_STRING
,sdsnew("+PONG\r\n"));
842 shared
.wrongtypeerr
= createObject(REDIS_STRING
,sdsnew(
843 "-ERR Operation against a key holding the wrong kind of value\r\n"));
844 shared
.nokeyerr
= createObject(REDIS_STRING
,sdsnew(
845 "-ERR no such key\r\n"));
846 shared
.syntaxerr
= createObject(REDIS_STRING
,sdsnew(
847 "-ERR syntax error\r\n"));
848 shared
.sameobjecterr
= createObject(REDIS_STRING
,sdsnew(
849 "-ERR source and destination objects are the same\r\n"));
850 shared
.outofrangeerr
= createObject(REDIS_STRING
,sdsnew(
851 "-ERR index out of range\r\n"));
852 shared
.space
= createObject(REDIS_STRING
,sdsnew(" "));
853 shared
.colon
= createObject(REDIS_STRING
,sdsnew(":"));
854 shared
.plus
= createObject(REDIS_STRING
,sdsnew("+"));
855 shared
.select0
= createStringObject("select 0\r\n",10);
856 shared
.select1
= createStringObject("select 1\r\n",10);
857 shared
.select2
= createStringObject("select 2\r\n",10);
858 shared
.select3
= createStringObject("select 3\r\n",10);
859 shared
.select4
= createStringObject("select 4\r\n",10);
860 shared
.select5
= createStringObject("select 5\r\n",10);
861 shared
.select6
= createStringObject("select 6\r\n",10);
862 shared
.select7
= createStringObject("select 7\r\n",10);
863 shared
.select8
= createStringObject("select 8\r\n",10);
864 shared
.select9
= createStringObject("select 9\r\n",10);
867 static void appendServerSaveParams(time_t seconds
, int changes
) {
868 server
.saveparams
= zrealloc(server
.saveparams
,sizeof(struct saveparam
)*(server
.saveparamslen
+1));
869 if (server
.saveparams
== NULL
) oom("appendServerSaveParams");
870 server
.saveparams
[server
.saveparamslen
].seconds
= seconds
;
871 server
.saveparams
[server
.saveparamslen
].changes
= changes
;
872 server
.saveparamslen
++;
875 static void ResetServerSaveParams() {
876 zfree(server
.saveparams
);
877 server
.saveparams
= NULL
;
878 server
.saveparamslen
= 0;
881 static void initServerConfig() {
882 server
.dbnum
= REDIS_DEFAULT_DBNUM
;
883 server
.port
= REDIS_SERVERPORT
;
884 server
.verbosity
= REDIS_DEBUG
;
885 server
.maxidletime
= REDIS_MAXIDLETIME
;
886 server
.saveparams
= NULL
;
887 server
.logfile
= NULL
; /* NULL = log on standard output */
888 server
.bindaddr
= NULL
;
889 server
.glueoutputbuf
= 1;
890 server
.daemonize
= 0;
891 server
.pidfile
= "/var/run/redis.pid";
892 server
.dbfilename
= "dump.rdb";
893 server
.requirepass
= NULL
;
894 server
.shareobjects
= 0;
895 server
.maxclients
= 0;
896 server
.maxmemory
= 0;
897 ResetServerSaveParams();
899 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
900 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
901 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
902 /* Replication related */
904 server
.masterhost
= NULL
;
905 server
.masterport
= 6379;
906 server
.master
= NULL
;
907 server
.replstate
= REDIS_REPL_NONE
;
910 static void initServer() {
913 signal(SIGHUP
, SIG_IGN
);
914 signal(SIGPIPE
, SIG_IGN
);
915 setupSigSegvAction();
917 server
.clients
= listCreate();
918 server
.slaves
= listCreate();
919 server
.monitors
= listCreate();
920 server
.objfreelist
= listCreate();
921 createSharedObjects();
922 server
.el
= aeCreateEventLoop();
923 server
.db
= zmalloc(sizeof(redisDb
)*server
.dbnum
);
924 server
.sharingpool
= dictCreate(&setDictType
,NULL
);
925 server
.sharingpoolsize
= 1024;
926 if (!server
.db
|| !server
.clients
|| !server
.slaves
|| !server
.monitors
|| !server
.el
|| !server
.objfreelist
)
927 oom("server initialization"); /* Fatal OOM */
928 server
.fd
= anetTcpServer(server
.neterr
, server
.port
, server
.bindaddr
);
929 if (server
.fd
== -1) {
930 redisLog(REDIS_WARNING
, "Opening TCP port: %s", server
.neterr
);
933 for (j
= 0; j
< server
.dbnum
; j
++) {
934 server
.db
[j
].dict
= dictCreate(&hashDictType
,NULL
);
935 server
.db
[j
].expires
= dictCreate(&setDictType
,NULL
);
938 server
.cronloops
= 0;
939 server
.bgsaveinprogress
= 0;
940 server
.bgsavechildpid
= -1;
941 server
.lastsave
= time(NULL
);
943 server
.usedmemory
= 0;
944 server
.stat_numcommands
= 0;
945 server
.stat_numconnections
= 0;
946 server
.stat_starttime
= time(NULL
);
947 aeCreateTimeEvent(server
.el
, 1000, serverCron
, NULL
, NULL
);
950 /* Empty the whole database */
951 static long long emptyDb() {
953 long long removed
= 0;
955 for (j
= 0; j
< server
.dbnum
; j
++) {
956 removed
+= dictSize(server
.db
[j
].dict
);
957 dictEmpty(server
.db
[j
].dict
);
958 dictEmpty(server
.db
[j
].expires
);
963 static int yesnotoi(char *s
) {
964 if (!strcasecmp(s
,"yes")) return 1;
965 else if (!strcasecmp(s
,"no")) return 0;
969 /* I agree, this is a very rudimental way to load a configuration...
970 will improve later if the config gets more complex */
971 static void loadServerConfig(char *filename
) {
972 FILE *fp
= fopen(filename
,"r");
973 char buf
[REDIS_CONFIGLINE_MAX
+1], *err
= NULL
;
978 redisLog(REDIS_WARNING
,"Fatal error, can't open config file");
981 while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) {
987 line
= sdstrim(line
," \t\r\n");
989 /* Skip comments and blank lines*/
990 if (line
[0] == '#' || line
[0] == '\0') {
995 /* Split into arguments */
996 argv
= sdssplitlen(line
,sdslen(line
)," ",1,&argc
);
999 /* Execute config directives */
1000 if (!strcasecmp(argv
[0],"timeout") && argc
== 2) {
1001 server
.maxidletime
= atoi(argv
[1]);
1002 if (server
.maxidletime
< 0) {
1003 err
= "Invalid timeout value"; goto loaderr
;
1005 } else if (!strcasecmp(argv
[0],"port") && argc
== 2) {
1006 server
.port
= atoi(argv
[1]);
1007 if (server
.port
< 1 || server
.port
> 65535) {
1008 err
= "Invalid port"; goto loaderr
;
1010 } else if (!strcasecmp(argv
[0],"bind") && argc
== 2) {
1011 server
.bindaddr
= zstrdup(argv
[1]);
1012 } else if (!strcasecmp(argv
[0],"save") && argc
== 3) {
1013 int seconds
= atoi(argv
[1]);
1014 int changes
= atoi(argv
[2]);
1015 if (seconds
< 1 || changes
< 0) {
1016 err
= "Invalid save parameters"; goto loaderr
;
1018 appendServerSaveParams(seconds
,changes
);
1019 } else if (!strcasecmp(argv
[0],"dir") && argc
== 2) {
1020 if (chdir(argv
[1]) == -1) {
1021 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s",
1022 argv
[1], strerror(errno
));
1025 } else if (!strcasecmp(argv
[0],"loglevel") && argc
== 2) {
1026 if (!strcasecmp(argv
[1],"debug")) server
.verbosity
= REDIS_DEBUG
;
1027 else if (!strcasecmp(argv
[1],"notice")) server
.verbosity
= REDIS_NOTICE
;
1028 else if (!strcasecmp(argv
[1],"warning")) server
.verbosity
= REDIS_WARNING
;
1030 err
= "Invalid log level. Must be one of debug, notice, warning";
1033 } else if (!strcasecmp(argv
[0],"logfile") && argc
== 2) {
1036 server
.logfile
= zstrdup(argv
[1]);
1037 if (!strcasecmp(server
.logfile
,"stdout")) {
1038 zfree(server
.logfile
);
1039 server
.logfile
= NULL
;
1041 if (server
.logfile
) {
1042 /* Test if we are able to open the file. The server will not
1043 * be able to abort just for this problem later... */
1044 fp
= fopen(server
.logfile
,"a");
1046 err
= sdscatprintf(sdsempty(),
1047 "Can't open the log file: %s", strerror(errno
));
1052 } else if (!strcasecmp(argv
[0],"databases") && argc
== 2) {
1053 server
.dbnum
= atoi(argv
[1]);
1054 if (server
.dbnum
< 1) {
1055 err
= "Invalid number of databases"; goto loaderr
;
1057 } else if (!strcasecmp(argv
[0],"maxclients") && argc
== 2) {
1058 server
.maxclients
= atoi(argv
[1]);
1059 } else if (!strcasecmp(argv
[0],"maxmemory") && argc
== 2) {
1060 server
.maxmemory
= atoi(argv
[1]);
1061 } else if (!strcasecmp(argv
[0],"slaveof") && argc
== 3) {
1062 server
.masterhost
= sdsnew(argv
[1]);
1063 server
.masterport
= atoi(argv
[2]);
1064 server
.replstate
= REDIS_REPL_CONNECT
;
1065 } else if (!strcasecmp(argv
[0],"glueoutputbuf") && argc
== 2) {
1066 if ((server
.glueoutputbuf
= yesnotoi(argv
[1])) == -1) {
1067 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1069 } else if (!strcasecmp(argv
[0],"shareobjects") && argc
== 2) {
1070 if ((server
.shareobjects
= yesnotoi(argv
[1])) == -1) {
1071 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1073 } else if (!strcasecmp(argv
[0],"shareobjectspoolsize") && argc
== 2) {
1074 server
.sharingpoolsize
= atoi(argv
[1]);
1075 if (server
.sharingpoolsize
< 1) {
1076 err
= "invalid object sharing pool size"; goto loaderr
;
1078 } else if (!strcasecmp(argv
[0],"daemonize") && argc
== 2) {
1079 if ((server
.daemonize
= yesnotoi(argv
[1])) == -1) {
1080 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1082 } else if (!strcasecmp(argv
[0],"requirepass") && argc
== 2) {
1083 server
.requirepass
= zstrdup(argv
[1]);
1084 } else if (!strcasecmp(argv
[0],"pidfile") && argc
== 2) {
1085 server
.pidfile
= zstrdup(argv
[1]);
1086 } else if (!strcasecmp(argv
[0],"dbfilename") && argc
== 2) {
1087 server
.dbfilename
= zstrdup(argv
[1]);
1089 err
= "Bad directive or wrong number of arguments"; goto loaderr
;
1091 for (j
= 0; j
< argc
; j
++)
1100 fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n");
1101 fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
);
1102 fprintf(stderr
, ">>> '%s'\n", line
);
1103 fprintf(stderr
, "%s\n", err
);
1107 static void freeClientArgv(redisClient
*c
) {
1110 for (j
= 0; j
< c
->argc
; j
++)
1111 decrRefCount(c
->argv
[j
]);
1115 static void freeClient(redisClient
*c
) {
1118 aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
);
1119 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1120 sdsfree(c
->querybuf
);
1121 listRelease(c
->reply
);
1124 ln
= listSearchKey(server
.clients
,c
);
1126 listDelNode(server
.clients
,ln
);
1127 if (c
->flags
& REDIS_SLAVE
) {
1128 if (c
->replstate
== REDIS_REPL_SEND_BULK
&& c
->repldbfd
!= -1)
1130 list
*l
= (c
->flags
& REDIS_MONITOR
) ? server
.monitors
: server
.slaves
;
1131 ln
= listSearchKey(l
,c
);
1135 if (c
->flags
& REDIS_MASTER
) {
1136 server
.master
= NULL
;
1137 server
.replstate
= REDIS_REPL_CONNECT
;
1143 static void glueReplyBuffersIfNeeded(redisClient
*c
) {
1148 listRewind(c
->reply
);
1149 while((ln
= listYield(c
->reply
))) {
1151 totlen
+= sdslen(o
->ptr
);
1152 /* This optimization makes more sense if we don't have to copy
1154 if (totlen
> 1024) return;
1160 listRewind(c
->reply
);
1161 while((ln
= listYield(c
->reply
))) {
1163 memcpy(buf
+copylen
,o
->ptr
,sdslen(o
->ptr
));
1164 copylen
+= sdslen(o
->ptr
);
1165 listDelNode(c
->reply
,ln
);
1167 /* Now the output buffer is empty, add the new single element */
1168 o
= createObject(REDIS_STRING
,sdsnewlen(buf
,totlen
));
1169 if (!listAddNodeTail(c
->reply
,o
)) oom("listAddNodeTail");
1173 static void sendReplyToClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1174 redisClient
*c
= privdata
;
1175 int nwritten
= 0, totwritten
= 0, objlen
;
1178 REDIS_NOTUSED(mask
);
1180 if (server
.glueoutputbuf
&& listLength(c
->reply
) > 1)
1181 glueReplyBuffersIfNeeded(c
);
1182 while(listLength(c
->reply
)) {
1183 o
= listNodeValue(listFirst(c
->reply
));
1184 objlen
= sdslen(o
->ptr
);
1187 listDelNode(c
->reply
,listFirst(c
->reply
));
1191 if (c
->flags
& REDIS_MASTER
) {
1192 /* Don't reply to a master */
1193 nwritten
= objlen
- c
->sentlen
;
1195 nwritten
= write(fd
, ((char*)o
->ptr
)+c
->sentlen
, objlen
- c
->sentlen
);
1196 if (nwritten
<= 0) break;
1198 c
->sentlen
+= nwritten
;
1199 totwritten
+= nwritten
;
1200 /* If we fully sent the object on head go to the next one */
1201 if (c
->sentlen
== objlen
) {
1202 listDelNode(c
->reply
,listFirst(c
->reply
));
1205 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
1206 * bytes, in a single threaded server it's a good idea to server
1207 * other clients as well, even if a very large request comes from
1208 * super fast link that is always able to accept data (in real world
1209 * terms think to 'KEYS *' against the loopback interfae) */
1210 if (totwritten
> REDIS_MAX_WRITE_PER_EVENT
) break;
1212 if (nwritten
== -1) {
1213 if (errno
== EAGAIN
) {
1216 redisLog(REDIS_DEBUG
,
1217 "Error writing to client: %s", strerror(errno
));
1222 if (totwritten
> 0) c
->lastinteraction
= time(NULL
);
1223 if (listLength(c
->reply
) == 0) {
1225 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1229 static struct redisCommand
*lookupCommand(char *name
) {
1231 while(cmdTable
[j
].name
!= NULL
) {
1232 if (!strcasecmp(name
,cmdTable
[j
].name
)) return &cmdTable
[j
];
1238 /* resetClient prepare the client to process the next command */
1239 static void resetClient(redisClient
*c
) {
1244 /* If this function gets called we already read a whole
1245 * command, argments are in the client argv/argc fields.
1246 * processCommand() execute the command or prepare the
1247 * server for a bulk read from the client.
1249 * If 1 is returned the client is still alive and valid and
1250 * and other operations can be performed by the caller. Otherwise
1251 * if 0 is returned the client was destroied (i.e. after QUIT). */
1252 static int processCommand(redisClient
*c
) {
1253 struct redisCommand
*cmd
;
1256 /* Free some memory if needed (maxmemory setting) */
1257 if (server
.maxmemory
) freeMemoryIfNeeded();
1259 /* The QUIT command is handled as a special case. Normal command
1260 * procs are unable to close the client connection safely */
1261 if (!strcasecmp(c
->argv
[0]->ptr
,"quit")) {
1265 cmd
= lookupCommand(c
->argv
[0]->ptr
);
1267 addReplySds(c
,sdsnew("-ERR unknown command\r\n"));
1270 } else if ((cmd
->arity
> 0 && cmd
->arity
!= c
->argc
) ||
1271 (c
->argc
< -cmd
->arity
)) {
1272 addReplySds(c
,sdsnew("-ERR wrong number of arguments\r\n"));
1275 } else if (server
.maxmemory
&& cmd
->flags
& REDIS_CMD_DENYOOM
&& zmalloc_used_memory() > server
.maxmemory
) {
1276 addReplySds(c
,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
1279 } else if (cmd
->flags
& REDIS_CMD_BULK
&& c
->bulklen
== -1) {
1280 int bulklen
= atoi(c
->argv
[c
->argc
-1]->ptr
);
1282 decrRefCount(c
->argv
[c
->argc
-1]);
1283 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
1285 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
1290 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
1291 /* It is possible that the bulk read is already in the
1292 * buffer. Check this condition and handle it accordingly */
1293 if ((signed)sdslen(c
->querybuf
) >= c
->bulklen
) {
1294 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
1296 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
1301 /* Let's try to share objects on the command arguments vector */
1302 if (server
.shareobjects
) {
1304 for(j
= 1; j
< c
->argc
; j
++)
1305 c
->argv
[j
] = tryObjectSharing(c
->argv
[j
]);
1307 /* Check if the user is authenticated */
1308 if (server
.requirepass
&& !c
->authenticated
&& cmd
->proc
!= authCommand
) {
1309 addReplySds(c
,sdsnew("-ERR operation not permitted\r\n"));
1314 /* Exec the command */
1315 dirty
= server
.dirty
;
1317 if (server
.dirty
-dirty
!= 0 && listLength(server
.slaves
))
1318 replicationFeedSlaves(server
.slaves
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1319 if (listLength(server
.monitors
))
1320 replicationFeedSlaves(server
.monitors
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1321 server
.stat_numcommands
++;
1323 /* Prepare the client for the next command */
1324 if (c
->flags
& REDIS_CLOSE
) {
1332 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
) {
1336 /* (args*2)+1 is enough room for args, spaces, newlines */
1337 robj
*static_outv
[REDIS_STATIC_ARGS
*2+1];
1339 if (argc
<= REDIS_STATIC_ARGS
) {
1342 outv
= zmalloc(sizeof(robj
*)*(argc
*2+1));
1343 if (!outv
) oom("replicationFeedSlaves");
1346 for (j
= 0; j
< argc
; j
++) {
1347 if (j
!= 0) outv
[outc
++] = shared
.space
;
1348 if ((cmd
->flags
& REDIS_CMD_BULK
) && j
== argc
-1) {
1351 lenobj
= createObject(REDIS_STRING
,
1352 sdscatprintf(sdsempty(),"%d\r\n",sdslen(argv
[j
]->ptr
)));
1353 lenobj
->refcount
= 0;
1354 outv
[outc
++] = lenobj
;
1356 outv
[outc
++] = argv
[j
];
1358 outv
[outc
++] = shared
.crlf
;
1360 /* Increment all the refcounts at start and decrement at end in order to
1361 * be sure to free objects if there is no slave in a replication state
1362 * able to be feed with commands */
1363 for (j
= 0; j
< outc
; j
++) incrRefCount(outv
[j
]);
1365 while((ln
= listYield(slaves
))) {
1366 redisClient
*slave
= ln
->value
;
1368 /* Don't feed slaves that are still waiting for BGSAVE to start */
1369 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) continue;
1371 /* Feed all the other slaves, MONITORs and so on */
1372 if (slave
->slaveseldb
!= dictid
) {
1376 case 0: selectcmd
= shared
.select0
; break;
1377 case 1: selectcmd
= shared
.select1
; break;
1378 case 2: selectcmd
= shared
.select2
; break;
1379 case 3: selectcmd
= shared
.select3
; break;
1380 case 4: selectcmd
= shared
.select4
; break;
1381 case 5: selectcmd
= shared
.select5
; break;
1382 case 6: selectcmd
= shared
.select6
; break;
1383 case 7: selectcmd
= shared
.select7
; break;
1384 case 8: selectcmd
= shared
.select8
; break;
1385 case 9: selectcmd
= shared
.select9
; break;
1387 selectcmd
= createObject(REDIS_STRING
,
1388 sdscatprintf(sdsempty(),"select %d\r\n",dictid
));
1389 selectcmd
->refcount
= 0;
1392 addReply(slave
,selectcmd
);
1393 slave
->slaveseldb
= dictid
;
1395 for (j
= 0; j
< outc
; j
++) addReply(slave
,outv
[j
]);
1397 for (j
= 0; j
< outc
; j
++) decrRefCount(outv
[j
]);
1398 if (outv
!= static_outv
) zfree(outv
);
1401 static void readQueryFromClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1402 redisClient
*c
= (redisClient
*) privdata
;
1403 char buf
[REDIS_IOBUF_LEN
];
1406 REDIS_NOTUSED(mask
);
1408 nread
= read(fd
, buf
, REDIS_IOBUF_LEN
);
1410 if (errno
== EAGAIN
) {
1413 redisLog(REDIS_DEBUG
, "Reading from client: %s",strerror(errno
));
1417 } else if (nread
== 0) {
1418 redisLog(REDIS_DEBUG
, "Client closed connection");
1423 c
->querybuf
= sdscatlen(c
->querybuf
, buf
, nread
);
1424 c
->lastinteraction
= time(NULL
);
1430 if (c
->bulklen
== -1) {
1431 /* Read the first line of the query */
1432 char *p
= strchr(c
->querybuf
,'\n');
1438 query
= c
->querybuf
;
1439 c
->querybuf
= sdsempty();
1440 querylen
= 1+(p
-(query
));
1441 if (sdslen(query
) > querylen
) {
1442 /* leave data after the first line of the query in the buffer */
1443 c
->querybuf
= sdscatlen(c
->querybuf
,query
+querylen
,sdslen(query
)-querylen
);
1445 *p
= '\0'; /* remove "\n" */
1446 if (*(p
-1) == '\r') *(p
-1) = '\0'; /* and "\r" if any */
1447 sdsupdatelen(query
);
1449 /* Now we can split the query in arguments */
1450 if (sdslen(query
) == 0) {
1451 /* Ignore empty query */
1455 argv
= sdssplitlen(query
,sdslen(query
)," ",1,&argc
);
1456 if (argv
== NULL
) oom("sdssplitlen");
1459 if (c
->argv
) zfree(c
->argv
);
1460 c
->argv
= zmalloc(sizeof(robj
*)*argc
);
1461 if (c
->argv
== NULL
) oom("allocating arguments list for client");
1463 for (j
= 0; j
< argc
; j
++) {
1464 if (sdslen(argv
[j
])) {
1465 c
->argv
[c
->argc
] = createObject(REDIS_STRING
,argv
[j
]);
1472 /* Execute the command. If the client is still valid
1473 * after processCommand() return and there is something
1474 * on the query buffer try to process the next command. */
1475 if (processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
1477 } else if (sdslen(c
->querybuf
) >= 1024*32) {
1478 redisLog(REDIS_DEBUG
, "Client protocol error");
1483 /* Bulk read handling. Note that if we are at this point
1484 the client already sent a command terminated with a newline,
1485 we are reading the bulk data that is actually the last
1486 argument of the command. */
1487 int qbl
= sdslen(c
->querybuf
);
1489 if (c
->bulklen
<= qbl
) {
1490 /* Copy everything but the final CRLF as final argument */
1491 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
1493 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
1500 static int selectDb(redisClient
*c
, int id
) {
1501 if (id
< 0 || id
>= server
.dbnum
)
1503 c
->db
= &server
.db
[id
];
1507 static void *dupClientReplyValue(void *o
) {
1508 incrRefCount((robj
*)o
);
1512 static redisClient
*createClient(int fd
) {
1513 redisClient
*c
= zmalloc(sizeof(*c
));
1515 anetNonBlock(NULL
,fd
);
1516 anetTcpNoDelay(NULL
,fd
);
1517 if (!c
) return NULL
;
1520 c
->querybuf
= sdsempty();
1526 c
->lastinteraction
= time(NULL
);
1527 c
->authenticated
= 0;
1528 c
->replstate
= REDIS_REPL_NONE
;
1529 if ((c
->reply
= listCreate()) == NULL
) oom("listCreate");
1530 listSetFreeMethod(c
->reply
,decrRefCount
);
1531 listSetDupMethod(c
->reply
,dupClientReplyValue
);
1532 if (aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
,
1533 readQueryFromClient
, c
, NULL
) == AE_ERR
) {
1537 if (!listAddNodeTail(server
.clients
,c
)) oom("listAddNodeTail");
1541 static void addReply(redisClient
*c
, robj
*obj
) {
1542 if (listLength(c
->reply
) == 0 &&
1543 (c
->replstate
== REDIS_REPL_NONE
||
1544 c
->replstate
== REDIS_REPL_ONLINE
) &&
1545 aeCreateFileEvent(server
.el
, c
->fd
, AE_WRITABLE
,
1546 sendReplyToClient
, c
, NULL
) == AE_ERR
) return;
1547 if (!listAddNodeTail(c
->reply
,obj
)) oom("listAddNodeTail");
1551 static void addReplySds(redisClient
*c
, sds s
) {
1552 robj
*o
= createObject(REDIS_STRING
,s
);
1557 static void acceptHandler(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1562 REDIS_NOTUSED(mask
);
1563 REDIS_NOTUSED(privdata
);
1565 cfd
= anetAccept(server
.neterr
, fd
, cip
, &cport
);
1566 if (cfd
== AE_ERR
) {
1567 redisLog(REDIS_DEBUG
,"Accepting client connection: %s", server
.neterr
);
1570 redisLog(REDIS_DEBUG
,"Accepted %s:%d", cip
, cport
);
1571 if ((c
= createClient(cfd
)) == NULL
) {
1572 redisLog(REDIS_WARNING
,"Error allocating resoures for the client");
1573 close(cfd
); /* May be already closed, just ingore errors */
1576 /* If maxclient directive is set and this is one client more... close the
1577 * connection. Note that we create the client instead to check before
1578 * for this condition, since now the socket is already set in nonblocking
1579 * mode and we can send an error for free using the Kernel I/O */
1580 if (server
.maxclients
&& listLength(server
.clients
) > server
.maxclients
) {
1581 char *err
= "-ERR max number of clients reached\r\n";
1583 /* That's a best effort error message, don't check write errors */
1584 (void) write(c
->fd
,err
,strlen(err
));
1588 server
.stat_numconnections
++;
1591 /* ======================= Redis objects implementation ===================== */
1593 static robj
*createObject(int type
, void *ptr
) {
1596 if (listLength(server
.objfreelist
)) {
1597 listNode
*head
= listFirst(server
.objfreelist
);
1598 o
= listNodeValue(head
);
1599 listDelNode(server
.objfreelist
,head
);
1601 o
= zmalloc(sizeof(*o
));
1603 if (!o
) oom("createObject");
1610 static robj
*createStringObject(char *ptr
, size_t len
) {
1611 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
1614 static robj
*createListObject(void) {
1615 list
*l
= listCreate();
1617 if (!l
) oom("listCreate");
1618 listSetFreeMethod(l
,decrRefCount
);
1619 return createObject(REDIS_LIST
,l
);
1622 static robj
*createSetObject(void) {
1623 dict
*d
= dictCreate(&setDictType
,NULL
);
1624 if (!d
) oom("dictCreate");
1625 return createObject(REDIS_SET
,d
);
1628 static void freeStringObject(robj
*o
) {
1632 static void freeListObject(robj
*o
) {
1633 listRelease((list
*) o
->ptr
);
1636 static void freeSetObject(robj
*o
) {
1637 dictRelease((dict
*) o
->ptr
);
1640 static void freeHashObject(robj
*o
) {
1641 dictRelease((dict
*) o
->ptr
);
1644 static void incrRefCount(robj
*o
) {
1646 #ifdef DEBUG_REFCOUNT
1647 if (o
->type
== REDIS_STRING
)
1648 printf("Increment '%s'(%p), now is: %d\n",o
->ptr
,o
,o
->refcount
);
1652 static void decrRefCount(void *obj
) {
1655 #ifdef DEBUG_REFCOUNT
1656 if (o
->type
== REDIS_STRING
)
1657 printf("Decrement '%s'(%p), now is: %d\n",o
->ptr
,o
,o
->refcount
-1);
1659 if (--(o
->refcount
) == 0) {
1661 case REDIS_STRING
: freeStringObject(o
); break;
1662 case REDIS_LIST
: freeListObject(o
); break;
1663 case REDIS_SET
: freeSetObject(o
); break;
1664 case REDIS_HASH
: freeHashObject(o
); break;
1665 default: assert(0 != 0); break;
1667 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
1668 !listAddNodeHead(server
.objfreelist
,o
))
1673 /* Try to share an object against the shared objects pool */
1674 static robj
*tryObjectSharing(robj
*o
) {
1675 struct dictEntry
*de
;
1678 if (o
== NULL
|| server
.shareobjects
== 0) return o
;
1680 assert(o
->type
== REDIS_STRING
);
1681 de
= dictFind(server
.sharingpool
,o
);
1683 robj
*shared
= dictGetEntryKey(de
);
1685 c
= ((unsigned long) dictGetEntryVal(de
))+1;
1686 dictGetEntryVal(de
) = (void*) c
;
1687 incrRefCount(shared
);
1691 /* Here we are using a stream algorihtm: Every time an object is
1692 * shared we increment its count, everytime there is a miss we
1693 * recrement the counter of a random object. If this object reaches
1694 * zero we remove the object and put the current object instead. */
1695 if (dictSize(server
.sharingpool
) >=
1696 server
.sharingpoolsize
) {
1697 de
= dictGetRandomKey(server
.sharingpool
);
1699 c
= ((unsigned long) dictGetEntryVal(de
))-1;
1700 dictGetEntryVal(de
) = (void*) c
;
1702 dictDelete(server
.sharingpool
,de
->key
);
1705 c
= 0; /* If the pool is empty we want to add this object */
1710 retval
= dictAdd(server
.sharingpool
,o
,(void*)1);
1711 assert(retval
== DICT_OK
);
1718 static robj
*lookupKey(redisDb
*db
, robj
*key
) {
1719 dictEntry
*de
= dictFind(db
->dict
,key
);
1720 return de
? dictGetEntryVal(de
) : NULL
;
1723 static robj
*lookupKeyRead(redisDb
*db
, robj
*key
) {
1724 expireIfNeeded(db
,key
);
1725 return lookupKey(db
,key
);
1728 static robj
*lookupKeyWrite(redisDb
*db
, robj
*key
) {
1729 deleteIfVolatile(db
,key
);
1730 return lookupKey(db
,key
);
1733 static int deleteKey(redisDb
*db
, robj
*key
) {
1736 /* We need to protect key from destruction: after the first dictDelete()
1737 * it may happen that 'key' is no longer valid if we don't increment
1738 * it's count. This may happen when we get the object reference directly
1739 * from the hash table with dictRandomKey() or dict iterators */
1741 if (dictSize(db
->expires
)) dictDelete(db
->expires
,key
);
1742 retval
= dictDelete(db
->dict
,key
);
1745 return retval
== DICT_OK
;
1748 /*============================ DB saving/loading ============================ */
1750 static int rdbSaveType(FILE *fp
, unsigned char type
) {
1751 if (fwrite(&type
,1,1,fp
) == 0) return -1;
1755 static int rdbSaveTime(FILE *fp
, time_t t
) {
1756 int32_t t32
= (int32_t) t
;
1757 if (fwrite(&t32
,4,1,fp
) == 0) return -1;
1761 /* check rdbLoadLen() comments for more info */
1762 static int rdbSaveLen(FILE *fp
, uint32_t len
) {
1763 unsigned char buf
[2];
1766 /* Save a 6 bit len */
1767 buf
[0] = (len
&0xFF)|(REDIS_RDB_6BITLEN
<<6);
1768 if (fwrite(buf
,1,1,fp
) == 0) return -1;
1769 } else if (len
< (1<<14)) {
1770 /* Save a 14 bit len */
1771 buf
[0] = ((len
>>8)&0xFF)|(REDIS_RDB_14BITLEN
<<6);
1773 if (fwrite(buf
,2,1,fp
) == 0) return -1;
1775 /* Save a 32 bit len */
1776 buf
[0] = (REDIS_RDB_32BITLEN
<<6);
1777 if (fwrite(buf
,1,1,fp
) == 0) return -1;
1779 if (fwrite(&len
,4,1,fp
) == 0) return -1;
1784 /* String objects in the form "2391" "-100" without any space and with a
1785 * range of values that can fit in an 8, 16 or 32 bit signed value can be
1786 * encoded as integers to save space */
1787 static int rdbTryIntegerEncoding(sds s
, unsigned char *enc
) {
1789 char *endptr
, buf
[32];
1791 /* Check if it's possible to encode this value as a number */
1792 value
= strtoll(s
, &endptr
, 10);
1793 if (endptr
[0] != '\0') return 0;
1794 snprintf(buf
,32,"%lld",value
);
1796 /* If the number converted back into a string is not identical
1797 * then it's not possible to encode the string as integer */
1798 if (strlen(buf
) != sdslen(s
) || memcmp(buf
,s
,sdslen(s
))) return 0;
1800 /* Finally check if it fits in our ranges */
1801 if (value
>= -(1<<7) && value
<= (1<<7)-1) {
1802 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT8
;
1803 enc
[1] = value
&0xFF;
1805 } else if (value
>= -(1<<15) && value
<= (1<<15)-1) {
1806 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT16
;
1807 enc
[1] = value
&0xFF;
1808 enc
[2] = (value
>>8)&0xFF;
1810 } else if (value
>= -((long long)1<<31) && value
<= ((long long)1<<31)-1) {
1811 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT32
;
1812 enc
[1] = value
&0xFF;
1813 enc
[2] = (value
>>8)&0xFF;
1814 enc
[3] = (value
>>16)&0xFF;
1815 enc
[4] = (value
>>24)&0xFF;
1822 static int rdbSaveLzfStringObject(FILE *fp
, robj
*obj
) {
1823 unsigned int comprlen
, outlen
;
1827 /* We require at least four bytes compression for this to be worth it */
1828 outlen
= sdslen(obj
->ptr
)-4;
1829 if (outlen
<= 0) return 0;
1830 if ((out
= zmalloc(outlen
+1)) == NULL
) return 0;
1831 comprlen
= lzf_compress(obj
->ptr
, sdslen(obj
->ptr
), out
, outlen
);
1832 if (comprlen
== 0) {
1836 /* Data compressed! Let's save it on disk */
1837 byte
= (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_LZF
;
1838 if (fwrite(&byte
,1,1,fp
) == 0) goto writeerr
;
1839 if (rdbSaveLen(fp
,comprlen
) == -1) goto writeerr
;
1840 if (rdbSaveLen(fp
,sdslen(obj
->ptr
)) == -1) goto writeerr
;
1841 if (fwrite(out
,comprlen
,1,fp
) == 0) goto writeerr
;
1850 /* Save a string objet as [len][data] on disk. If the object is a string
1851 * representation of an integer value we try to safe it in a special form */
1852 static int rdbSaveStringObject(FILE *fp
, robj
*obj
) {
1853 size_t len
= sdslen(obj
->ptr
);
1856 /* Try integer encoding */
1858 unsigned char buf
[5];
1859 if ((enclen
= rdbTryIntegerEncoding(obj
->ptr
,buf
)) > 0) {
1860 if (fwrite(buf
,enclen
,1,fp
) == 0) return -1;
1865 /* Try LZF compression - under 20 bytes it's unable to compress even
1866 * aaaaaaaaaaaaaaaaaa so skip it */
1867 if (1 && len
> 20) {
1870 retval
= rdbSaveLzfStringObject(fp
,obj
);
1871 if (retval
== -1) return -1;
1872 if (retval
> 0) return 0;
1873 /* retval == 0 means data can't be compressed, save the old way */
1876 /* Store verbatim */
1877 if (rdbSaveLen(fp
,len
) == -1) return -1;
1878 if (len
&& fwrite(obj
->ptr
,len
,1,fp
) == 0) return -1;
1882 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
1883 static int rdbSave(char *filename
) {
1884 dictIterator
*di
= NULL
;
1889 time_t now
= time(NULL
);
1891 snprintf(tmpfile
,256,"temp-%d.%ld.rdb",(int)time(NULL
),(long int)random());
1892 fp
= fopen(tmpfile
,"w");
1894 redisLog(REDIS_WARNING
, "Failed saving the DB: %s", strerror(errno
));
1897 if (fwrite("REDIS0001",9,1,fp
) == 0) goto werr
;
1898 for (j
= 0; j
< server
.dbnum
; j
++) {
1899 redisDb
*db
= server
.db
+j
;
1901 if (dictSize(d
) == 0) continue;
1902 di
= dictGetIterator(d
);
1908 /* Write the SELECT DB opcode */
1909 if (rdbSaveType(fp
,REDIS_SELECTDB
) == -1) goto werr
;
1910 if (rdbSaveLen(fp
,j
) == -1) goto werr
;
1912 /* Iterate this DB writing every entry */
1913 while((de
= dictNext(di
)) != NULL
) {
1914 robj
*key
= dictGetEntryKey(de
);
1915 robj
*o
= dictGetEntryVal(de
);
1916 time_t expiretime
= getExpire(db
,key
);
1918 /* Save the expire time */
1919 if (expiretime
!= -1) {
1920 /* If this key is already expired skip it */
1921 if (expiretime
< now
) continue;
1922 if (rdbSaveType(fp
,REDIS_EXPIRETIME
) == -1) goto werr
;
1923 if (rdbSaveTime(fp
,expiretime
) == -1) goto werr
;
1925 /* Save the key and associated value */
1926 if (rdbSaveType(fp
,o
->type
) == -1) goto werr
;
1927 if (rdbSaveStringObject(fp
,key
) == -1) goto werr
;
1928 if (o
->type
== REDIS_STRING
) {
1929 /* Save a string value */
1930 if (rdbSaveStringObject(fp
,o
) == -1) goto werr
;
1931 } else if (o
->type
== REDIS_LIST
) {
1932 /* Save a list value */
1933 list
*list
= o
->ptr
;
1937 if (rdbSaveLen(fp
,listLength(list
)) == -1) goto werr
;
1938 while((ln
= listYield(list
))) {
1939 robj
*eleobj
= listNodeValue(ln
);
1941 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
1943 } else if (o
->type
== REDIS_SET
) {
1944 /* Save a set value */
1946 dictIterator
*di
= dictGetIterator(set
);
1949 if (!set
) oom("dictGetIteraotr");
1950 if (rdbSaveLen(fp
,dictSize(set
)) == -1) goto werr
;
1951 while((de
= dictNext(di
)) != NULL
) {
1952 robj
*eleobj
= dictGetEntryKey(de
);
1954 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
1956 dictReleaseIterator(di
);
1961 dictReleaseIterator(di
);
1964 if (rdbSaveType(fp
,REDIS_EOF
) == -1) goto werr
;
1966 /* Make sure data will not remain on the OS's output buffers */
1971 /* Use RENAME to make sure the DB file is changed atomically only
1972 * if the generate DB file is ok. */
1973 if (rename(tmpfile
,filename
) == -1) {
1974 redisLog(REDIS_WARNING
,"Error moving temp DB file on the final destionation: %s", strerror(errno
));
1978 redisLog(REDIS_NOTICE
,"DB saved on disk");
1980 server
.lastsave
= time(NULL
);
1986 redisLog(REDIS_WARNING
,"Write error saving DB on disk: %s", strerror(errno
));
1987 if (di
) dictReleaseIterator(di
);
1991 static int rdbSaveBackground(char *filename
) {
1994 if (server
.bgsaveinprogress
) return REDIS_ERR
;
1995 if ((childpid
= fork()) == 0) {
1998 if (rdbSave(filename
) == REDIS_OK
) {
2005 if (childpid
== -1) {
2006 redisLog(REDIS_WARNING
,"Can't save in background: fork: %s",
2010 redisLog(REDIS_NOTICE
,"Background saving started by pid %d",childpid
);
2011 server
.bgsaveinprogress
= 1;
2012 server
.bgsavechildpid
= childpid
;
2015 return REDIS_OK
; /* unreached */
2018 static int rdbLoadType(FILE *fp
) {
2020 if (fread(&type
,1,1,fp
) == 0) return -1;
2024 static time_t rdbLoadTime(FILE *fp
) {
2026 if (fread(&t32
,4,1,fp
) == 0) return -1;
2027 return (time_t) t32
;
2030 /* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
2031 * of this file for a description of how this are stored on disk.
2033 * isencoded is set to 1 if the readed length is not actually a length but
2034 * an "encoding type", check the above comments for more info */
2035 static uint32_t rdbLoadLen(FILE *fp
, int rdbver
, int *isencoded
) {
2036 unsigned char buf
[2];
2039 if (isencoded
) *isencoded
= 0;
2041 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
2046 if (fread(buf
,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2047 type
= (buf
[0]&0xC0)>>6;
2048 if (type
== REDIS_RDB_6BITLEN
) {
2049 /* Read a 6 bit len */
2051 } else if (type
== REDIS_RDB_ENCVAL
) {
2052 /* Read a 6 bit len encoding type */
2053 if (isencoded
) *isencoded
= 1;
2055 } else if (type
== REDIS_RDB_14BITLEN
) {
2056 /* Read a 14 bit len */
2057 if (fread(buf
+1,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2058 return ((buf
[0]&0x3F)<<8)|buf
[1];
2060 /* Read a 32 bit len */
2061 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
2067 static robj
*rdbLoadIntegerObject(FILE *fp
, int enctype
) {
2068 unsigned char enc
[4];
2071 if (enctype
== REDIS_RDB_ENC_INT8
) {
2072 if (fread(enc
,1,1,fp
) == 0) return NULL
;
2073 val
= (signed char)enc
[0];
2074 } else if (enctype
== REDIS_RDB_ENC_INT16
) {
2076 if (fread(enc
,2,1,fp
) == 0) return NULL
;
2077 v
= enc
[0]|(enc
[1]<<8);
2079 } else if (enctype
== REDIS_RDB_ENC_INT32
) {
2081 if (fread(enc
,4,1,fp
) == 0) return NULL
;
2082 v
= enc
[0]|(enc
[1]<<8)|(enc
[2]<<16)|(enc
[3]<<24);
2085 val
= 0; /* anti-warning */
2088 return createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",val
));
2091 static robj
*rdbLoadLzfStringObject(FILE*fp
, int rdbver
) {
2092 unsigned int len
, clen
;
2093 unsigned char *c
= NULL
;
2096 if ((clen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2097 if ((len
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2098 if ((c
= zmalloc(clen
)) == NULL
) goto err
;
2099 if ((val
= sdsnewlen(NULL
,len
)) == NULL
) goto err
;
2100 if (fread(c
,clen
,1,fp
) == 0) goto err
;
2101 if (lzf_decompress(c
,clen
,val
,len
) == 0) goto err
;
2103 return createObject(REDIS_STRING
,val
);
2110 static robj
*rdbLoadStringObject(FILE*fp
, int rdbver
) {
2115 len
= rdbLoadLen(fp
,rdbver
,&isencoded
);
2118 case REDIS_RDB_ENC_INT8
:
2119 case REDIS_RDB_ENC_INT16
:
2120 case REDIS_RDB_ENC_INT32
:
2121 return tryObjectSharing(rdbLoadIntegerObject(fp
,len
));
2122 case REDIS_RDB_ENC_LZF
:
2123 return tryObjectSharing(rdbLoadLzfStringObject(fp
,rdbver
));
2129 if (len
== REDIS_RDB_LENERR
) return NULL
;
2130 val
= sdsnewlen(NULL
,len
);
2131 if (len
&& fread(val
,len
,1,fp
) == 0) {
2135 return tryObjectSharing(createObject(REDIS_STRING
,val
));
2138 static int rdbLoad(char *filename
) {
2140 robj
*keyobj
= NULL
;
2142 int type
, retval
, rdbver
;
2143 dict
*d
= server
.db
[0].dict
;
2144 redisDb
*db
= server
.db
+0;
2146 time_t expiretime
= -1, now
= time(NULL
);
2148 fp
= fopen(filename
,"r");
2149 if (!fp
) return REDIS_ERR
;
2150 if (fread(buf
,9,1,fp
) == 0) goto eoferr
;
2152 if (memcmp(buf
,"REDIS",5) != 0) {
2154 redisLog(REDIS_WARNING
,"Wrong signature trying to load DB from file");
2157 rdbver
= atoi(buf
+5);
2160 redisLog(REDIS_WARNING
,"Can't handle RDB format version %d",rdbver
);
2167 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
2168 if (type
== REDIS_EXPIRETIME
) {
2169 if ((expiretime
= rdbLoadTime(fp
)) == -1) goto eoferr
;
2170 /* We read the time so we need to read the object type again */
2171 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
2173 if (type
== REDIS_EOF
) break;
2174 /* Handle SELECT DB opcode as a special case */
2175 if (type
== REDIS_SELECTDB
) {
2176 if ((dbid
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2178 if (dbid
>= (unsigned)server
.dbnum
) {
2179 redisLog(REDIS_WARNING
,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server
.dbnum
);
2182 db
= server
.db
+dbid
;
2187 if ((keyobj
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2189 if (type
== REDIS_STRING
) {
2190 /* Read string value */
2191 if ((o
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2192 } else if (type
== REDIS_LIST
|| type
== REDIS_SET
) {
2193 /* Read list/set value */
2196 if ((listlen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2198 o
= (type
== REDIS_LIST
) ? createListObject() : createSetObject();
2199 /* Load every single element of the list/set */
2203 if ((ele
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2204 if (type
== REDIS_LIST
) {
2205 if (!listAddNodeTail((list
*)o
->ptr
,ele
))
2206 oom("listAddNodeTail");
2208 if (dictAdd((dict
*)o
->ptr
,ele
,NULL
) == DICT_ERR
)
2215 /* Add the new object in the hash table */
2216 retval
= dictAdd(d
,keyobj
,o
);
2217 if (retval
== DICT_ERR
) {
2218 redisLog(REDIS_WARNING
,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj
->ptr
);
2221 /* Set the expire time if needed */
2222 if (expiretime
!= -1) {
2223 setExpire(db
,keyobj
,expiretime
);
2224 /* Delete this key if already expired */
2225 if (expiretime
< now
) deleteKey(db
,keyobj
);
2233 eoferr
: /* unexpected end of file is handled here with a fatal exit */
2234 if (keyobj
) decrRefCount(keyobj
);
2235 redisLog(REDIS_WARNING
,"Short read or OOM loading DB. Unrecoverable error, exiting now.");
2237 return REDIS_ERR
; /* Just to avoid warning */
2240 /*================================== Commands =============================== */
2242 static void authCommand(redisClient
*c
) {
2243 if (!server
.requirepass
|| !strcmp(c
->argv
[1]->ptr
, server
.requirepass
)) {
2244 c
->authenticated
= 1;
2245 addReply(c
,shared
.ok
);
2247 c
->authenticated
= 0;
2248 addReply(c
,shared
.err
);
2252 static void pingCommand(redisClient
*c
) {
2253 addReply(c
,shared
.pong
);
2256 static void echoCommand(redisClient
*c
) {
2257 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",
2258 (int)sdslen(c
->argv
[1]->ptr
)));
2259 addReply(c
,c
->argv
[1]);
2260 addReply(c
,shared
.crlf
);
2263 /*=================================== Strings =============================== */
2265 static void setGenericCommand(redisClient
*c
, int nx
) {
2268 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2269 if (retval
== DICT_ERR
) {
2271 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2272 incrRefCount(c
->argv
[2]);
2274 addReply(c
,shared
.czero
);
2278 incrRefCount(c
->argv
[1]);
2279 incrRefCount(c
->argv
[2]);
2282 removeExpire(c
->db
,c
->argv
[1]);
2283 addReply(c
, nx
? shared
.cone
: shared
.ok
);
2286 static void setCommand(redisClient
*c
) {
2287 setGenericCommand(c
,0);
2290 static void setnxCommand(redisClient
*c
) {
2291 setGenericCommand(c
,1);
2294 static void getCommand(redisClient
*c
) {
2295 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2298 addReply(c
,shared
.nullbulk
);
2300 if (o
->type
!= REDIS_STRING
) {
2301 addReply(c
,shared
.wrongtypeerr
);
2303 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(o
->ptr
)));
2305 addReply(c
,shared
.crlf
);
2310 static void getSetCommand(redisClient
*c
) {
2312 if (dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]) == DICT_ERR
) {
2313 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2315 incrRefCount(c
->argv
[1]);
2317 incrRefCount(c
->argv
[2]);
2319 removeExpire(c
->db
,c
->argv
[1]);
2322 static void mgetCommand(redisClient
*c
) {
2325 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",c
->argc
-1));
2326 for (j
= 1; j
< c
->argc
; j
++) {
2327 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
2329 addReply(c
,shared
.nullbulk
);
2331 if (o
->type
!= REDIS_STRING
) {
2332 addReply(c
,shared
.nullbulk
);
2334 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(o
->ptr
)));
2336 addReply(c
,shared
.crlf
);
2342 static void incrDecrCommand(redisClient
*c
, long long incr
) {
2347 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2351 if (o
->type
!= REDIS_STRING
) {
2356 value
= strtoll(o
->ptr
, &eptr
, 10);
2361 o
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",value
));
2362 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],o
);
2363 if (retval
== DICT_ERR
) {
2364 dictReplace(c
->db
->dict
,c
->argv
[1],o
);
2365 removeExpire(c
->db
,c
->argv
[1]);
2367 incrRefCount(c
->argv
[1]);
2370 addReply(c
,shared
.colon
);
2372 addReply(c
,shared
.crlf
);
2375 static void incrCommand(redisClient
*c
) {
2376 incrDecrCommand(c
,1);
2379 static void decrCommand(redisClient
*c
) {
2380 incrDecrCommand(c
,-1);
2383 static void incrbyCommand(redisClient
*c
) {
2384 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
2385 incrDecrCommand(c
,incr
);
2388 static void decrbyCommand(redisClient
*c
) {
2389 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
2390 incrDecrCommand(c
,-incr
);
2393 /* ========================= Type agnostic commands ========================= */
2395 static void delCommand(redisClient
*c
) {
2398 for (j
= 1; j
< c
->argc
; j
++) {
2399 if (deleteKey(c
->db
,c
->argv
[j
])) {
2406 addReply(c
,shared
.czero
);
2409 addReply(c
,shared
.cone
);
2412 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",deleted
));
2417 static void existsCommand(redisClient
*c
) {
2418 addReply(c
,lookupKeyRead(c
->db
,c
->argv
[1]) ? shared
.cone
: shared
.czero
);
2421 static void selectCommand(redisClient
*c
) {
2422 int id
= atoi(c
->argv
[1]->ptr
);
2424 if (selectDb(c
,id
) == REDIS_ERR
) {
2425 addReplySds(c
,sdsnew("-ERR invalid DB index\r\n"));
2427 addReply(c
,shared
.ok
);
2431 static void randomkeyCommand(redisClient
*c
) {
2435 de
= dictGetRandomKey(c
->db
->dict
);
2436 if (!de
|| expireIfNeeded(c
->db
,dictGetEntryKey(de
)) == 0) break;
2439 addReply(c
,shared
.plus
);
2440 addReply(c
,shared
.crlf
);
2442 addReply(c
,shared
.plus
);
2443 addReply(c
,dictGetEntryKey(de
));
2444 addReply(c
,shared
.crlf
);
2448 static void keysCommand(redisClient
*c
) {
2451 sds pattern
= c
->argv
[1]->ptr
;
2452 int plen
= sdslen(pattern
);
2453 int numkeys
= 0, keyslen
= 0;
2454 robj
*lenobj
= createObject(REDIS_STRING
,NULL
);
2456 di
= dictGetIterator(c
->db
->dict
);
2457 if (!di
) oom("dictGetIterator");
2459 decrRefCount(lenobj
);
2460 while((de
= dictNext(di
)) != NULL
) {
2461 robj
*keyobj
= dictGetEntryKey(de
);
2463 sds key
= keyobj
->ptr
;
2464 if ((pattern
[0] == '*' && pattern
[1] == '\0') ||
2465 stringmatchlen(pattern
,plen
,key
,sdslen(key
),0)) {
2466 if (expireIfNeeded(c
->db
,keyobj
) == 0) {
2468 addReply(c
,shared
.space
);
2471 keyslen
+= sdslen(key
);
2475 dictReleaseIterator(di
);
2476 lenobj
->ptr
= sdscatprintf(sdsempty(),"$%lu\r\n",keyslen
+(numkeys
? (numkeys
-1) : 0));
2477 addReply(c
,shared
.crlf
);
2480 static void dbsizeCommand(redisClient
*c
) {
2482 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c
->db
->dict
)));
2485 static void lastsaveCommand(redisClient
*c
) {
2487 sdscatprintf(sdsempty(),":%lu\r\n",server
.lastsave
));
2490 static void typeCommand(redisClient
*c
) {
2494 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2499 case REDIS_STRING
: type
= "+string"; break;
2500 case REDIS_LIST
: type
= "+list"; break;
2501 case REDIS_SET
: type
= "+set"; break;
2502 default: type
= "unknown"; break;
2505 addReplySds(c
,sdsnew(type
));
2506 addReply(c
,shared
.crlf
);
2509 static void saveCommand(redisClient
*c
) {
2510 if (server
.bgsaveinprogress
) {
2511 addReplySds(c
,sdsnew("-ERR background save in progress\r\n"));
2514 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
2515 addReply(c
,shared
.ok
);
2517 addReply(c
,shared
.err
);
2521 static void bgsaveCommand(redisClient
*c
) {
2522 if (server
.bgsaveinprogress
) {
2523 addReplySds(c
,sdsnew("-ERR background save already in progress\r\n"));
2526 if (rdbSaveBackground(server
.dbfilename
) == REDIS_OK
) {
2527 addReply(c
,shared
.ok
);
2529 addReply(c
,shared
.err
);
2533 static void shutdownCommand(redisClient
*c
) {
2534 redisLog(REDIS_WARNING
,"User requested shutdown, saving DB...");
2535 if (server
.bgsaveinprogress
) {
2536 redisLog(REDIS_WARNING
,"There is a live saving child. Killing it!");
2537 signal(SIGCHLD
, SIG_IGN
);
2538 kill(server
.bgsavechildpid
,SIGKILL
);
2540 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
2541 if (server
.daemonize
)
2542 unlink(server
.pidfile
);
2543 redisLog(REDIS_WARNING
,"%zu bytes used at exit",zmalloc_used_memory());
2544 redisLog(REDIS_WARNING
,"Server exit now, bye bye...");
2547 signal(SIGCHLD
, SIG_DFL
);
2548 redisLog(REDIS_WARNING
,"Error trying to save the DB, can't exit");
2549 addReplySds(c
,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
2553 static void renameGenericCommand(redisClient
*c
, int nx
) {
2556 /* To use the same key as src and dst is probably an error */
2557 if (sdscmp(c
->argv
[1]->ptr
,c
->argv
[2]->ptr
) == 0) {
2558 addReply(c
,shared
.sameobjecterr
);
2562 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2564 addReply(c
,shared
.nokeyerr
);
2568 deleteIfVolatile(c
->db
,c
->argv
[2]);
2569 if (dictAdd(c
->db
->dict
,c
->argv
[2],o
) == DICT_ERR
) {
2572 addReply(c
,shared
.czero
);
2575 dictReplace(c
->db
->dict
,c
->argv
[2],o
);
2577 incrRefCount(c
->argv
[2]);
2579 deleteKey(c
->db
,c
->argv
[1]);
2581 addReply(c
,nx
? shared
.cone
: shared
.ok
);
2584 static void renameCommand(redisClient
*c
) {
2585 renameGenericCommand(c
,0);
2588 static void renamenxCommand(redisClient
*c
) {
2589 renameGenericCommand(c
,1);
2592 static void moveCommand(redisClient
*c
) {
2597 /* Obtain source and target DB pointers */
2600 if (selectDb(c
,atoi(c
->argv
[2]->ptr
)) == REDIS_ERR
) {
2601 addReply(c
,shared
.outofrangeerr
);
2605 selectDb(c
,srcid
); /* Back to the source DB */
2607 /* If the user is moving using as target the same
2608 * DB as the source DB it is probably an error. */
2610 addReply(c
,shared
.sameobjecterr
);
2614 /* Check if the element exists and get a reference */
2615 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2617 addReply(c
,shared
.czero
);
2621 /* Try to add the element to the target DB */
2622 deleteIfVolatile(dst
,c
->argv
[1]);
2623 if (dictAdd(dst
->dict
,c
->argv
[1],o
) == DICT_ERR
) {
2624 addReply(c
,shared
.czero
);
2627 incrRefCount(c
->argv
[1]);
2630 /* OK! key moved, free the entry in the source DB */
2631 deleteKey(src
,c
->argv
[1]);
2633 addReply(c
,shared
.cone
);
2636 /* =================================== Lists ================================ */
2637 static void pushGenericCommand(redisClient
*c
, int where
) {
2641 lobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2643 lobj
= createListObject();
2645 if (where
== REDIS_HEAD
) {
2646 if (!listAddNodeHead(list
,c
->argv
[2])) oom("listAddNodeHead");
2648 if (!listAddNodeTail(list
,c
->argv
[2])) oom("listAddNodeTail");
2650 dictAdd(c
->db
->dict
,c
->argv
[1],lobj
);
2651 incrRefCount(c
->argv
[1]);
2652 incrRefCount(c
->argv
[2]);
2654 if (lobj
->type
!= REDIS_LIST
) {
2655 addReply(c
,shared
.wrongtypeerr
);
2659 if (where
== REDIS_HEAD
) {
2660 if (!listAddNodeHead(list
,c
->argv
[2])) oom("listAddNodeHead");
2662 if (!listAddNodeTail(list
,c
->argv
[2])) oom("listAddNodeTail");
2664 incrRefCount(c
->argv
[2]);
2667 addReply(c
,shared
.ok
);
2670 static void lpushCommand(redisClient
*c
) {
2671 pushGenericCommand(c
,REDIS_HEAD
);
2674 static void rpushCommand(redisClient
*c
) {
2675 pushGenericCommand(c
,REDIS_TAIL
);
2678 static void llenCommand(redisClient
*c
) {
2682 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2684 addReply(c
,shared
.czero
);
2687 if (o
->type
!= REDIS_LIST
) {
2688 addReply(c
,shared
.wrongtypeerr
);
2691 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",listLength(l
)));
2696 static void lindexCommand(redisClient
*c
) {
2698 int index
= atoi(c
->argv
[2]->ptr
);
2700 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2702 addReply(c
,shared
.nullbulk
);
2704 if (o
->type
!= REDIS_LIST
) {
2705 addReply(c
,shared
.wrongtypeerr
);
2707 list
*list
= o
->ptr
;
2710 ln
= listIndex(list
, index
);
2712 addReply(c
,shared
.nullbulk
);
2714 robj
*ele
= listNodeValue(ln
);
2715 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele
->ptr
)));
2717 addReply(c
,shared
.crlf
);
2723 static void lsetCommand(redisClient
*c
) {
2725 int index
= atoi(c
->argv
[2]->ptr
);
2727 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2729 addReply(c
,shared
.nokeyerr
);
2731 if (o
->type
!= REDIS_LIST
) {
2732 addReply(c
,shared
.wrongtypeerr
);
2734 list
*list
= o
->ptr
;
2737 ln
= listIndex(list
, index
);
2739 addReply(c
,shared
.outofrangeerr
);
2741 robj
*ele
= listNodeValue(ln
);
2744 listNodeValue(ln
) = c
->argv
[3];
2745 incrRefCount(c
->argv
[3]);
2746 addReply(c
,shared
.ok
);
2753 static void popGenericCommand(redisClient
*c
, int where
) {
2756 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2758 addReply(c
,shared
.nullbulk
);
2760 if (o
->type
!= REDIS_LIST
) {
2761 addReply(c
,shared
.wrongtypeerr
);
2763 list
*list
= o
->ptr
;
2766 if (where
== REDIS_HEAD
)
2767 ln
= listFirst(list
);
2769 ln
= listLast(list
);
2772 addReply(c
,shared
.nullbulk
);
2774 robj
*ele
= listNodeValue(ln
);
2775 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele
->ptr
)));
2777 addReply(c
,shared
.crlf
);
2778 listDelNode(list
,ln
);
2785 static void lpopCommand(redisClient
*c
) {
2786 popGenericCommand(c
,REDIS_HEAD
);
2789 static void rpopCommand(redisClient
*c
) {
2790 popGenericCommand(c
,REDIS_TAIL
);
2793 static void lrangeCommand(redisClient
*c
) {
2795 int start
= atoi(c
->argv
[2]->ptr
);
2796 int end
= atoi(c
->argv
[3]->ptr
);
2798 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2800 addReply(c
,shared
.nullmultibulk
);
2802 if (o
->type
!= REDIS_LIST
) {
2803 addReply(c
,shared
.wrongtypeerr
);
2805 list
*list
= o
->ptr
;
2807 int llen
= listLength(list
);
2811 /* convert negative indexes */
2812 if (start
< 0) start
= llen
+start
;
2813 if (end
< 0) end
= llen
+end
;
2814 if (start
< 0) start
= 0;
2815 if (end
< 0) end
= 0;
2817 /* indexes sanity checks */
2818 if (start
> end
|| start
>= llen
) {
2819 /* Out of range start or start > end result in empty list */
2820 addReply(c
,shared
.emptymultibulk
);
2823 if (end
>= llen
) end
= llen
-1;
2824 rangelen
= (end
-start
)+1;
2826 /* Return the result in form of a multi-bulk reply */
2827 ln
= listIndex(list
, start
);
2828 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",rangelen
));
2829 for (j
= 0; j
< rangelen
; j
++) {
2830 ele
= listNodeValue(ln
);
2831 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele
->ptr
)));
2833 addReply(c
,shared
.crlf
);
2840 static void ltrimCommand(redisClient
*c
) {
2842 int start
= atoi(c
->argv
[2]->ptr
);
2843 int end
= atoi(c
->argv
[3]->ptr
);
2845 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2847 addReply(c
,shared
.nokeyerr
);
2849 if (o
->type
!= REDIS_LIST
) {
2850 addReply(c
,shared
.wrongtypeerr
);
2852 list
*list
= o
->ptr
;
2854 int llen
= listLength(list
);
2855 int j
, ltrim
, rtrim
;
2857 /* convert negative indexes */
2858 if (start
< 0) start
= llen
+start
;
2859 if (end
< 0) end
= llen
+end
;
2860 if (start
< 0) start
= 0;
2861 if (end
< 0) end
= 0;
2863 /* indexes sanity checks */
2864 if (start
> end
|| start
>= llen
) {
2865 /* Out of range start or start > end result in empty list */
2869 if (end
>= llen
) end
= llen
-1;
2874 /* Remove list elements to perform the trim */
2875 for (j
= 0; j
< ltrim
; j
++) {
2876 ln
= listFirst(list
);
2877 listDelNode(list
,ln
);
2879 for (j
= 0; j
< rtrim
; j
++) {
2880 ln
= listLast(list
);
2881 listDelNode(list
,ln
);
2883 addReply(c
,shared
.ok
);
2889 static void lremCommand(redisClient
*c
) {
2892 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2894 addReply(c
,shared
.czero
);
2896 if (o
->type
!= REDIS_LIST
) {
2897 addReply(c
,shared
.wrongtypeerr
);
2899 list
*list
= o
->ptr
;
2900 listNode
*ln
, *next
;
2901 int toremove
= atoi(c
->argv
[2]->ptr
);
2906 toremove
= -toremove
;
2909 ln
= fromtail
? list
->tail
: list
->head
;
2911 robj
*ele
= listNodeValue(ln
);
2913 next
= fromtail
? ln
->prev
: ln
->next
;
2914 if (sdscmp(ele
->ptr
,c
->argv
[3]->ptr
) == 0) {
2915 listDelNode(list
,ln
);
2918 if (toremove
&& removed
== toremove
) break;
2922 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",removed
));
2927 /* ==================================== Sets ================================ */
2929 static void saddCommand(redisClient
*c
) {
2932 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2934 set
= createSetObject();
2935 dictAdd(c
->db
->dict
,c
->argv
[1],set
);
2936 incrRefCount(c
->argv
[1]);
2938 if (set
->type
!= REDIS_SET
) {
2939 addReply(c
,shared
.wrongtypeerr
);
2943 if (dictAdd(set
->ptr
,c
->argv
[2],NULL
) == DICT_OK
) {
2944 incrRefCount(c
->argv
[2]);
2946 addReply(c
,shared
.cone
);
2948 addReply(c
,shared
.czero
);
2952 static void sremCommand(redisClient
*c
) {
2955 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2957 addReply(c
,shared
.czero
);
2959 if (set
->type
!= REDIS_SET
) {
2960 addReply(c
,shared
.wrongtypeerr
);
2963 if (dictDelete(set
->ptr
,c
->argv
[2]) == DICT_OK
) {
2965 addReply(c
,shared
.cone
);
2967 addReply(c
,shared
.czero
);
2972 static void smoveCommand(redisClient
*c
) {
2973 robj
*srcset
, *dstset
;
2975 srcset
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2976 dstset
= lookupKeyWrite(c
->db
,c
->argv
[2]);
2978 /* If the source key does not exist return 0, if it's of the wrong type
2980 if (srcset
== NULL
|| srcset
->type
!= REDIS_SET
) {
2981 addReply(c
, srcset
? shared
.wrongtypeerr
: shared
.czero
);
2984 /* Error if the destination key is not a set as well */
2985 if (dstset
&& dstset
->type
!= REDIS_SET
) {
2986 addReply(c
,shared
.wrongtypeerr
);
2989 /* Remove the element from the source set */
2990 if (dictDelete(srcset
->ptr
,c
->argv
[3]) == DICT_ERR
) {
2991 /* Key not found in the src set! return zero */
2992 addReply(c
,shared
.czero
);
2996 /* Add the element to the destination set */
2998 dstset
= createSetObject();
2999 dictAdd(c
->db
->dict
,c
->argv
[2],dstset
);
3000 incrRefCount(c
->argv
[2]);
3002 if (dictAdd(dstset
->ptr
,c
->argv
[3],NULL
) == DICT_OK
)
3003 incrRefCount(c
->argv
[3]);
3004 addReply(c
,shared
.cone
);
3007 static void sismemberCommand(redisClient
*c
) {
3010 set
= lookupKeyRead(c
->db
,c
->argv
[1]);
3012 addReply(c
,shared
.czero
);
3014 if (set
->type
!= REDIS_SET
) {
3015 addReply(c
,shared
.wrongtypeerr
);
3018 if (dictFind(set
->ptr
,c
->argv
[2]))
3019 addReply(c
,shared
.cone
);
3021 addReply(c
,shared
.czero
);
3025 static void scardCommand(redisClient
*c
) {
3029 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3031 addReply(c
,shared
.czero
);
3034 if (o
->type
!= REDIS_SET
) {
3035 addReply(c
,shared
.wrongtypeerr
);
3038 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3044 static int qsortCompareSetsByCardinality(const void *s1
, const void *s2
) {
3045 dict
**d1
= (void*) s1
, **d2
= (void*) s2
;
3047 return dictSize(*d1
)-dictSize(*d2
);
3050 static void sinterGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
) {
3051 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
3054 robj
*lenobj
= NULL
, *dstset
= NULL
;
3055 int j
, cardinality
= 0;
3057 if (!dv
) oom("sinterGenericCommand");
3058 for (j
= 0; j
< setsnum
; j
++) {
3062 lookupKeyWrite(c
->db
,setskeys
[j
]) :
3063 lookupKeyRead(c
->db
,setskeys
[j
]);
3067 deleteKey(c
->db
,dstkey
);
3068 addReply(c
,shared
.ok
);
3070 addReply(c
,shared
.nullmultibulk
);
3074 if (setobj
->type
!= REDIS_SET
) {
3076 addReply(c
,shared
.wrongtypeerr
);
3079 dv
[j
] = setobj
->ptr
;
3081 /* Sort sets from the smallest to largest, this will improve our
3082 * algorithm's performace */
3083 qsort(dv
,setsnum
,sizeof(dict
*),qsortCompareSetsByCardinality
);
3085 /* The first thing we should output is the total number of elements...
3086 * since this is a multi-bulk write, but at this stage we don't know
3087 * the intersection set size, so we use a trick, append an empty object
3088 * to the output list and save the pointer to later modify it with the
3091 lenobj
= createObject(REDIS_STRING
,NULL
);
3093 decrRefCount(lenobj
);
3095 /* If we have a target key where to store the resulting set
3096 * create this key with an empty set inside */
3097 dstset
= createSetObject();
3100 /* Iterate all the elements of the first (smallest) set, and test
3101 * the element against all the other sets, if at least one set does
3102 * not include the element it is discarded */
3103 di
= dictGetIterator(dv
[0]);
3104 if (!di
) oom("dictGetIterator");
3106 while((de
= dictNext(di
)) != NULL
) {
3109 for (j
= 1; j
< setsnum
; j
++)
3110 if (dictFind(dv
[j
],dictGetEntryKey(de
)) == NULL
) break;
3112 continue; /* at least one set does not contain the member */
3113 ele
= dictGetEntryKey(de
);
3115 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(ele
->ptr
)));
3117 addReply(c
,shared
.crlf
);
3120 dictAdd(dstset
->ptr
,ele
,NULL
);
3124 dictReleaseIterator(di
);
3127 /* Store the resulting set into the target */
3128 deleteKey(c
->db
,dstkey
);
3129 dictAdd(c
->db
->dict
,dstkey
,dstset
);
3130 incrRefCount(dstkey
);
3134 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%d\r\n",cardinality
);
3136 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3137 dictSize((dict
*)dstset
->ptr
)));
3143 static void sinterCommand(redisClient
*c
) {
3144 sinterGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
);
3147 static void sinterstoreCommand(redisClient
*c
) {
3148 sinterGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1]);
3151 #define REDIS_OP_UNION 0
3152 #define REDIS_OP_DIFF 1
3154 static void sunionDiffGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
, int op
) {
3155 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
3158 robj
*dstset
= NULL
;
3159 int j
, cardinality
= 0;
3161 if (!dv
) oom("sunionDiffGenericCommand");
3162 for (j
= 0; j
< setsnum
; j
++) {
3166 lookupKeyWrite(c
->db
,setskeys
[j
]) :
3167 lookupKeyRead(c
->db
,setskeys
[j
]);
3172 if (setobj
->type
!= REDIS_SET
) {
3174 addReply(c
,shared
.wrongtypeerr
);
3177 dv
[j
] = setobj
->ptr
;
3180 /* We need a temp set object to store our union. If the dstkey
3181 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
3182 * this set object will be the resulting object to set into the target key*/
3183 dstset
= createSetObject();
3185 /* Iterate all the elements of all the sets, add every element a single
3186 * time to the result set */
3187 for (j
= 0; j
< setsnum
; j
++) {
3188 if (op
== REDIS_OP_DIFF
&& j
== 0 && !dv
[j
]) break; /* result set is empty */
3189 if (!dv
[j
]) continue; /* non existing keys are like empty sets */
3191 di
= dictGetIterator(dv
[j
]);
3192 if (!di
) oom("dictGetIterator");
3194 while((de
= dictNext(di
)) != NULL
) {
3197 /* dictAdd will not add the same element multiple times */
3198 ele
= dictGetEntryKey(de
);
3199 if (op
== REDIS_OP_UNION
|| j
== 0) {
3200 if (dictAdd(dstset
->ptr
,ele
,NULL
) == DICT_OK
) {
3204 } else if (op
== REDIS_OP_DIFF
) {
3205 if (dictDelete(dstset
->ptr
,ele
) == DICT_OK
) {
3210 dictReleaseIterator(di
);
3212 if (op
== REDIS_OP_DIFF
&& cardinality
== 0) break; /* result set is empty */
3215 /* Output the content of the resulting set, if not in STORE mode */
3217 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",cardinality
));
3218 di
= dictGetIterator(dstset
->ptr
);
3219 if (!di
) oom("dictGetIterator");
3220 while((de
= dictNext(di
)) != NULL
) {
3223 ele
= dictGetEntryKey(de
);
3224 addReplySds(c
,sdscatprintf(sdsempty(),
3225 "$%d\r\n",sdslen(ele
->ptr
)));
3227 addReply(c
,shared
.crlf
);
3229 dictReleaseIterator(di
);
3231 /* If we have a target key where to store the resulting set
3232 * create this key with the result set inside */
3233 deleteKey(c
->db
,dstkey
);
3234 dictAdd(c
->db
->dict
,dstkey
,dstset
);
3235 incrRefCount(dstkey
);
3240 decrRefCount(dstset
);
3242 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3243 dictSize((dict
*)dstset
->ptr
)));
3249 static void sunionCommand(redisClient
*c
) {
3250 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_UNION
);
3253 static void sunionstoreCommand(redisClient
*c
) {
3254 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_UNION
);
3257 static void sdiffCommand(redisClient
*c
) {
3258 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_DIFF
);
3261 static void sdiffstoreCommand(redisClient
*c
) {
3262 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_DIFF
);
3265 static void flushdbCommand(redisClient
*c
) {
3266 server
.dirty
+= dictSize(c
->db
->dict
);
3267 dictEmpty(c
->db
->dict
);
3268 dictEmpty(c
->db
->expires
);
3269 addReply(c
,shared
.ok
);
3272 static void flushallCommand(redisClient
*c
) {
3273 server
.dirty
+= emptyDb();
3274 addReply(c
,shared
.ok
);
3275 rdbSave(server
.dbfilename
);
3279 static redisSortOperation
*createSortOperation(int type
, robj
*pattern
) {
3280 redisSortOperation
*so
= zmalloc(sizeof(*so
));
3281 if (!so
) oom("createSortOperation");
3283 so
->pattern
= pattern
;
3287 /* Return the value associated to the key with a name obtained
3288 * substituting the first occurence of '*' in 'pattern' with 'subst' */
3289 static robj
*lookupKeyByPattern(redisDb
*db
, robj
*pattern
, robj
*subst
) {
3293 int prefixlen
, sublen
, postfixlen
;
3294 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
3298 char buf
[REDIS_SORTKEY_MAX
+1];
3301 spat
= pattern
->ptr
;
3303 if (sdslen(spat
)+sdslen(ssub
)-1 > REDIS_SORTKEY_MAX
) return NULL
;
3304 p
= strchr(spat
,'*');
3305 if (!p
) return NULL
;
3308 sublen
= sdslen(ssub
);
3309 postfixlen
= sdslen(spat
)-(prefixlen
+1);
3310 memcpy(keyname
.buf
,spat
,prefixlen
);
3311 memcpy(keyname
.buf
+prefixlen
,ssub
,sublen
);
3312 memcpy(keyname
.buf
+prefixlen
+sublen
,p
+1,postfixlen
);
3313 keyname
.buf
[prefixlen
+sublen
+postfixlen
] = '\0';
3314 keyname
.len
= prefixlen
+sublen
+postfixlen
;
3316 keyobj
.refcount
= 1;
3317 keyobj
.type
= REDIS_STRING
;
3318 keyobj
.ptr
= ((char*)&keyname
)+(sizeof(long)*2);
3320 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
3321 return lookupKeyRead(db
,&keyobj
);
3324 /* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
3325 * the additional parameter is not standard but a BSD-specific we have to
3326 * pass sorting parameters via the global 'server' structure */
3327 static int sortCompare(const void *s1
, const void *s2
) {
3328 const redisSortObject
*so1
= s1
, *so2
= s2
;
3331 if (!server
.sort_alpha
) {
3332 /* Numeric sorting. Here it's trivial as we precomputed scores */
3333 if (so1
->u
.score
> so2
->u
.score
) {
3335 } else if (so1
->u
.score
< so2
->u
.score
) {
3341 /* Alphanumeric sorting */
3342 if (server
.sort_bypattern
) {
3343 if (!so1
->u
.cmpobj
|| !so2
->u
.cmpobj
) {
3344 /* At least one compare object is NULL */
3345 if (so1
->u
.cmpobj
== so2
->u
.cmpobj
)
3347 else if (so1
->u
.cmpobj
== NULL
)
3352 /* We have both the objects, use strcoll */
3353 cmp
= strcoll(so1
->u
.cmpobj
->ptr
,so2
->u
.cmpobj
->ptr
);
3356 /* Compare elements directly */
3357 cmp
= strcoll(so1
->obj
->ptr
,so2
->obj
->ptr
);
3360 return server
.sort_desc
? -cmp
: cmp
;
3363 /* The SORT command is the most complex command in Redis. Warning: this code
3364 * is optimized for speed and a bit less for readability */
3365 static void sortCommand(redisClient
*c
) {
3368 int desc
= 0, alpha
= 0;
3369 int limit_start
= 0, limit_count
= -1, start
, end
;
3370 int j
, dontsort
= 0, vectorlen
;
3371 int getop
= 0; /* GET operation counter */
3372 robj
*sortval
, *sortby
= NULL
;
3373 redisSortObject
*vector
; /* Resulting vector to sort */
3375 /* Lookup the key to sort. It must be of the right types */
3376 sortval
= lookupKeyRead(c
->db
,c
->argv
[1]);
3377 if (sortval
== NULL
) {
3378 addReply(c
,shared
.nokeyerr
);
3381 if (sortval
->type
!= REDIS_SET
&& sortval
->type
!= REDIS_LIST
) {
3382 addReply(c
,shared
.wrongtypeerr
);
3386 /* Create a list of operations to perform for every sorted element.
3387 * Operations can be GET/DEL/INCR/DECR */
3388 operations
= listCreate();
3389 listSetFreeMethod(operations
,zfree
);
3392 /* Now we need to protect sortval incrementing its count, in the future
3393 * SORT may have options able to overwrite/delete keys during the sorting
3394 * and the sorted key itself may get destroied */
3395 incrRefCount(sortval
);
3397 /* The SORT command has an SQL-alike syntax, parse it */
3398 while(j
< c
->argc
) {
3399 int leftargs
= c
->argc
-j
-1;
3400 if (!strcasecmp(c
->argv
[j
]->ptr
,"asc")) {
3402 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"desc")) {
3404 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"alpha")) {
3406 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"limit") && leftargs
>= 2) {
3407 limit_start
= atoi(c
->argv
[j
+1]->ptr
);
3408 limit_count
= atoi(c
->argv
[j
+2]->ptr
);
3410 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"by") && leftargs
>= 1) {
3411 sortby
= c
->argv
[j
+1];
3412 /* If the BY pattern does not contain '*', i.e. it is constant,
3413 * we don't need to sort nor to lookup the weight keys. */
3414 if (strchr(c
->argv
[j
+1]->ptr
,'*') == NULL
) dontsort
= 1;
3416 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
3417 listAddNodeTail(operations
,createSortOperation(
3418 REDIS_SORT_GET
,c
->argv
[j
+1]));
3421 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"del") && leftargs
>= 1) {
3422 listAddNodeTail(operations
,createSortOperation(
3423 REDIS_SORT_DEL
,c
->argv
[j
+1]));
3425 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"incr") && leftargs
>= 1) {
3426 listAddNodeTail(operations
,createSortOperation(
3427 REDIS_SORT_INCR
,c
->argv
[j
+1]));
3429 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
3430 listAddNodeTail(operations
,createSortOperation(
3431 REDIS_SORT_DECR
,c
->argv
[j
+1]));
3434 decrRefCount(sortval
);
3435 listRelease(operations
);
3436 addReply(c
,shared
.syntaxerr
);
3442 /* Load the sorting vector with all the objects to sort */
3443 vectorlen
= (sortval
->type
== REDIS_LIST
) ?
3444 listLength((list
*)sortval
->ptr
) :
3445 dictSize((dict
*)sortval
->ptr
);
3446 vector
= zmalloc(sizeof(redisSortObject
)*vectorlen
);
3447 if (!vector
) oom("allocating objects vector for SORT");
3449 if (sortval
->type
== REDIS_LIST
) {
3450 list
*list
= sortval
->ptr
;
3454 while((ln
= listYield(list
))) {
3455 robj
*ele
= ln
->value
;
3456 vector
[j
].obj
= ele
;
3457 vector
[j
].u
.score
= 0;
3458 vector
[j
].u
.cmpobj
= NULL
;
3462 dict
*set
= sortval
->ptr
;
3466 di
= dictGetIterator(set
);
3467 if (!di
) oom("dictGetIterator");
3468 while((setele
= dictNext(di
)) != NULL
) {
3469 vector
[j
].obj
= dictGetEntryKey(setele
);
3470 vector
[j
].u
.score
= 0;
3471 vector
[j
].u
.cmpobj
= NULL
;
3474 dictReleaseIterator(di
);
3476 assert(j
== vectorlen
);
3478 /* Now it's time to load the right scores in the sorting vector */
3479 if (dontsort
== 0) {
3480 for (j
= 0; j
< vectorlen
; j
++) {
3484 byval
= lookupKeyByPattern(c
->db
,sortby
,vector
[j
].obj
);
3485 if (!byval
|| byval
->type
!= REDIS_STRING
) continue;
3487 vector
[j
].u
.cmpobj
= byval
;
3488 incrRefCount(byval
);
3490 vector
[j
].u
.score
= strtod(byval
->ptr
,NULL
);
3493 if (!alpha
) vector
[j
].u
.score
= strtod(vector
[j
].obj
->ptr
,NULL
);
3498 /* We are ready to sort the vector... perform a bit of sanity check
3499 * on the LIMIT option too. We'll use a partial version of quicksort. */
3500 start
= (limit_start
< 0) ? 0 : limit_start
;
3501 end
= (limit_count
< 0) ? vectorlen
-1 : start
+limit_count
-1;
3502 if (start
>= vectorlen
) {
3503 start
= vectorlen
-1;
3506 if (end
>= vectorlen
) end
= vectorlen
-1;
3508 if (dontsort
== 0) {
3509 server
.sort_desc
= desc
;
3510 server
.sort_alpha
= alpha
;
3511 server
.sort_bypattern
= sortby
? 1 : 0;
3512 if (sortby
&& (start
!= 0 || end
!= vectorlen
-1))
3513 pqsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
, start
,end
);
3515 qsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
);
3518 /* Send command output to the output buffer, performing the specified
3519 * GET/DEL/INCR/DECR operations if any. */
3520 outputlen
= getop
? getop
*(end
-start
+1) : end
-start
+1;
3521 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",outputlen
));
3522 for (j
= start
; j
<= end
; j
++) {
3525 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",
3526 sdslen(vector
[j
].obj
->ptr
)));
3527 addReply(c
,vector
[j
].obj
);
3528 addReply(c
,shared
.crlf
);
3530 listRewind(operations
);
3531 while((ln
= listYield(operations
))) {
3532 redisSortOperation
*sop
= ln
->value
;
3533 robj
*val
= lookupKeyByPattern(c
->db
,sop
->pattern
,
3536 if (sop
->type
== REDIS_SORT_GET
) {
3537 if (!val
|| val
->type
!= REDIS_STRING
) {
3538 addReply(c
,shared
.nullbulk
);
3540 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",
3543 addReply(c
,shared
.crlf
);
3545 } else if (sop
->type
== REDIS_SORT_DEL
) {
3552 decrRefCount(sortval
);
3553 listRelease(operations
);
3554 for (j
= 0; j
< vectorlen
; j
++) {
3555 if (sortby
&& alpha
&& vector
[j
].u
.cmpobj
)
3556 decrRefCount(vector
[j
].u
.cmpobj
);
3561 static void infoCommand(redisClient
*c
) {
3563 time_t uptime
= time(NULL
)-server
.stat_starttime
;
3565 info
= sdscatprintf(sdsempty(),
3566 "redis_version:%s\r\n"
3567 "uptime_in_seconds:%d\r\n"
3568 "uptime_in_days:%d\r\n"
3569 "connected_clients:%d\r\n"
3570 "connected_slaves:%d\r\n"
3571 "used_memory:%zu\r\n"
3572 "changes_since_last_save:%lld\r\n"
3573 "bgsave_in_progress:%d\r\n"
3574 "last_save_time:%d\r\n"
3575 "total_connections_received:%lld\r\n"
3576 "total_commands_processed:%lld\r\n"
3581 listLength(server
.clients
)-listLength(server
.slaves
),
3582 listLength(server
.slaves
),
3585 server
.bgsaveinprogress
,
3587 server
.stat_numconnections
,
3588 server
.stat_numcommands
,
3589 server
.masterhost
== NULL
? "master" : "slave"
3591 if (server
.masterhost
) {
3592 info
= sdscatprintf(info
,
3593 "master_host:%s\r\n"
3594 "master_port:%d\r\n"
3595 "master_link_status:%s\r\n"
3596 "master_last_io_seconds_ago:%d\r\n"
3599 (server
.replstate
== REDIS_REPL_CONNECTED
) ?
3601 (int)(time(NULL
)-server
.master
->lastinteraction
)
3604 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(info
)));
3605 addReplySds(c
,info
);
3606 addReply(c
,shared
.crlf
);
3609 static void monitorCommand(redisClient
*c
) {
3610 /* ignore MONITOR if aleady slave or in monitor mode */
3611 if (c
->flags
& REDIS_SLAVE
) return;
3613 c
->flags
|= (REDIS_SLAVE
|REDIS_MONITOR
);
3615 if (!listAddNodeTail(server
.monitors
,c
)) oom("listAddNodeTail");
3616 addReply(c
,shared
.ok
);
3619 /* ================================= Expire ================================= */
3620 static int removeExpire(redisDb
*db
, robj
*key
) {
3621 if (dictDelete(db
->expires
,key
) == DICT_OK
) {
3628 static int setExpire(redisDb
*db
, robj
*key
, time_t when
) {
3629 if (dictAdd(db
->expires
,key
,(void*)when
) == DICT_ERR
) {
3637 /* Return the expire time of the specified key, or -1 if no expire
3638 * is associated with this key (i.e. the key is non volatile) */
3639 static time_t getExpire(redisDb
*db
, robj
*key
) {
3642 /* No expire? return ASAP */
3643 if (dictSize(db
->expires
) == 0 ||
3644 (de
= dictFind(db
->expires
,key
)) == NULL
) return -1;
3646 return (time_t) dictGetEntryVal(de
);
3649 static int expireIfNeeded(redisDb
*db
, robj
*key
) {
3653 /* No expire? return ASAP */
3654 if (dictSize(db
->expires
) == 0 ||
3655 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
3657 /* Lookup the expire */
3658 when
= (time_t) dictGetEntryVal(de
);
3659 if (time(NULL
) <= when
) return 0;
3661 /* Delete the key */
3662 dictDelete(db
->expires
,key
);
3663 return dictDelete(db
->dict
,key
) == DICT_OK
;
3666 static int deleteIfVolatile(redisDb
*db
, robj
*key
) {
3669 /* No expire? return ASAP */
3670 if (dictSize(db
->expires
) == 0 ||
3671 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
3673 /* Delete the key */
3675 dictDelete(db
->expires
,key
);
3676 return dictDelete(db
->dict
,key
) == DICT_OK
;
3679 static void expireCommand(redisClient
*c
) {
3681 int seconds
= atoi(c
->argv
[2]->ptr
);
3683 de
= dictFind(c
->db
->dict
,c
->argv
[1]);
3685 addReply(c
,shared
.czero
);
3689 addReply(c
, shared
.czero
);
3692 time_t when
= time(NULL
)+seconds
;
3693 if (setExpire(c
->db
,c
->argv
[1],when
))
3694 addReply(c
,shared
.cone
);
3696 addReply(c
,shared
.czero
);
3701 static void ttlCommand(redisClient
*c
) {
3705 expire
= getExpire(c
->db
,c
->argv
[1]);
3707 ttl
= (int) (expire
-time(NULL
));
3708 if (ttl
< 0) ttl
= -1;
3710 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",ttl
));
3713 /* =============================== Replication ============================= */
3715 static int syncWrite(int fd
, char *ptr
, ssize_t size
, int timeout
) {
3716 ssize_t nwritten
, ret
= size
;
3717 time_t start
= time(NULL
);
3721 if (aeWait(fd
,AE_WRITABLE
,1000) & AE_WRITABLE
) {
3722 nwritten
= write(fd
,ptr
,size
);
3723 if (nwritten
== -1) return -1;
3727 if ((time(NULL
)-start
) > timeout
) {
3735 static int syncRead(int fd
, char *ptr
, ssize_t size
, int timeout
) {
3736 ssize_t nread
, totread
= 0;
3737 time_t start
= time(NULL
);
3741 if (aeWait(fd
,AE_READABLE
,1000) & AE_READABLE
) {
3742 nread
= read(fd
,ptr
,size
);
3743 if (nread
== -1) return -1;
3748 if ((time(NULL
)-start
) > timeout
) {
3756 static int syncReadLine(int fd
, char *ptr
, ssize_t size
, int timeout
) {
3763 if (syncRead(fd
,&c
,1,timeout
) == -1) return -1;
3766 if (nread
&& *(ptr
-1) == '\r') *(ptr
-1) = '\0';
3777 static void syncCommand(redisClient
*c
) {
3778 /* ignore SYNC if aleady slave or in monitor mode */
3779 if (c
->flags
& REDIS_SLAVE
) return;
3781 /* SYNC can't be issued when the server has pending data to send to
3782 * the client about already issued commands. We need a fresh reply
3783 * buffer registering the differences between the BGSAVE and the current
3784 * dataset, so that we can copy to other slaves if needed. */
3785 if (listLength(c
->reply
) != 0) {
3786 addReplySds(c
,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
3790 redisLog(REDIS_NOTICE
,"Slave ask for synchronization");
3791 /* Here we need to check if there is a background saving operation
3792 * in progress, or if it is required to start one */
3793 if (server
.bgsaveinprogress
) {
3794 /* Ok a background save is in progress. Let's check if it is a good
3795 * one for replication, i.e. if there is another slave that is
3796 * registering differences since the server forked to save */
3800 listRewind(server
.slaves
);
3801 while((ln
= listYield(server
.slaves
))) {
3803 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) break;
3806 /* Perfect, the server is already registering differences for
3807 * another slave. Set the right state, and copy the buffer. */
3808 listRelease(c
->reply
);
3809 c
->reply
= listDup(slave
->reply
);
3810 if (!c
->reply
) oom("listDup copying slave reply list");
3811 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
3812 redisLog(REDIS_NOTICE
,"Waiting for end of BGSAVE for SYNC");
3814 /* No way, we need to wait for the next BGSAVE in order to
3815 * register differences */
3816 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
3817 redisLog(REDIS_NOTICE
,"Waiting for next BGSAVE for SYNC");
3820 /* Ok we don't have a BGSAVE in progress, let's start one */
3821 redisLog(REDIS_NOTICE
,"Starting BGSAVE for SYNC");
3822 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
3823 redisLog(REDIS_NOTICE
,"Replication failed, can't BGSAVE");
3824 addReplySds(c
,sdsnew("-ERR Unalbe to perform background save\r\n"));
3827 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
3830 c
->flags
|= REDIS_SLAVE
;
3832 if (!listAddNodeTail(server
.slaves
,c
)) oom("listAddNodeTail");
3836 static void sendBulkToSlave(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
3837 redisClient
*slave
= privdata
;
3839 REDIS_NOTUSED(mask
);
3840 char buf
[REDIS_IOBUF_LEN
];
3841 ssize_t nwritten
, buflen
;
3843 if (slave
->repldboff
== 0) {
3844 /* Write the bulk write count before to transfer the DB. In theory here
3845 * we don't know how much room there is in the output buffer of the
3846 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
3847 * operations) will never be smaller than the few bytes we need. */
3850 bulkcount
= sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
3852 if (write(fd
,bulkcount
,sdslen(bulkcount
)) != (signed)sdslen(bulkcount
))
3860 lseek(slave
->repldbfd
,slave
->repldboff
,SEEK_SET
);
3861 buflen
= read(slave
->repldbfd
,buf
,REDIS_IOBUF_LEN
);
3863 redisLog(REDIS_WARNING
,"Read error sending DB to slave: %s",
3864 (buflen
== 0) ? "premature EOF" : strerror(errno
));
3868 if ((nwritten
= write(fd
,buf
,buflen
)) == -1) {
3869 redisLog(REDIS_DEBUG
,"Write error sending DB to slave: %s",
3874 slave
->repldboff
+= nwritten
;
3875 if (slave
->repldboff
== slave
->repldbsize
) {
3876 close(slave
->repldbfd
);
3877 slave
->repldbfd
= -1;
3878 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
3879 slave
->replstate
= REDIS_REPL_ONLINE
;
3880 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
,
3881 sendReplyToClient
, slave
, NULL
) == AE_ERR
) {
3885 addReplySds(slave
,sdsempty());
3886 redisLog(REDIS_NOTICE
,"Synchronization with slave succeeded");
3890 static void updateSalvesWaitingBgsave(int bgsaveerr
) {
3892 int startbgsave
= 0;
3894 listRewind(server
.slaves
);
3895 while((ln
= listYield(server
.slaves
))) {
3896 redisClient
*slave
= ln
->value
;
3898 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) {
3900 slave
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
3901 } else if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) {
3902 struct redis_stat buf
;
3904 if (bgsaveerr
!= REDIS_OK
) {
3906 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE child returned an error");
3909 if ((slave
->repldbfd
= open(server
.dbfilename
,O_RDONLY
)) == -1 ||
3910 redis_fstat(slave
->repldbfd
,&buf
) == -1) {
3912 redisLog(REDIS_WARNING
,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno
));
3915 slave
->repldboff
= 0;
3916 slave
->repldbsize
= buf
.st_size
;
3917 slave
->replstate
= REDIS_REPL_SEND_BULK
;
3918 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
3919 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
, sendBulkToSlave
, slave
, NULL
) == AE_ERR
) {
3926 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
3927 listRewind(server
.slaves
);
3928 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE failed");
3929 while((ln
= listYield(server
.slaves
))) {
3930 redisClient
*slave
= ln
->value
;
3932 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
)
3939 static int syncWithMaster(void) {
3940 char buf
[1024], tmpfile
[256];
3942 int fd
= anetTcpConnect(NULL
,server
.masterhost
,server
.masterport
);
3946 redisLog(REDIS_WARNING
,"Unable to connect to MASTER: %s",
3950 /* Issue the SYNC command */
3951 if (syncWrite(fd
,"SYNC \r\n",7,5) == -1) {
3953 redisLog(REDIS_WARNING
,"I/O error writing to MASTER: %s",
3957 /* Read the bulk write count */
3958 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
3960 redisLog(REDIS_WARNING
,"I/O error reading bulk count from MASTER: %s",
3964 dumpsize
= atoi(buf
+1);
3965 redisLog(REDIS_NOTICE
,"Receiving %d bytes data dump from MASTER",dumpsize
);
3966 /* Read the bulk write data on a temp file */
3967 snprintf(tmpfile
,256,"temp-%d.%ld.rdb",(int)time(NULL
),(long int)random());
3968 dfd
= open(tmpfile
,O_CREAT
|O_WRONLY
,0644);
3971 redisLog(REDIS_WARNING
,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno
));
3975 int nread
, nwritten
;
3977 nread
= read(fd
,buf
,(dumpsize
< 1024)?dumpsize
:1024);
3979 redisLog(REDIS_WARNING
,"I/O error trying to sync with MASTER: %s",
3985 nwritten
= write(dfd
,buf
,nread
);
3986 if (nwritten
== -1) {
3987 redisLog(REDIS_WARNING
,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno
));
3995 if (rename(tmpfile
,server
.dbfilename
) == -1) {
3996 redisLog(REDIS_WARNING
,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno
));
4002 if (rdbLoad(server
.dbfilename
) != REDIS_OK
) {
4003 redisLog(REDIS_WARNING
,"Failed trying to load the MASTER synchronization DB from disk");
4007 server
.master
= createClient(fd
);
4008 server
.master
->flags
|= REDIS_MASTER
;
4009 server
.replstate
= REDIS_REPL_CONNECTED
;
4013 static void slaveofCommand(redisClient
*c
) {
4014 if (!strcasecmp(c
->argv
[1]->ptr
,"no") &&
4015 !strcasecmp(c
->argv
[2]->ptr
,"one")) {
4016 if (server
.masterhost
) {
4017 sdsfree(server
.masterhost
);
4018 server
.masterhost
= NULL
;
4019 if (server
.master
) freeClient(server
.master
);
4020 server
.replstate
= REDIS_REPL_NONE
;
4021 redisLog(REDIS_NOTICE
,"MASTER MODE enabled (user request)");
4024 sdsfree(server
.masterhost
);
4025 server
.masterhost
= sdsdup(c
->argv
[1]->ptr
);
4026 server
.masterport
= atoi(c
->argv
[2]->ptr
);
4027 if (server
.master
) freeClient(server
.master
);
4028 server
.replstate
= REDIS_REPL_CONNECT
;
4029 redisLog(REDIS_NOTICE
,"SLAVE OF %s:%d enabled (user request)",
4030 server
.masterhost
, server
.masterport
);
4032 addReply(c
,shared
.ok
);
4035 /* ============================ Maxmemory directive ======================== */
4037 /* This function gets called when 'maxmemory' is set on the config file to limit
4038 * the max memory used by the server, and we are out of memory.
4039 * This function will try to, in order:
4041 * - Free objects from the free list
4042 * - Try to remove keys with an EXPIRE set
4044 * It is not possible to free enough memory to reach used-memory < maxmemory
4045 * the server will start refusing commands that will enlarge even more the
4048 static void freeMemoryIfNeeded(void) {
4049 while (server
.maxmemory
&& zmalloc_used_memory() > server
.maxmemory
) {
4050 if (listLength(server
.objfreelist
)) {
4053 listNode
*head
= listFirst(server
.objfreelist
);
4054 o
= listNodeValue(head
);
4055 listDelNode(server
.objfreelist
,head
);
4058 int j
, k
, freed
= 0;
4060 for (j
= 0; j
< server
.dbnum
; j
++) {
4062 robj
*minkey
= NULL
;
4063 struct dictEntry
*de
;
4065 if (dictSize(server
.db
[j
].expires
)) {
4067 /* From a sample of three keys drop the one nearest to
4068 * the natural expire */
4069 for (k
= 0; k
< 3; k
++) {
4072 de
= dictGetRandomKey(server
.db
[j
].expires
);
4073 t
= (time_t) dictGetEntryVal(de
);
4074 if (minttl
== -1 || t
< minttl
) {
4075 minkey
= dictGetEntryKey(de
);
4079 deleteKey(server
.db
+j
,minkey
);
4082 if (!freed
) return; /* nothing to free... */
4087 /* ================================= Debugging ============================== */
4089 static void debugCommand(redisClient
*c
) {
4090 if (!strcasecmp(c
->argv
[1]->ptr
,"segfault")) {
4092 } else if (!strcasecmp(c
->argv
[1]->ptr
,"object") && c
->argc
== 3) {
4093 dictEntry
*de
= dictFind(c
->db
->dict
,c
->argv
[2]);
4097 addReply(c
,shared
.nokeyerr
);
4100 key
= dictGetEntryKey(de
);
4101 val
= dictGetEntryVal(de
);
4102 addReplySds(c
,sdscatprintf(sdsempty(),
4103 "+Key at:%p refcount:%d, value at:%p refcount:%d\r\n",
4104 key
, key
->refcount
, val
, val
->refcount
));
4106 addReplySds(c
,sdsnew(
4107 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>]\r\n"));
4111 #if defined(__APPLE__) || defined(__linux__)
4112 static struct redisFunctionSym symsTable
[] = {
4113 {"freeStringObject", (unsigned long)freeStringObject
},
4114 {"freeListObject", (unsigned long)freeListObject
},
4115 {"freeSetObject", (unsigned long)freeSetObject
},
4116 {"decrRefCount", (unsigned long)decrRefCount
},
4117 {"createObject", (unsigned long)createObject
},
4118 {"freeClient", (unsigned long)freeClient
},
4119 {"rdbLoad", (unsigned long)rdbLoad
},
4120 {"addReply", (unsigned long)addReply
},
4121 {"addReplySds", (unsigned long)addReplySds
},
4122 {"incrRefCount", (unsigned long)incrRefCount
},
4123 {"rdbSaveBackground", (unsigned long)rdbSaveBackground
},
4124 {"createStringObject", (unsigned long)createStringObject
},
4125 {"replicationFeedSlaves", (unsigned long)replicationFeedSlaves
},
4126 {"syncWithMaster", (unsigned long)syncWithMaster
},
4127 {"tryObjectSharing", (unsigned long)tryObjectSharing
},
4128 {"removeExpire", (unsigned long)removeExpire
},
4129 {"expireIfNeeded", (unsigned long)expireIfNeeded
},
4130 {"deleteIfVolatile", (unsigned long)deleteIfVolatile
},
4131 {"deleteKey", (unsigned long)deleteKey
},
4132 {"getExpire", (unsigned long)getExpire
},
4133 {"setExpire", (unsigned long)setExpire
},
4134 {"updateSalvesWaitingBgsave", (unsigned long)updateSalvesWaitingBgsave
},
4135 {"freeMemoryIfNeeded", (unsigned long)freeMemoryIfNeeded
},
4136 {"authCommand", (unsigned long)authCommand
},
4137 {"pingCommand", (unsigned long)pingCommand
},
4138 {"echoCommand", (unsigned long)echoCommand
},
4139 {"setCommand", (unsigned long)setCommand
},
4140 {"setnxCommand", (unsigned long)setnxCommand
},
4141 {"getCommand", (unsigned long)getCommand
},
4142 {"delCommand", (unsigned long)delCommand
},
4143 {"existsCommand", (unsigned long)existsCommand
},
4144 {"incrCommand", (unsigned long)incrCommand
},
4145 {"decrCommand", (unsigned long)decrCommand
},
4146 {"incrbyCommand", (unsigned long)incrbyCommand
},
4147 {"decrbyCommand", (unsigned long)decrbyCommand
},
4148 {"selectCommand", (unsigned long)selectCommand
},
4149 {"randomkeyCommand", (unsigned long)randomkeyCommand
},
4150 {"keysCommand", (unsigned long)keysCommand
},
4151 {"dbsizeCommand", (unsigned long)dbsizeCommand
},
4152 {"lastsaveCommand", (unsigned long)lastsaveCommand
},
4153 {"saveCommand", (unsigned long)saveCommand
},
4154 {"bgsaveCommand", (unsigned long)bgsaveCommand
},
4155 {"shutdownCommand", (unsigned long)shutdownCommand
},
4156 {"moveCommand", (unsigned long)moveCommand
},
4157 {"renameCommand", (unsigned long)renameCommand
},
4158 {"renamenxCommand", (unsigned long)renamenxCommand
},
4159 {"lpushCommand", (unsigned long)lpushCommand
},
4160 {"rpushCommand", (unsigned long)rpushCommand
},
4161 {"lpopCommand", (unsigned long)lpopCommand
},
4162 {"rpopCommand", (unsigned long)rpopCommand
},
4163 {"llenCommand", (unsigned long)llenCommand
},
4164 {"lindexCommand", (unsigned long)lindexCommand
},
4165 {"lrangeCommand", (unsigned long)lrangeCommand
},
4166 {"ltrimCommand", (unsigned long)ltrimCommand
},
4167 {"typeCommand", (unsigned long)typeCommand
},
4168 {"lsetCommand", (unsigned long)lsetCommand
},
4169 {"saddCommand", (unsigned long)saddCommand
},
4170 {"sremCommand", (unsigned long)sremCommand
},
4171 {"smoveCommand", (unsigned long)smoveCommand
},
4172 {"sismemberCommand", (unsigned long)sismemberCommand
},
4173 {"scardCommand", (unsigned long)scardCommand
},
4174 {"sinterCommand", (unsigned long)sinterCommand
},
4175 {"sinterstoreCommand", (unsigned long)sinterstoreCommand
},
4176 {"sunionCommand", (unsigned long)sunionCommand
},
4177 {"sunionstoreCommand", (unsigned long)sunionstoreCommand
},
4178 {"sdiffCommand", (unsigned long)sdiffCommand
},
4179 {"sdiffstoreCommand", (unsigned long)sdiffstoreCommand
},
4180 {"syncCommand", (unsigned long)syncCommand
},
4181 {"flushdbCommand", (unsigned long)flushdbCommand
},
4182 {"flushallCommand", (unsigned long)flushallCommand
},
4183 {"sortCommand", (unsigned long)sortCommand
},
4184 {"lremCommand", (unsigned long)lremCommand
},
4185 {"infoCommand", (unsigned long)infoCommand
},
4186 {"mgetCommand", (unsigned long)mgetCommand
},
4187 {"monitorCommand", (unsigned long)monitorCommand
},
4188 {"expireCommand", (unsigned long)expireCommand
},
4189 {"getSetCommand", (unsigned long)getSetCommand
},
4190 {"ttlCommand", (unsigned long)ttlCommand
},
4191 {"slaveofCommand", (unsigned long)slaveofCommand
},
4192 {"debugCommand", (unsigned long)debugCommand
},
4193 {"processCommand", (unsigned long)processCommand
},
4194 {"setupSigSegvAction", (unsigned long)setupSigSegvAction
},
4195 {"segvHandler", (unsigned long)segvHandler
},
4196 {"readQueryFromClient", (unsigned long)readQueryFromClient
},
4200 /* This function try to convert a pointer into a function name. It's used in
4201 * oreder to provide a backtrace under segmentation fault that's able to
4202 * display functions declared as static (otherwise the backtrace is useless). */
4203 static char *findFuncName(void *pointer
, unsigned long *offset
){
4205 unsigned long off
, minoff
= 0;
4207 /* Try to match against the Symbol with the smallest offset */
4208 for (i
=0; symsTable
[i
].pointer
; i
++) {
4209 unsigned long lp
= (unsigned long) pointer
;
4211 if (lp
!= (unsigned long)-1 && lp
>= symsTable
[i
].pointer
) {
4212 off
=lp
-symsTable
[i
].pointer
;
4213 if (ret
< 0 || off
< minoff
) {
4219 if (ret
== -1) return NULL
;
4221 return symsTable
[ret
].name
;
4224 static void *getMcontextEip(ucontext_t
*uc
) {
4225 #if defined(__FreeBSD__)
4226 return (void*) uc
->uc_mcontext
.mc_eip
;
4227 #elif defined(__dietlibc__)
4228 return (void*) uc
->uc_mcontext
.eip
;
4229 #elif defined(__APPLE__)
4230 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
4232 return (void*) uc
->uc_mcontext
.gregs
[REG_EIP
];
4236 static void segvHandler(int sig
, siginfo_t
*info
, void *secret
) {
4238 char **messages
= NULL
;
4239 int i
, trace_size
= 0;
4240 unsigned long offset
=0;
4241 time_t uptime
= time(NULL
)-server
.stat_starttime
;
4242 ucontext_t
*uc
= (ucontext_t
*) secret
;
4243 REDIS_NOTUSED(info
);
4245 redisLog(REDIS_WARNING
,
4246 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION
, sig
);
4247 redisLog(REDIS_WARNING
, "%s", sdscatprintf(sdsempty(),
4248 "redis_version:%s; "
4249 "uptime_in_seconds:%d; "
4250 "connected_clients:%d; "
4251 "connected_slaves:%d; "
4253 "changes_since_last_save:%lld; "
4254 "bgsave_in_progress:%d; "
4255 "last_save_time:%d; "
4256 "total_connections_received:%lld; "
4257 "total_commands_processed:%lld; "
4261 listLength(server
.clients
)-listLength(server
.slaves
),
4262 listLength(server
.slaves
),
4265 server
.bgsaveinprogress
,
4267 server
.stat_numconnections
,
4268 server
.stat_numcommands
,
4269 server
.masterhost
== NULL
? "master" : "slave"
4272 trace_size
= backtrace(trace
, 100);
4273 /* overwrite sigaction with caller's address */
4274 trace
[1] = getMcontextEip(uc
);
4275 messages
= backtrace_symbols(trace
, trace_size
);
4277 for (i
=0; i
<trace_size
; ++i
) {
4278 char *fn
= findFuncName(trace
[i
], &offset
), *p
;
4280 p
= strchr(messages
[i
],'+');
4281 if (!fn
|| (p
&& ((unsigned long)strtol(p
+1,NULL
,10)) < offset
)) {
4282 redisLog(REDIS_WARNING
,"%s", messages
[i
]);
4284 redisLog(REDIS_WARNING
,"%d redis-server %p %s + %d", i
, trace
[i
], fn
, (unsigned int)offset
);
4291 static void setupSigSegvAction(void) {
4292 #if defined(__APPLE__) || defined(__linux__)
4293 struct sigaction act
;
4295 sigemptyset (&act
.sa_mask
);
4296 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
4297 * is used. Otherwise, sa_handler is used */
4298 act
.sa_flags
= SA_NODEFER
| SA_ONSTACK
| SA_RESETHAND
| SA_SIGINFO
;
4299 act
.sa_sigaction
= segvHandler
;
4300 sigaction (SIGSEGV
, &act
, NULL
);
4301 sigaction (SIGBUS
, &act
, NULL
);
4307 #endif /* if __APPLE__ or __linux__ */
4309 /* =================================== Main! ================================ */
4312 int linuxOvercommitMemoryValue(void) {
4313 FILE *fp
= fopen("/proc/sys/vm/overcommit_memory","r");
4317 if (fgets(buf
,64,fp
) == NULL
) {
4326 void linuxOvercommitMemoryWarning(void) {
4327 if (linuxOvercommitMemoryValue() == 0) {
4328 redisLog(REDIS_WARNING
,"WARNING overcommit_memory is set to 0! Background save may fail under low condition memory. To fix this issue add 'echo 1 > /proc/sys/vm/overcommit_memory' in your init scripts.");
4331 #endif /* __linux__ */
4333 static void daemonize(void) {
4337 if (fork() != 0) exit(0); /* parent exits */
4338 setsid(); /* create a new session */
4340 /* Every output goes to /dev/null. If Redis is daemonized but
4341 * the 'logfile' is set to 'stdout' in the configuration file
4342 * it will not log at all. */
4343 if ((fd
= open("/dev/null", O_RDWR
, 0)) != -1) {
4344 dup2(fd
, STDIN_FILENO
);
4345 dup2(fd
, STDOUT_FILENO
);
4346 dup2(fd
, STDERR_FILENO
);
4347 if (fd
> STDERR_FILENO
) close(fd
);
4349 /* Try to write the pid file */
4350 fp
= fopen(server
.pidfile
,"w");
4352 fprintf(fp
,"%d\n",getpid());
4357 int main(int argc
, char **argv
) {
4359 linuxOvercommitMemoryWarning();
4364 ResetServerSaveParams();
4365 loadServerConfig(argv
[1]);
4366 } else if (argc
> 2) {
4367 fprintf(stderr
,"Usage: ./redis-server [/path/to/redis.conf]\n");
4370 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'");
4373 if (server
.daemonize
) daemonize();
4374 redisLog(REDIS_NOTICE
,"Server started, Redis version " REDIS_VERSION
);
4375 if (rdbLoad(server
.dbfilename
) == REDIS_OK
)
4376 redisLog(REDIS_NOTICE
,"DB loaded from disk");
4377 if (aeCreateFileEvent(server
.el
, server
.fd
, AE_READABLE
,
4378 acceptHandler
, NULL
, NULL
) == AE_ERR
) oom("creating file event");
4379 redisLog(REDIS_NOTICE
,"The server is now ready to accept connections on port %d", server
.port
);
4381 aeDeleteEventLoop(server
.el
);