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.900"
40 #define __USE_POSIX199309
46 #endif /* HAVE_BACKTRACE */
54 #include <arpa/inet.h>
58 #include <sys/resource.h>
62 #include "ae.h" /* Event driven programming library */
63 #include "sds.h" /* Dynamic safe strings */
64 #include "anet.h" /* Networking the easy way */
65 #include "dict.h" /* Hash tables */
66 #include "adlist.h" /* Linked lists */
67 #include "zmalloc.h" /* total memory usage aware version of malloc/free */
68 #include "lzf.h" /* LZF compression library */
69 #include "pqsort.h" /* Partial qsort for SORT+LIMIT */
75 /* Static server configuration */
76 #define REDIS_SERVERPORT 6379 /* TCP port */
77 #define REDIS_MAXIDLETIME (60*5) /* default client timeout */
78 #define REDIS_IOBUF_LEN 1024
79 #define REDIS_LOADBUF_LEN 1024
80 #define REDIS_STATIC_ARGS 4
81 #define REDIS_DEFAULT_DBNUM 16
82 #define REDIS_CONFIGLINE_MAX 1024
83 #define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
84 #define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
85 #define REDIS_EXPIRELOOKUPS_PER_CRON 100 /* try to expire 100 keys/second */
86 #define REDIS_MAX_WRITE_PER_EVENT (1024*64)
87 #define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
89 /* Hash table parameters */
90 #define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
93 #define REDIS_CMD_BULK 1 /* Bulk write command */
94 #define REDIS_CMD_INLINE 2 /* Inline command */
95 /* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
96 this flags will return an error when the 'maxmemory' option is set in the
97 config file and the server is using more than maxmemory bytes of memory.
98 In short this commands are denied on low memory conditions. */
99 #define REDIS_CMD_DENYOOM 4
102 #define REDIS_STRING 0
107 /* Object types only used for dumping to disk */
108 #define REDIS_EXPIRETIME 253
109 #define REDIS_SELECTDB 254
110 #define REDIS_EOF 255
112 /* Defines related to the dump file format. To store 32 bits lengths for short
113 * keys requires a lot of space, so we check the most significant 2 bits of
114 * the first byte to interpreter the length:
116 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
117 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
118 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
119 * 11|000000 this means: specially encoded object will follow. The six bits
120 * number specify the kind of object that follows.
121 * See the REDIS_RDB_ENC_* defines.
123 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
124 * values, will fit inside. */
125 #define REDIS_RDB_6BITLEN 0
126 #define REDIS_RDB_14BITLEN 1
127 #define REDIS_RDB_32BITLEN 2
128 #define REDIS_RDB_ENCVAL 3
129 #define REDIS_RDB_LENERR UINT_MAX
131 /* When a length of a string object stored on disk has the first two bits
132 * set, the remaining two bits specify a special encoding for the object
133 * accordingly to the following defines: */
134 #define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
135 #define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
136 #define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
137 #define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
140 #define REDIS_CLOSE 1 /* This client connection should be closed ASAP */
141 #define REDIS_SLAVE 2 /* This client is a slave server */
142 #define REDIS_MASTER 4 /* This client is a master server */
143 #define REDIS_MONITOR 8 /* This client is a slave monitor, see MONITOR */
145 /* Slave replication state - slave side */
146 #define REDIS_REPL_NONE 0 /* No active replication */
147 #define REDIS_REPL_CONNECT 1 /* Must connect to master */
148 #define REDIS_REPL_CONNECTED 2 /* Connected to master */
150 /* Slave replication state - from the point of view of master
151 * Note that in SEND_BULK and ONLINE state the slave receives new updates
152 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
153 * to start the next background saving in order to send updates to it. */
154 #define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
155 #define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
156 #define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
157 #define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
159 /* List related stuff */
163 /* Sort operations */
164 #define REDIS_SORT_GET 0
165 #define REDIS_SORT_DEL 1
166 #define REDIS_SORT_INCR 2
167 #define REDIS_SORT_DECR 3
168 #define REDIS_SORT_ASC 4
169 #define REDIS_SORT_DESC 5
170 #define REDIS_SORTKEY_MAX 1024
173 #define REDIS_DEBUG 0
174 #define REDIS_NOTICE 1
175 #define REDIS_WARNING 2
177 /* Anti-warning macro... */
178 #define REDIS_NOTUSED(V) ((void) V)
181 /*================================= Data types ============================== */
183 /* A redis object, that is a type able to hold a string / list / set */
184 typedef struct redisObject
{
190 typedef struct redisDb
{
196 /* With multiplexing we need to take per-clinet state.
197 * Clients are taken in a liked list. */
198 typedef struct redisClient
{
205 int bulklen
; /* bulk read len. -1 if not in bulk read mode */
208 time_t lastinteraction
; /* time of the last interaction, used for timeout */
209 int flags
; /* REDIS_CLOSE | REDIS_SLAVE | REDIS_MONITOR */
210 int slaveseldb
; /* slave selected db, if this client is a slave */
211 int authenticated
; /* when requirepass is non-NULL */
212 int replstate
; /* replication state if this is a slave */
213 int repldbfd
; /* replication DB file descriptor */
214 long repldboff
; /* replication DB file offset */
215 off_t repldbsize
; /* replication DB file size */
223 /* Global server state structure */
229 unsigned int sharingpoolsize
;
230 long long dirty
; /* changes to DB from the last save */
232 list
*slaves
, *monitors
;
233 char neterr
[ANET_ERR_LEN
];
235 int cronloops
; /* number of times the cron function run */
236 list
*objfreelist
; /* A list of freed objects to avoid malloc() */
237 time_t lastsave
; /* Unix time of last save succeeede */
238 size_t usedmemory
; /* Used memory in megabytes */
239 /* Fields used only for stats */
240 time_t stat_starttime
; /* server start time */
241 long long stat_numcommands
; /* number of processed commands */
242 long long stat_numconnections
; /* number of connections received */
250 int bgsaveinprogress
;
251 pid_t bgsavechildpid
;
252 struct saveparam
*saveparams
;
259 /* Replication related */
263 redisClient
*master
; /* client that is master for this slave */
265 unsigned int maxclients
;
266 unsigned int maxmemory
;
267 /* Sort parameters - qsort_r() is only available under BSD so we
268 * have to take this state global, in order to pass it to sortCompare() */
274 typedef void redisCommandProc(redisClient
*c
);
275 struct redisCommand
{
277 redisCommandProc
*proc
;
282 struct redisFunctionSym
{
284 unsigned long pointer
;
287 typedef struct _redisSortObject
{
295 typedef struct _redisSortOperation
{
298 } redisSortOperation
;
300 struct sharedObjectsStruct
{
301 robj
*crlf
, *ok
, *err
, *emptybulk
, *czero
, *cone
, *pong
, *space
,
302 *colon
, *nullbulk
, *nullmultibulk
,
303 *emptymultibulk
, *wrongtypeerr
, *nokeyerr
, *syntaxerr
, *sameobjecterr
,
304 *outofrangeerr
, *plus
,
305 *select0
, *select1
, *select2
, *select3
, *select4
,
306 *select5
, *select6
, *select7
, *select8
, *select9
;
309 /*================================ Prototypes =============================== */
311 static void freeStringObject(robj
*o
);
312 static void freeListObject(robj
*o
);
313 static void freeSetObject(robj
*o
);
314 static void decrRefCount(void *o
);
315 static robj
*createObject(int type
, void *ptr
);
316 static void freeClient(redisClient
*c
);
317 static int rdbLoad(char *filename
);
318 static void addReply(redisClient
*c
, robj
*obj
);
319 static void addReplySds(redisClient
*c
, sds s
);
320 static void incrRefCount(robj
*o
);
321 static int rdbSaveBackground(char *filename
);
322 static robj
*createStringObject(char *ptr
, size_t len
);
323 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
);
324 static int syncWithMaster(void);
325 static robj
*tryObjectSharing(robj
*o
);
326 static int removeExpire(redisDb
*db
, robj
*key
);
327 static int expireIfNeeded(redisDb
*db
, robj
*key
);
328 static int deleteIfVolatile(redisDb
*db
, robj
*key
);
329 static int deleteKey(redisDb
*db
, robj
*key
);
330 static time_t getExpire(redisDb
*db
, robj
*key
);
331 static int setExpire(redisDb
*db
, robj
*key
, time_t when
);
332 static void updateSlavesWaitingBgsave(int bgsaveerr
);
333 static void freeMemoryIfNeeded(void);
334 static int processCommand(redisClient
*c
);
335 static void setupSigSegvAction(void);
336 static void rdbRemoveTempFile(pid_t childpid
);
338 static void authCommand(redisClient
*c
);
339 static void pingCommand(redisClient
*c
);
340 static void echoCommand(redisClient
*c
);
341 static void setCommand(redisClient
*c
);
342 static void setnxCommand(redisClient
*c
);
343 static void getCommand(redisClient
*c
);
344 static void delCommand(redisClient
*c
);
345 static void existsCommand(redisClient
*c
);
346 static void incrCommand(redisClient
*c
);
347 static void decrCommand(redisClient
*c
);
348 static void incrbyCommand(redisClient
*c
);
349 static void decrbyCommand(redisClient
*c
);
350 static void selectCommand(redisClient
*c
);
351 static void randomkeyCommand(redisClient
*c
);
352 static void keysCommand(redisClient
*c
);
353 static void dbsizeCommand(redisClient
*c
);
354 static void lastsaveCommand(redisClient
*c
);
355 static void saveCommand(redisClient
*c
);
356 static void bgsaveCommand(redisClient
*c
);
357 static void shutdownCommand(redisClient
*c
);
358 static void moveCommand(redisClient
*c
);
359 static void renameCommand(redisClient
*c
);
360 static void renamenxCommand(redisClient
*c
);
361 static void lpushCommand(redisClient
*c
);
362 static void rpushCommand(redisClient
*c
);
363 static void lpopCommand(redisClient
*c
);
364 static void rpopCommand(redisClient
*c
);
365 static void llenCommand(redisClient
*c
);
366 static void lindexCommand(redisClient
*c
);
367 static void lrangeCommand(redisClient
*c
);
368 static void ltrimCommand(redisClient
*c
);
369 static void typeCommand(redisClient
*c
);
370 static void lsetCommand(redisClient
*c
);
371 static void saddCommand(redisClient
*c
);
372 static void sremCommand(redisClient
*c
);
373 static void smoveCommand(redisClient
*c
);
374 static void sismemberCommand(redisClient
*c
);
375 static void scardCommand(redisClient
*c
);
376 static void spopCommand(redisClient
*c
);
377 static void sinterCommand(redisClient
*c
);
378 static void sinterstoreCommand(redisClient
*c
);
379 static void sunionCommand(redisClient
*c
);
380 static void sunionstoreCommand(redisClient
*c
);
381 static void sdiffCommand(redisClient
*c
);
382 static void sdiffstoreCommand(redisClient
*c
);
383 static void syncCommand(redisClient
*c
);
384 static void flushdbCommand(redisClient
*c
);
385 static void flushallCommand(redisClient
*c
);
386 static void sortCommand(redisClient
*c
);
387 static void lremCommand(redisClient
*c
);
388 static void infoCommand(redisClient
*c
);
389 static void mgetCommand(redisClient
*c
);
390 static void monitorCommand(redisClient
*c
);
391 static void expireCommand(redisClient
*c
);
392 static void getSetCommand(redisClient
*c
);
393 static void ttlCommand(redisClient
*c
);
394 static void slaveofCommand(redisClient
*c
);
395 static void debugCommand(redisClient
*c
);
396 /*================================= Globals ================================= */
399 static struct redisServer server
; /* server global state */
400 static struct redisCommand cmdTable
[] = {
401 {"get",getCommand
,2,REDIS_CMD_INLINE
},
402 {"set",setCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
403 {"setnx",setnxCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
404 {"del",delCommand
,-2,REDIS_CMD_INLINE
},
405 {"exists",existsCommand
,2,REDIS_CMD_INLINE
},
406 {"incr",incrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
407 {"decr",decrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
408 {"mget",mgetCommand
,-2,REDIS_CMD_INLINE
},
409 {"rpush",rpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
410 {"lpush",lpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
411 {"rpop",rpopCommand
,2,REDIS_CMD_INLINE
},
412 {"lpop",lpopCommand
,2,REDIS_CMD_INLINE
},
413 {"llen",llenCommand
,2,REDIS_CMD_INLINE
},
414 {"lindex",lindexCommand
,3,REDIS_CMD_INLINE
},
415 {"lset",lsetCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
416 {"lrange",lrangeCommand
,4,REDIS_CMD_INLINE
},
417 {"ltrim",ltrimCommand
,4,REDIS_CMD_INLINE
},
418 {"lrem",lremCommand
,4,REDIS_CMD_BULK
},
419 {"sadd",saddCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
420 {"srem",sremCommand
,3,REDIS_CMD_BULK
},
421 {"smove",smoveCommand
,4,REDIS_CMD_BULK
},
422 {"sismember",sismemberCommand
,3,REDIS_CMD_BULK
},
423 {"scard",scardCommand
,2,REDIS_CMD_INLINE
},
424 {"spop",spopCommand
,2,REDIS_CMD_INLINE
},
425 {"sinter",sinterCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
426 {"sinterstore",sinterstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
427 {"sunion",sunionCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
428 {"sunionstore",sunionstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
429 {"sdiff",sdiffCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
430 {"sdiffstore",sdiffstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
431 {"smembers",sinterCommand
,2,REDIS_CMD_INLINE
},
432 {"incrby",incrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
433 {"decrby",decrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
434 {"getset",getSetCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
435 {"randomkey",randomkeyCommand
,1,REDIS_CMD_INLINE
},
436 {"select",selectCommand
,2,REDIS_CMD_INLINE
},
437 {"move",moveCommand
,3,REDIS_CMD_INLINE
},
438 {"rename",renameCommand
,3,REDIS_CMD_INLINE
},
439 {"renamenx",renamenxCommand
,3,REDIS_CMD_INLINE
},
440 {"expire",expireCommand
,3,REDIS_CMD_INLINE
},
441 {"keys",keysCommand
,2,REDIS_CMD_INLINE
},
442 {"dbsize",dbsizeCommand
,1,REDIS_CMD_INLINE
},
443 {"auth",authCommand
,2,REDIS_CMD_INLINE
},
444 {"ping",pingCommand
,1,REDIS_CMD_INLINE
},
445 {"echo",echoCommand
,2,REDIS_CMD_BULK
},
446 {"save",saveCommand
,1,REDIS_CMD_INLINE
},
447 {"bgsave",bgsaveCommand
,1,REDIS_CMD_INLINE
},
448 {"shutdown",shutdownCommand
,1,REDIS_CMD_INLINE
},
449 {"lastsave",lastsaveCommand
,1,REDIS_CMD_INLINE
},
450 {"type",typeCommand
,2,REDIS_CMD_INLINE
},
451 {"sync",syncCommand
,1,REDIS_CMD_INLINE
},
452 {"flushdb",flushdbCommand
,1,REDIS_CMD_INLINE
},
453 {"flushall",flushallCommand
,1,REDIS_CMD_INLINE
},
454 {"sort",sortCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
455 {"info",infoCommand
,1,REDIS_CMD_INLINE
},
456 {"monitor",monitorCommand
,1,REDIS_CMD_INLINE
},
457 {"ttl",ttlCommand
,2,REDIS_CMD_INLINE
},
458 {"slaveof",slaveofCommand
,3,REDIS_CMD_INLINE
},
459 {"debug",debugCommand
,-2,REDIS_CMD_INLINE
},
462 /*============================ Utility functions ============================ */
464 /* Glob-style pattern matching. */
465 int stringmatchlen(const char *pattern
, int patternLen
,
466 const char *string
, int stringLen
, int nocase
)
471 while (pattern
[1] == '*') {
476 return 1; /* match */
478 if (stringmatchlen(pattern
+1, patternLen
-1,
479 string
, stringLen
, nocase
))
480 return 1; /* match */
484 return 0; /* no match */
488 return 0; /* no match */
498 not = pattern
[0] == '^';
505 if (pattern
[0] == '\\') {
508 if (pattern
[0] == string
[0])
510 } else if (pattern
[0] == ']') {
512 } else if (patternLen
== 0) {
516 } else if (pattern
[1] == '-' && patternLen
>= 3) {
517 int start
= pattern
[0];
518 int end
= pattern
[2];
526 start
= tolower(start
);
532 if (c
>= start
&& c
<= end
)
536 if (pattern
[0] == string
[0])
539 if (tolower((int)pattern
[0]) == tolower((int)string
[0]))
549 return 0; /* no match */
555 if (patternLen
>= 2) {
562 if (pattern
[0] != string
[0])
563 return 0; /* no match */
565 if (tolower((int)pattern
[0]) != tolower((int)string
[0]))
566 return 0; /* no match */
574 if (stringLen
== 0) {
575 while(*pattern
== '*') {
582 if (patternLen
== 0 && stringLen
== 0)
587 static void redisLog(int level
, const char *fmt
, ...) {
591 fp
= (server
.logfile
== NULL
) ? stdout
: fopen(server
.logfile
,"a");
595 if (level
>= server
.verbosity
) {
601 strftime(buf
,64,"%d %b %H:%M:%S",gmtime(&now
));
602 fprintf(fp
,"%s %c ",buf
,c
[level
]);
603 vfprintf(fp
, fmt
, ap
);
609 if (server
.logfile
) fclose(fp
);
612 /*====================== Hash table type implementation ==================== */
614 /* This is an hash table type that uses the SDS dynamic strings libary as
615 * keys and radis objects as values (objects can hold SDS strings,
618 static int sdsDictKeyCompare(void *privdata
, const void *key1
,
622 DICT_NOTUSED(privdata
);
624 l1
= sdslen((sds
)key1
);
625 l2
= sdslen((sds
)key2
);
626 if (l1
!= l2
) return 0;
627 return memcmp(key1
, key2
, l1
) == 0;
630 static void dictRedisObjectDestructor(void *privdata
, void *val
)
632 DICT_NOTUSED(privdata
);
637 static int dictSdsKeyCompare(void *privdata
, const void *key1
,
640 const robj
*o1
= key1
, *o2
= key2
;
641 return sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
644 static unsigned int dictSdsHash(const void *key
) {
646 return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
649 static dictType setDictType
= {
650 dictSdsHash
, /* hash function */
653 dictSdsKeyCompare
, /* key compare */
654 dictRedisObjectDestructor
, /* key destructor */
655 NULL
/* val destructor */
658 static dictType hashDictType
= {
659 dictSdsHash
, /* hash function */
662 dictSdsKeyCompare
, /* key compare */
663 dictRedisObjectDestructor
, /* key destructor */
664 dictRedisObjectDestructor
/* val destructor */
667 /* ========================= Random utility functions ======================= */
669 /* Redis generally does not try to recover from out of memory conditions
670 * when allocating objects or strings, it is not clear if it will be possible
671 * to report this condition to the client since the networking layer itself
672 * is based on heap allocation for send buffers, so we simply abort.
673 * At least the code will be simpler to read... */
674 static void oom(const char *msg
) {
675 fprintf(stderr
, "%s: Out of memory\n",msg
);
681 /* ====================== Redis server networking stuff ===================== */
682 static void closeTimedoutClients(void) {
685 time_t now
= time(NULL
);
687 listRewind(server
.clients
);
688 while ((ln
= listYield(server
.clients
)) != NULL
) {
689 c
= listNodeValue(ln
);
690 if (!(c
->flags
& REDIS_SLAVE
) && /* no timeout for slaves */
691 !(c
->flags
& REDIS_MASTER
) && /* no timeout for masters */
692 (now
- c
->lastinteraction
> server
.maxidletime
)) {
693 redisLog(REDIS_DEBUG
,"Closing idle client");
699 static int htNeedsResize(dict
*dict
) {
700 long long size
, used
;
702 size
= dictSlots(dict
);
703 used
= dictSize(dict
);
704 return (size
&& used
&& size
> DICT_HT_INITIAL_SIZE
&&
705 (used
*100/size
< REDIS_HT_MINFILL
));
708 /* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
709 * we resize the hash table to save memory */
710 static void tryResizeHashTables(void) {
713 for (j
= 0; j
< server
.dbnum
; j
++) {
714 if (htNeedsResize(server
.db
[j
].dict
)) {
715 redisLog(REDIS_DEBUG
,"The hash table %d is too sparse, resize it...",j
);
716 dictResize(server
.db
[j
].dict
);
717 redisLog(REDIS_DEBUG
,"Hash table %d resized.",j
);
719 if (htNeedsResize(server
.db
[j
].expires
))
720 dictResize(server
.db
[j
].expires
);
724 static int serverCron(struct aeEventLoop
*eventLoop
, long long id
, void *clientData
) {
725 int j
, loops
= server
.cronloops
++;
726 REDIS_NOTUSED(eventLoop
);
728 REDIS_NOTUSED(clientData
);
730 /* Update the global state with the amount of used memory */
731 server
.usedmemory
= zmalloc_used_memory();
733 /* Show some info about non-empty databases */
734 for (j
= 0; j
< server
.dbnum
; j
++) {
735 long long size
, used
, vkeys
;
737 size
= dictSlots(server
.db
[j
].dict
);
738 used
= dictSize(server
.db
[j
].dict
);
739 vkeys
= dictSize(server
.db
[j
].expires
);
740 if (!(loops
% 5) && (used
|| vkeys
)) {
741 redisLog(REDIS_DEBUG
,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j
,used
,vkeys
,size
);
742 /* dictPrintStats(server.dict); */
746 /* We don't want to resize the hash tables while a bacground saving
747 * is in progress: the saving child is created using fork() that is
748 * implemented with a copy-on-write semantic in most modern systems, so
749 * if we resize the HT while there is the saving child at work actually
750 * a lot of memory movements in the parent will cause a lot of pages
752 if (!server
.bgsaveinprogress
) tryResizeHashTables();
754 /* Show information about connected clients */
756 redisLog(REDIS_DEBUG
,"%d clients connected (%d slaves), %zu bytes in use, %d shared objects",
757 listLength(server
.clients
)-listLength(server
.slaves
),
758 listLength(server
.slaves
),
760 dictSize(server
.sharingpool
));
763 /* Close connections of timedout clients */
764 if (server
.maxidletime
&& !(loops
% 10))
765 closeTimedoutClients();
767 /* Check if a background saving in progress terminated */
768 if (server
.bgsaveinprogress
) {
770 if (wait4(-1,&statloc
,WNOHANG
,NULL
)) {
771 int exitcode
= WEXITSTATUS(statloc
);
772 int bysignal
= WIFSIGNALED(statloc
);
774 if (!bysignal
&& exitcode
== 0) {
775 redisLog(REDIS_NOTICE
,
776 "Background saving terminated with success");
778 server
.lastsave
= time(NULL
);
779 } else if (!bysignal
&& exitcode
!= 0) {
780 redisLog(REDIS_WARNING
, "Background saving error");
782 redisLog(REDIS_WARNING
,
783 "Background saving terminated by signal");
784 rdbRemoveTempFile(server
.bgsavechildpid
);
786 server
.bgsaveinprogress
= 0;
787 server
.bgsavechildpid
= -1;
788 updateSlavesWaitingBgsave(exitcode
== 0 ? REDIS_OK
: REDIS_ERR
);
791 /* If there is not a background saving in progress check if
792 * we have to save now */
793 time_t now
= time(NULL
);
794 for (j
= 0; j
< server
.saveparamslen
; j
++) {
795 struct saveparam
*sp
= server
.saveparams
+j
;
797 if (server
.dirty
>= sp
->changes
&&
798 now
-server
.lastsave
> sp
->seconds
) {
799 redisLog(REDIS_NOTICE
,"%d changes in %d seconds. Saving...",
800 sp
->changes
, sp
->seconds
);
801 rdbSaveBackground(server
.dbfilename
);
807 /* Try to expire a few timed out keys */
808 for (j
= 0; j
< server
.dbnum
; j
++) {
809 redisDb
*db
= server
.db
+j
;
810 int num
= dictSize(db
->expires
);
813 time_t now
= time(NULL
);
815 if (num
> REDIS_EXPIRELOOKUPS_PER_CRON
)
816 num
= REDIS_EXPIRELOOKUPS_PER_CRON
;
821 if ((de
= dictGetRandomKey(db
->expires
)) == NULL
) break;
822 t
= (time_t) dictGetEntryVal(de
);
824 deleteKey(db
,dictGetEntryKey(de
));
830 /* Check if we should connect to a MASTER */
831 if (server
.replstate
== REDIS_REPL_CONNECT
) {
832 redisLog(REDIS_NOTICE
,"Connecting to MASTER...");
833 if (syncWithMaster() == REDIS_OK
) {
834 redisLog(REDIS_NOTICE
,"MASTER <-> SLAVE sync succeeded");
840 static void createSharedObjects(void) {
841 shared
.crlf
= createObject(REDIS_STRING
,sdsnew("\r\n"));
842 shared
.ok
= createObject(REDIS_STRING
,sdsnew("+OK\r\n"));
843 shared
.err
= createObject(REDIS_STRING
,sdsnew("-ERR\r\n"));
844 shared
.emptybulk
= createObject(REDIS_STRING
,sdsnew("$0\r\n\r\n"));
845 shared
.czero
= createObject(REDIS_STRING
,sdsnew(":0\r\n"));
846 shared
.cone
= createObject(REDIS_STRING
,sdsnew(":1\r\n"));
847 shared
.nullbulk
= createObject(REDIS_STRING
,sdsnew("$-1\r\n"));
848 shared
.nullmultibulk
= createObject(REDIS_STRING
,sdsnew("*-1\r\n"));
849 shared
.emptymultibulk
= createObject(REDIS_STRING
,sdsnew("*0\r\n"));
851 shared
.pong
= createObject(REDIS_STRING
,sdsnew("+PONG\r\n"));
852 shared
.wrongtypeerr
= createObject(REDIS_STRING
,sdsnew(
853 "-ERR Operation against a key holding the wrong kind of value\r\n"));
854 shared
.nokeyerr
= createObject(REDIS_STRING
,sdsnew(
855 "-ERR no such key\r\n"));
856 shared
.syntaxerr
= createObject(REDIS_STRING
,sdsnew(
857 "-ERR syntax error\r\n"));
858 shared
.sameobjecterr
= createObject(REDIS_STRING
,sdsnew(
859 "-ERR source and destination objects are the same\r\n"));
860 shared
.outofrangeerr
= createObject(REDIS_STRING
,sdsnew(
861 "-ERR index out of range\r\n"));
862 shared
.space
= createObject(REDIS_STRING
,sdsnew(" "));
863 shared
.colon
= createObject(REDIS_STRING
,sdsnew(":"));
864 shared
.plus
= createObject(REDIS_STRING
,sdsnew("+"));
865 shared
.select0
= createStringObject("select 0\r\n",10);
866 shared
.select1
= createStringObject("select 1\r\n",10);
867 shared
.select2
= createStringObject("select 2\r\n",10);
868 shared
.select3
= createStringObject("select 3\r\n",10);
869 shared
.select4
= createStringObject("select 4\r\n",10);
870 shared
.select5
= createStringObject("select 5\r\n",10);
871 shared
.select6
= createStringObject("select 6\r\n",10);
872 shared
.select7
= createStringObject("select 7\r\n",10);
873 shared
.select8
= createStringObject("select 8\r\n",10);
874 shared
.select9
= createStringObject("select 9\r\n",10);
877 static void appendServerSaveParams(time_t seconds
, int changes
) {
878 server
.saveparams
= zrealloc(server
.saveparams
,sizeof(struct saveparam
)*(server
.saveparamslen
+1));
879 if (server
.saveparams
== NULL
) oom("appendServerSaveParams");
880 server
.saveparams
[server
.saveparamslen
].seconds
= seconds
;
881 server
.saveparams
[server
.saveparamslen
].changes
= changes
;
882 server
.saveparamslen
++;
885 static void ResetServerSaveParams() {
886 zfree(server
.saveparams
);
887 server
.saveparams
= NULL
;
888 server
.saveparamslen
= 0;
891 static void initServerConfig() {
892 server
.dbnum
= REDIS_DEFAULT_DBNUM
;
893 server
.port
= REDIS_SERVERPORT
;
894 server
.verbosity
= REDIS_DEBUG
;
895 server
.maxidletime
= REDIS_MAXIDLETIME
;
896 server
.saveparams
= NULL
;
897 server
.logfile
= NULL
; /* NULL = log on standard output */
898 server
.bindaddr
= NULL
;
899 server
.glueoutputbuf
= 1;
900 server
.daemonize
= 0;
901 server
.pidfile
= "/var/run/redis.pid";
902 server
.dbfilename
= "dump.rdb";
903 server
.requirepass
= NULL
;
904 server
.shareobjects
= 0;
905 server
.sharingpoolsize
= 1024;
906 server
.maxclients
= 0;
907 server
.maxmemory
= 0;
908 ResetServerSaveParams();
910 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
911 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
912 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
913 /* Replication related */
915 server
.masterhost
= NULL
;
916 server
.masterport
= 6379;
917 server
.master
= NULL
;
918 server
.replstate
= REDIS_REPL_NONE
;
921 static void initServer() {
924 signal(SIGHUP
, SIG_IGN
);
925 signal(SIGPIPE
, SIG_IGN
);
926 setupSigSegvAction();
928 server
.clients
= listCreate();
929 server
.slaves
= listCreate();
930 server
.monitors
= listCreate();
931 server
.objfreelist
= listCreate();
932 createSharedObjects();
933 server
.el
= aeCreateEventLoop();
934 server
.db
= zmalloc(sizeof(redisDb
)*server
.dbnum
);
935 server
.sharingpool
= dictCreate(&setDictType
,NULL
);
936 if (!server
.db
|| !server
.clients
|| !server
.slaves
|| !server
.monitors
|| !server
.el
|| !server
.objfreelist
)
937 oom("server initialization"); /* Fatal OOM */
938 server
.fd
= anetTcpServer(server
.neterr
, server
.port
, server
.bindaddr
);
939 if (server
.fd
== -1) {
940 redisLog(REDIS_WARNING
, "Opening TCP port: %s", server
.neterr
);
943 for (j
= 0; j
< server
.dbnum
; j
++) {
944 server
.db
[j
].dict
= dictCreate(&hashDictType
,NULL
);
945 server
.db
[j
].expires
= dictCreate(&setDictType
,NULL
);
948 server
.cronloops
= 0;
949 server
.bgsaveinprogress
= 0;
950 server
.bgsavechildpid
= -1;
951 server
.lastsave
= time(NULL
);
953 server
.usedmemory
= 0;
954 server
.stat_numcommands
= 0;
955 server
.stat_numconnections
= 0;
956 server
.stat_starttime
= time(NULL
);
957 aeCreateTimeEvent(server
.el
, 1000, serverCron
, NULL
, NULL
);
960 /* Empty the whole database */
961 static long long emptyDb() {
963 long long removed
= 0;
965 for (j
= 0; j
< server
.dbnum
; j
++) {
966 removed
+= dictSize(server
.db
[j
].dict
);
967 dictEmpty(server
.db
[j
].dict
);
968 dictEmpty(server
.db
[j
].expires
);
973 static int yesnotoi(char *s
) {
974 if (!strcasecmp(s
,"yes")) return 1;
975 else if (!strcasecmp(s
,"no")) return 0;
979 /* I agree, this is a very rudimental way to load a configuration...
980 will improve later if the config gets more complex */
981 static void loadServerConfig(char *filename
) {
983 char buf
[REDIS_CONFIGLINE_MAX
+1], *err
= NULL
;
987 if (filename
[0] == '-' && filename
[1] == '\0')
990 if ((fp
= fopen(filename
,"r")) == NULL
) {
991 redisLog(REDIS_WARNING
,"Fatal error, can't open config file");
996 while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) {
1002 line
= sdstrim(line
," \t\r\n");
1004 /* Skip comments and blank lines*/
1005 if (line
[0] == '#' || line
[0] == '\0') {
1010 /* Split into arguments */
1011 argv
= sdssplitlen(line
,sdslen(line
)," ",1,&argc
);
1012 sdstolower(argv
[0]);
1014 /* Execute config directives */
1015 if (!strcasecmp(argv
[0],"timeout") && argc
== 2) {
1016 server
.maxidletime
= atoi(argv
[1]);
1017 if (server
.maxidletime
< 0) {
1018 err
= "Invalid timeout value"; goto loaderr
;
1020 } else if (!strcasecmp(argv
[0],"port") && argc
== 2) {
1021 server
.port
= atoi(argv
[1]);
1022 if (server
.port
< 1 || server
.port
> 65535) {
1023 err
= "Invalid port"; goto loaderr
;
1025 } else if (!strcasecmp(argv
[0],"bind") && argc
== 2) {
1026 server
.bindaddr
= zstrdup(argv
[1]);
1027 } else if (!strcasecmp(argv
[0],"save") && argc
== 3) {
1028 int seconds
= atoi(argv
[1]);
1029 int changes
= atoi(argv
[2]);
1030 if (seconds
< 1 || changes
< 0) {
1031 err
= "Invalid save parameters"; goto loaderr
;
1033 appendServerSaveParams(seconds
,changes
);
1034 } else if (!strcasecmp(argv
[0],"dir") && argc
== 2) {
1035 if (chdir(argv
[1]) == -1) {
1036 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s",
1037 argv
[1], strerror(errno
));
1040 } else if (!strcasecmp(argv
[0],"loglevel") && argc
== 2) {
1041 if (!strcasecmp(argv
[1],"debug")) server
.verbosity
= REDIS_DEBUG
;
1042 else if (!strcasecmp(argv
[1],"notice")) server
.verbosity
= REDIS_NOTICE
;
1043 else if (!strcasecmp(argv
[1],"warning")) server
.verbosity
= REDIS_WARNING
;
1045 err
= "Invalid log level. Must be one of debug, notice, warning";
1048 } else if (!strcasecmp(argv
[0],"logfile") && argc
== 2) {
1051 server
.logfile
= zstrdup(argv
[1]);
1052 if (!strcasecmp(server
.logfile
,"stdout")) {
1053 zfree(server
.logfile
);
1054 server
.logfile
= NULL
;
1056 if (server
.logfile
) {
1057 /* Test if we are able to open the file. The server will not
1058 * be able to abort just for this problem later... */
1059 logfp
= fopen(server
.logfile
,"a");
1060 if (logfp
== NULL
) {
1061 err
= sdscatprintf(sdsempty(),
1062 "Can't open the log file: %s", strerror(errno
));
1067 } else if (!strcasecmp(argv
[0],"databases") && argc
== 2) {
1068 server
.dbnum
= atoi(argv
[1]);
1069 if (server
.dbnum
< 1) {
1070 err
= "Invalid number of databases"; goto loaderr
;
1072 } else if (!strcasecmp(argv
[0],"maxclients") && argc
== 2) {
1073 server
.maxclients
= atoi(argv
[1]);
1074 } else if (!strcasecmp(argv
[0],"maxmemory") && argc
== 2) {
1075 server
.maxmemory
= atoi(argv
[1]);
1076 } else if (!strcasecmp(argv
[0],"slaveof") && argc
== 3) {
1077 server
.masterhost
= sdsnew(argv
[1]);
1078 server
.masterport
= atoi(argv
[2]);
1079 server
.replstate
= REDIS_REPL_CONNECT
;
1080 } else if (!strcasecmp(argv
[0],"glueoutputbuf") && argc
== 2) {
1081 if ((server
.glueoutputbuf
= yesnotoi(argv
[1])) == -1) {
1082 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1084 } else if (!strcasecmp(argv
[0],"shareobjects") && argc
== 2) {
1085 if ((server
.shareobjects
= yesnotoi(argv
[1])) == -1) {
1086 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1088 } else if (!strcasecmp(argv
[0],"shareobjectspoolsize") && argc
== 2) {
1089 server
.sharingpoolsize
= atoi(argv
[1]);
1090 if (server
.sharingpoolsize
< 1) {
1091 err
= "invalid object sharing pool size"; goto loaderr
;
1093 } else if (!strcasecmp(argv
[0],"daemonize") && argc
== 2) {
1094 if ((server
.daemonize
= yesnotoi(argv
[1])) == -1) {
1095 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1097 } else if (!strcasecmp(argv
[0],"requirepass") && argc
== 2) {
1098 server
.requirepass
= zstrdup(argv
[1]);
1099 } else if (!strcasecmp(argv
[0],"pidfile") && argc
== 2) {
1100 server
.pidfile
= zstrdup(argv
[1]);
1101 } else if (!strcasecmp(argv
[0],"dbfilename") && argc
== 2) {
1102 server
.dbfilename
= zstrdup(argv
[1]);
1104 err
= "Bad directive or wrong number of arguments"; goto loaderr
;
1106 for (j
= 0; j
< argc
; j
++)
1111 if (fp
!= stdin
) fclose(fp
);
1115 fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n");
1116 fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
);
1117 fprintf(stderr
, ">>> '%s'\n", line
);
1118 fprintf(stderr
, "%s\n", err
);
1122 static void freeClientArgv(redisClient
*c
) {
1125 for (j
= 0; j
< c
->argc
; j
++)
1126 decrRefCount(c
->argv
[j
]);
1130 static void freeClient(redisClient
*c
) {
1133 aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
);
1134 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1135 sdsfree(c
->querybuf
);
1136 listRelease(c
->reply
);
1139 ln
= listSearchKey(server
.clients
,c
);
1141 listDelNode(server
.clients
,ln
);
1142 if (c
->flags
& REDIS_SLAVE
) {
1143 if (c
->replstate
== REDIS_REPL_SEND_BULK
&& c
->repldbfd
!= -1)
1145 list
*l
= (c
->flags
& REDIS_MONITOR
) ? server
.monitors
: server
.slaves
;
1146 ln
= listSearchKey(l
,c
);
1150 if (c
->flags
& REDIS_MASTER
) {
1151 server
.master
= NULL
;
1152 server
.replstate
= REDIS_REPL_CONNECT
;
1158 static void glueReplyBuffersIfNeeded(redisClient
*c
) {
1163 listRewind(c
->reply
);
1164 while((ln
= listYield(c
->reply
))) {
1166 totlen
+= sdslen(o
->ptr
);
1167 /* This optimization makes more sense if we don't have to copy
1169 if (totlen
> 1024) return;
1175 listRewind(c
->reply
);
1176 while((ln
= listYield(c
->reply
))) {
1178 memcpy(buf
+copylen
,o
->ptr
,sdslen(o
->ptr
));
1179 copylen
+= sdslen(o
->ptr
);
1180 listDelNode(c
->reply
,ln
);
1182 /* Now the output buffer is empty, add the new single element */
1183 o
= createObject(REDIS_STRING
,sdsnewlen(buf
,totlen
));
1184 if (!listAddNodeTail(c
->reply
,o
)) oom("listAddNodeTail");
1188 static void sendReplyToClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1189 redisClient
*c
= privdata
;
1190 int nwritten
= 0, totwritten
= 0, objlen
;
1193 REDIS_NOTUSED(mask
);
1195 if (server
.glueoutputbuf
&& listLength(c
->reply
) > 1)
1196 glueReplyBuffersIfNeeded(c
);
1197 while(listLength(c
->reply
)) {
1198 o
= listNodeValue(listFirst(c
->reply
));
1199 objlen
= sdslen(o
->ptr
);
1202 listDelNode(c
->reply
,listFirst(c
->reply
));
1206 if (c
->flags
& REDIS_MASTER
) {
1207 /* Don't reply to a master */
1208 nwritten
= objlen
- c
->sentlen
;
1210 nwritten
= write(fd
, ((char*)o
->ptr
)+c
->sentlen
, objlen
- c
->sentlen
);
1211 if (nwritten
<= 0) break;
1213 c
->sentlen
+= nwritten
;
1214 totwritten
+= nwritten
;
1215 /* If we fully sent the object on head go to the next one */
1216 if (c
->sentlen
== objlen
) {
1217 listDelNode(c
->reply
,listFirst(c
->reply
));
1220 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
1221 * bytes, in a single threaded server it's a good idea to server
1222 * other clients as well, even if a very large request comes from
1223 * super fast link that is always able to accept data (in real world
1224 * terms think to 'KEYS *' against the loopback interfae) */
1225 if (totwritten
> REDIS_MAX_WRITE_PER_EVENT
) break;
1227 if (nwritten
== -1) {
1228 if (errno
== EAGAIN
) {
1231 redisLog(REDIS_DEBUG
,
1232 "Error writing to client: %s", strerror(errno
));
1237 if (totwritten
> 0) c
->lastinteraction
= time(NULL
);
1238 if (listLength(c
->reply
) == 0) {
1240 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1244 static struct redisCommand
*lookupCommand(char *name
) {
1246 while(cmdTable
[j
].name
!= NULL
) {
1247 if (!strcasecmp(name
,cmdTable
[j
].name
)) return &cmdTable
[j
];
1253 /* resetClient prepare the client to process the next command */
1254 static void resetClient(redisClient
*c
) {
1259 /* If this function gets called we already read a whole
1260 * command, argments are in the client argv/argc fields.
1261 * processCommand() execute the command or prepare the
1262 * server for a bulk read from the client.
1264 * If 1 is returned the client is still alive and valid and
1265 * and other operations can be performed by the caller. Otherwise
1266 * if 0 is returned the client was destroied (i.e. after QUIT). */
1267 static int processCommand(redisClient
*c
) {
1268 struct redisCommand
*cmd
;
1271 /* Free some memory if needed (maxmemory setting) */
1272 if (server
.maxmemory
) freeMemoryIfNeeded();
1274 /* The QUIT command is handled as a special case. Normal command
1275 * procs are unable to close the client connection safely */
1276 if (!strcasecmp(c
->argv
[0]->ptr
,"quit")) {
1280 cmd
= lookupCommand(c
->argv
[0]->ptr
);
1282 addReplySds(c
,sdsnew("-ERR unknown command\r\n"));
1285 } else if ((cmd
->arity
> 0 && cmd
->arity
!= c
->argc
) ||
1286 (c
->argc
< -cmd
->arity
)) {
1287 addReplySds(c
,sdsnew("-ERR wrong number of arguments\r\n"));
1290 } else if (server
.maxmemory
&& cmd
->flags
& REDIS_CMD_DENYOOM
&& zmalloc_used_memory() > server
.maxmemory
) {
1291 addReplySds(c
,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
1294 } else if (cmd
->flags
& REDIS_CMD_BULK
&& c
->bulklen
== -1) {
1295 int bulklen
= atoi(c
->argv
[c
->argc
-1]->ptr
);
1297 decrRefCount(c
->argv
[c
->argc
-1]);
1298 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
1300 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
1305 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
1306 /* It is possible that the bulk read is already in the
1307 * buffer. Check this condition and handle it accordingly */
1308 if ((signed)sdslen(c
->querybuf
) >= c
->bulklen
) {
1309 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
1311 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
1316 /* Let's try to share objects on the command arguments vector */
1317 if (server
.shareobjects
) {
1319 for(j
= 1; j
< c
->argc
; j
++)
1320 c
->argv
[j
] = tryObjectSharing(c
->argv
[j
]);
1322 /* Check if the user is authenticated */
1323 if (server
.requirepass
&& !c
->authenticated
&& cmd
->proc
!= authCommand
) {
1324 addReplySds(c
,sdsnew("-ERR operation not permitted\r\n"));
1329 /* Exec the command */
1330 dirty
= server
.dirty
;
1332 if (server
.dirty
-dirty
!= 0 && listLength(server
.slaves
))
1333 replicationFeedSlaves(server
.slaves
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1334 if (listLength(server
.monitors
))
1335 replicationFeedSlaves(server
.monitors
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1336 server
.stat_numcommands
++;
1338 /* Prepare the client for the next command */
1339 if (c
->flags
& REDIS_CLOSE
) {
1347 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
) {
1351 /* (args*2)+1 is enough room for args, spaces, newlines */
1352 robj
*static_outv
[REDIS_STATIC_ARGS
*2+1];
1354 if (argc
<= REDIS_STATIC_ARGS
) {
1357 outv
= zmalloc(sizeof(robj
*)*(argc
*2+1));
1358 if (!outv
) oom("replicationFeedSlaves");
1361 for (j
= 0; j
< argc
; j
++) {
1362 if (j
!= 0) outv
[outc
++] = shared
.space
;
1363 if ((cmd
->flags
& REDIS_CMD_BULK
) && j
== argc
-1) {
1366 lenobj
= createObject(REDIS_STRING
,
1367 sdscatprintf(sdsempty(),"%d\r\n",sdslen(argv
[j
]->ptr
)));
1368 lenobj
->refcount
= 0;
1369 outv
[outc
++] = lenobj
;
1371 outv
[outc
++] = argv
[j
];
1373 outv
[outc
++] = shared
.crlf
;
1375 /* Increment all the refcounts at start and decrement at end in order to
1376 * be sure to free objects if there is no slave in a replication state
1377 * able to be feed with commands */
1378 for (j
= 0; j
< outc
; j
++) incrRefCount(outv
[j
]);
1380 while((ln
= listYield(slaves
))) {
1381 redisClient
*slave
= ln
->value
;
1383 /* Don't feed slaves that are still waiting for BGSAVE to start */
1384 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) continue;
1386 /* Feed all the other slaves, MONITORs and so on */
1387 if (slave
->slaveseldb
!= dictid
) {
1391 case 0: selectcmd
= shared
.select0
; break;
1392 case 1: selectcmd
= shared
.select1
; break;
1393 case 2: selectcmd
= shared
.select2
; break;
1394 case 3: selectcmd
= shared
.select3
; break;
1395 case 4: selectcmd
= shared
.select4
; break;
1396 case 5: selectcmd
= shared
.select5
; break;
1397 case 6: selectcmd
= shared
.select6
; break;
1398 case 7: selectcmd
= shared
.select7
; break;
1399 case 8: selectcmd
= shared
.select8
; break;
1400 case 9: selectcmd
= shared
.select9
; break;
1402 selectcmd
= createObject(REDIS_STRING
,
1403 sdscatprintf(sdsempty(),"select %d\r\n",dictid
));
1404 selectcmd
->refcount
= 0;
1407 addReply(slave
,selectcmd
);
1408 slave
->slaveseldb
= dictid
;
1410 for (j
= 0; j
< outc
; j
++) addReply(slave
,outv
[j
]);
1412 for (j
= 0; j
< outc
; j
++) decrRefCount(outv
[j
]);
1413 if (outv
!= static_outv
) zfree(outv
);
1416 static void readQueryFromClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1417 redisClient
*c
= (redisClient
*) privdata
;
1418 char buf
[REDIS_IOBUF_LEN
];
1421 REDIS_NOTUSED(mask
);
1423 nread
= read(fd
, buf
, REDIS_IOBUF_LEN
);
1425 if (errno
== EAGAIN
) {
1428 redisLog(REDIS_DEBUG
, "Reading from client: %s",strerror(errno
));
1432 } else if (nread
== 0) {
1433 redisLog(REDIS_DEBUG
, "Client closed connection");
1438 c
->querybuf
= sdscatlen(c
->querybuf
, buf
, nread
);
1439 c
->lastinteraction
= time(NULL
);
1445 if (c
->bulklen
== -1) {
1446 /* Read the first line of the query */
1447 char *p
= strchr(c
->querybuf
,'\n');
1454 query
= c
->querybuf
;
1455 c
->querybuf
= sdsempty();
1456 querylen
= 1+(p
-(query
));
1457 if (sdslen(query
) > querylen
) {
1458 /* leave data after the first line of the query in the buffer */
1459 c
->querybuf
= sdscatlen(c
->querybuf
,query
+querylen
,sdslen(query
)-querylen
);
1461 *p
= '\0'; /* remove "\n" */
1462 if (*(p
-1) == '\r') *(p
-1) = '\0'; /* and "\r" if any */
1463 sdsupdatelen(query
);
1465 /* Now we can split the query in arguments */
1466 if (sdslen(query
) == 0) {
1467 /* Ignore empty query */
1471 argv
= sdssplitlen(query
,sdslen(query
)," ",1,&argc
);
1472 if (argv
== NULL
) oom("sdssplitlen");
1475 if (c
->argv
) zfree(c
->argv
);
1476 c
->argv
= zmalloc(sizeof(robj
*)*argc
);
1477 if (c
->argv
== NULL
) oom("allocating arguments list for client");
1479 for (j
= 0; j
< argc
; j
++) {
1480 if (sdslen(argv
[j
])) {
1481 c
->argv
[c
->argc
] = createObject(REDIS_STRING
,argv
[j
]);
1488 /* Execute the command. If the client is still valid
1489 * after processCommand() return and there is something
1490 * on the query buffer try to process the next command. */
1491 if (c
->argc
&& processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
1493 } else if (sdslen(c
->querybuf
) >= REDIS_REQUEST_MAX_SIZE
) {
1494 redisLog(REDIS_DEBUG
, "Client protocol error");
1499 /* Bulk read handling. Note that if we are at this point
1500 the client already sent a command terminated with a newline,
1501 we are reading the bulk data that is actually the last
1502 argument of the command. */
1503 int qbl
= sdslen(c
->querybuf
);
1505 if (c
->bulklen
<= qbl
) {
1506 /* Copy everything but the final CRLF as final argument */
1507 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
1509 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
1516 static int selectDb(redisClient
*c
, int id
) {
1517 if (id
< 0 || id
>= server
.dbnum
)
1519 c
->db
= &server
.db
[id
];
1523 static void *dupClientReplyValue(void *o
) {
1524 incrRefCount((robj
*)o
);
1528 static redisClient
*createClient(int fd
) {
1529 redisClient
*c
= zmalloc(sizeof(*c
));
1531 anetNonBlock(NULL
,fd
);
1532 anetTcpNoDelay(NULL
,fd
);
1533 if (!c
) return NULL
;
1536 c
->querybuf
= sdsempty();
1542 c
->lastinteraction
= time(NULL
);
1543 c
->authenticated
= 0;
1544 c
->replstate
= REDIS_REPL_NONE
;
1545 if ((c
->reply
= listCreate()) == NULL
) oom("listCreate");
1546 listSetFreeMethod(c
->reply
,decrRefCount
);
1547 listSetDupMethod(c
->reply
,dupClientReplyValue
);
1548 if (aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
,
1549 readQueryFromClient
, c
, NULL
) == AE_ERR
) {
1553 if (!listAddNodeTail(server
.clients
,c
)) oom("listAddNodeTail");
1557 static void addReply(redisClient
*c
, robj
*obj
) {
1558 if (listLength(c
->reply
) == 0 &&
1559 (c
->replstate
== REDIS_REPL_NONE
||
1560 c
->replstate
== REDIS_REPL_ONLINE
) &&
1561 aeCreateFileEvent(server
.el
, c
->fd
, AE_WRITABLE
,
1562 sendReplyToClient
, c
, NULL
) == AE_ERR
) return;
1563 if (!listAddNodeTail(c
->reply
,obj
)) oom("listAddNodeTail");
1567 static void addReplySds(redisClient
*c
, sds s
) {
1568 robj
*o
= createObject(REDIS_STRING
,s
);
1573 static void acceptHandler(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1578 REDIS_NOTUSED(mask
);
1579 REDIS_NOTUSED(privdata
);
1581 cfd
= anetAccept(server
.neterr
, fd
, cip
, &cport
);
1582 if (cfd
== AE_ERR
) {
1583 redisLog(REDIS_DEBUG
,"Accepting client connection: %s", server
.neterr
);
1586 redisLog(REDIS_DEBUG
,"Accepted %s:%d", cip
, cport
);
1587 if ((c
= createClient(cfd
)) == NULL
) {
1588 redisLog(REDIS_WARNING
,"Error allocating resoures for the client");
1589 close(cfd
); /* May be already closed, just ingore errors */
1592 /* If maxclient directive is set and this is one client more... close the
1593 * connection. Note that we create the client instead to check before
1594 * for this condition, since now the socket is already set in nonblocking
1595 * mode and we can send an error for free using the Kernel I/O */
1596 if (server
.maxclients
&& listLength(server
.clients
) > server
.maxclients
) {
1597 char *err
= "-ERR max number of clients reached\r\n";
1599 /* That's a best effort error message, don't check write errors */
1600 (void) write(c
->fd
,err
,strlen(err
));
1604 server
.stat_numconnections
++;
1607 /* ======================= Redis objects implementation ===================== */
1609 static robj
*createObject(int type
, void *ptr
) {
1612 if (listLength(server
.objfreelist
)) {
1613 listNode
*head
= listFirst(server
.objfreelist
);
1614 o
= listNodeValue(head
);
1615 listDelNode(server
.objfreelist
,head
);
1617 o
= zmalloc(sizeof(*o
));
1619 if (!o
) oom("createObject");
1626 static robj
*createStringObject(char *ptr
, size_t len
) {
1627 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
1630 static robj
*createListObject(void) {
1631 list
*l
= listCreate();
1633 if (!l
) oom("listCreate");
1634 listSetFreeMethod(l
,decrRefCount
);
1635 return createObject(REDIS_LIST
,l
);
1638 static robj
*createSetObject(void) {
1639 dict
*d
= dictCreate(&setDictType
,NULL
);
1640 if (!d
) oom("dictCreate");
1641 return createObject(REDIS_SET
,d
);
1644 static void freeStringObject(robj
*o
) {
1648 static void freeListObject(robj
*o
) {
1649 listRelease((list
*) o
->ptr
);
1652 static void freeSetObject(robj
*o
) {
1653 dictRelease((dict
*) o
->ptr
);
1656 static void freeHashObject(robj
*o
) {
1657 dictRelease((dict
*) o
->ptr
);
1660 static void incrRefCount(robj
*o
) {
1662 #ifdef DEBUG_REFCOUNT
1663 if (o
->type
== REDIS_STRING
)
1664 printf("Increment '%s'(%p), now is: %d\n",o
->ptr
,o
,o
->refcount
);
1668 static void decrRefCount(void *obj
) {
1671 #ifdef DEBUG_REFCOUNT
1672 if (o
->type
== REDIS_STRING
)
1673 printf("Decrement '%s'(%p), now is: %d\n",o
->ptr
,o
,o
->refcount
-1);
1675 if (--(o
->refcount
) == 0) {
1677 case REDIS_STRING
: freeStringObject(o
); break;
1678 case REDIS_LIST
: freeListObject(o
); break;
1679 case REDIS_SET
: freeSetObject(o
); break;
1680 case REDIS_HASH
: freeHashObject(o
); break;
1681 default: assert(0 != 0); break;
1683 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
1684 !listAddNodeHead(server
.objfreelist
,o
))
1689 /* Try to share an object against the shared objects pool */
1690 static robj
*tryObjectSharing(robj
*o
) {
1691 struct dictEntry
*de
;
1694 if (o
== NULL
|| server
.shareobjects
== 0) return o
;
1696 assert(o
->type
== REDIS_STRING
);
1697 de
= dictFind(server
.sharingpool
,o
);
1699 robj
*shared
= dictGetEntryKey(de
);
1701 c
= ((unsigned long) dictGetEntryVal(de
))+1;
1702 dictGetEntryVal(de
) = (void*) c
;
1703 incrRefCount(shared
);
1707 /* Here we are using a stream algorihtm: Every time an object is
1708 * shared we increment its count, everytime there is a miss we
1709 * recrement the counter of a random object. If this object reaches
1710 * zero we remove the object and put the current object instead. */
1711 if (dictSize(server
.sharingpool
) >=
1712 server
.sharingpoolsize
) {
1713 de
= dictGetRandomKey(server
.sharingpool
);
1715 c
= ((unsigned long) dictGetEntryVal(de
))-1;
1716 dictGetEntryVal(de
) = (void*) c
;
1718 dictDelete(server
.sharingpool
,de
->key
);
1721 c
= 0; /* If the pool is empty we want to add this object */
1726 retval
= dictAdd(server
.sharingpool
,o
,(void*)1);
1727 assert(retval
== DICT_OK
);
1734 static robj
*lookupKey(redisDb
*db
, robj
*key
) {
1735 dictEntry
*de
= dictFind(db
->dict
,key
);
1736 return de
? dictGetEntryVal(de
) : NULL
;
1739 static robj
*lookupKeyRead(redisDb
*db
, robj
*key
) {
1740 expireIfNeeded(db
,key
);
1741 return lookupKey(db
,key
);
1744 static robj
*lookupKeyWrite(redisDb
*db
, robj
*key
) {
1745 deleteIfVolatile(db
,key
);
1746 return lookupKey(db
,key
);
1749 static int deleteKey(redisDb
*db
, robj
*key
) {
1752 /* We need to protect key from destruction: after the first dictDelete()
1753 * it may happen that 'key' is no longer valid if we don't increment
1754 * it's count. This may happen when we get the object reference directly
1755 * from the hash table with dictRandomKey() or dict iterators */
1757 if (dictSize(db
->expires
)) dictDelete(db
->expires
,key
);
1758 retval
= dictDelete(db
->dict
,key
);
1761 return retval
== DICT_OK
;
1764 /*============================ DB saving/loading ============================ */
1766 static int rdbSaveType(FILE *fp
, unsigned char type
) {
1767 if (fwrite(&type
,1,1,fp
) == 0) return -1;
1771 static int rdbSaveTime(FILE *fp
, time_t t
) {
1772 int32_t t32
= (int32_t) t
;
1773 if (fwrite(&t32
,4,1,fp
) == 0) return -1;
1777 /* check rdbLoadLen() comments for more info */
1778 static int rdbSaveLen(FILE *fp
, uint32_t len
) {
1779 unsigned char buf
[2];
1782 /* Save a 6 bit len */
1783 buf
[0] = (len
&0xFF)|(REDIS_RDB_6BITLEN
<<6);
1784 if (fwrite(buf
,1,1,fp
) == 0) return -1;
1785 } else if (len
< (1<<14)) {
1786 /* Save a 14 bit len */
1787 buf
[0] = ((len
>>8)&0xFF)|(REDIS_RDB_14BITLEN
<<6);
1789 if (fwrite(buf
,2,1,fp
) == 0) return -1;
1791 /* Save a 32 bit len */
1792 buf
[0] = (REDIS_RDB_32BITLEN
<<6);
1793 if (fwrite(buf
,1,1,fp
) == 0) return -1;
1795 if (fwrite(&len
,4,1,fp
) == 0) return -1;
1800 /* String objects in the form "2391" "-100" without any space and with a
1801 * range of values that can fit in an 8, 16 or 32 bit signed value can be
1802 * encoded as integers to save space */
1803 static int rdbTryIntegerEncoding(sds s
, unsigned char *enc
) {
1805 char *endptr
, buf
[32];
1807 /* Check if it's possible to encode this value as a number */
1808 value
= strtoll(s
, &endptr
, 10);
1809 if (endptr
[0] != '\0') return 0;
1810 snprintf(buf
,32,"%lld",value
);
1812 /* If the number converted back into a string is not identical
1813 * then it's not possible to encode the string as integer */
1814 if (strlen(buf
) != sdslen(s
) || memcmp(buf
,s
,sdslen(s
))) return 0;
1816 /* Finally check if it fits in our ranges */
1817 if (value
>= -(1<<7) && value
<= (1<<7)-1) {
1818 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT8
;
1819 enc
[1] = value
&0xFF;
1821 } else if (value
>= -(1<<15) && value
<= (1<<15)-1) {
1822 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT16
;
1823 enc
[1] = value
&0xFF;
1824 enc
[2] = (value
>>8)&0xFF;
1826 } else if (value
>= -((long long)1<<31) && value
<= ((long long)1<<31)-1) {
1827 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT32
;
1828 enc
[1] = value
&0xFF;
1829 enc
[2] = (value
>>8)&0xFF;
1830 enc
[3] = (value
>>16)&0xFF;
1831 enc
[4] = (value
>>24)&0xFF;
1838 static int rdbSaveLzfStringObject(FILE *fp
, robj
*obj
) {
1839 unsigned int comprlen
, outlen
;
1843 /* We require at least four bytes compression for this to be worth it */
1844 outlen
= sdslen(obj
->ptr
)-4;
1845 if (outlen
<= 0) return 0;
1846 if ((out
= zmalloc(outlen
+1)) == NULL
) return 0;
1847 comprlen
= lzf_compress(obj
->ptr
, sdslen(obj
->ptr
), out
, outlen
);
1848 if (comprlen
== 0) {
1852 /* Data compressed! Let's save it on disk */
1853 byte
= (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_LZF
;
1854 if (fwrite(&byte
,1,1,fp
) == 0) goto writeerr
;
1855 if (rdbSaveLen(fp
,comprlen
) == -1) goto writeerr
;
1856 if (rdbSaveLen(fp
,sdslen(obj
->ptr
)) == -1) goto writeerr
;
1857 if (fwrite(out
,comprlen
,1,fp
) == 0) goto writeerr
;
1866 /* Save a string objet as [len][data] on disk. If the object is a string
1867 * representation of an integer value we try to safe it in a special form */
1868 static int rdbSaveStringObject(FILE *fp
, robj
*obj
) {
1869 size_t len
= sdslen(obj
->ptr
);
1872 /* Try integer encoding */
1874 unsigned char buf
[5];
1875 if ((enclen
= rdbTryIntegerEncoding(obj
->ptr
,buf
)) > 0) {
1876 if (fwrite(buf
,enclen
,1,fp
) == 0) return -1;
1881 /* Try LZF compression - under 20 bytes it's unable to compress even
1882 * aaaaaaaaaaaaaaaaaa so skip it */
1883 if (1 && len
> 20) {
1886 retval
= rdbSaveLzfStringObject(fp
,obj
);
1887 if (retval
== -1) return -1;
1888 if (retval
> 0) return 0;
1889 /* retval == 0 means data can't be compressed, save the old way */
1892 /* Store verbatim */
1893 if (rdbSaveLen(fp
,len
) == -1) return -1;
1894 if (len
&& fwrite(obj
->ptr
,len
,1,fp
) == 0) return -1;
1898 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
1899 static int rdbSave(char *filename
) {
1900 dictIterator
*di
= NULL
;
1905 time_t now
= time(NULL
);
1907 snprintf(tmpfile
,256,"temp-%d.rdb", (int) getpid());
1908 fp
= fopen(tmpfile
,"w");
1910 redisLog(REDIS_WARNING
, "Failed saving the DB: %s", strerror(errno
));
1913 if (fwrite("REDIS0001",9,1,fp
) == 0) goto werr
;
1914 for (j
= 0; j
< server
.dbnum
; j
++) {
1915 redisDb
*db
= server
.db
+j
;
1917 if (dictSize(d
) == 0) continue;
1918 di
= dictGetIterator(d
);
1924 /* Write the SELECT DB opcode */
1925 if (rdbSaveType(fp
,REDIS_SELECTDB
) == -1) goto werr
;
1926 if (rdbSaveLen(fp
,j
) == -1) goto werr
;
1928 /* Iterate this DB writing every entry */
1929 while((de
= dictNext(di
)) != NULL
) {
1930 robj
*key
= dictGetEntryKey(de
);
1931 robj
*o
= dictGetEntryVal(de
);
1932 time_t expiretime
= getExpire(db
,key
);
1934 /* Save the expire time */
1935 if (expiretime
!= -1) {
1936 /* If this key is already expired skip it */
1937 if (expiretime
< now
) continue;
1938 if (rdbSaveType(fp
,REDIS_EXPIRETIME
) == -1) goto werr
;
1939 if (rdbSaveTime(fp
,expiretime
) == -1) goto werr
;
1941 /* Save the key and associated value */
1942 if (rdbSaveType(fp
,o
->type
) == -1) goto werr
;
1943 if (rdbSaveStringObject(fp
,key
) == -1) goto werr
;
1944 if (o
->type
== REDIS_STRING
) {
1945 /* Save a string value */
1946 if (rdbSaveStringObject(fp
,o
) == -1) goto werr
;
1947 } else if (o
->type
== REDIS_LIST
) {
1948 /* Save a list value */
1949 list
*list
= o
->ptr
;
1953 if (rdbSaveLen(fp
,listLength(list
)) == -1) goto werr
;
1954 while((ln
= listYield(list
))) {
1955 robj
*eleobj
= listNodeValue(ln
);
1957 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
1959 } else if (o
->type
== REDIS_SET
) {
1960 /* Save a set value */
1962 dictIterator
*di
= dictGetIterator(set
);
1965 if (!set
) oom("dictGetIteraotr");
1966 if (rdbSaveLen(fp
,dictSize(set
)) == -1) goto werr
;
1967 while((de
= dictNext(di
)) != NULL
) {
1968 robj
*eleobj
= dictGetEntryKey(de
);
1970 if (rdbSaveStringObject(fp
,eleobj
) == -1) goto werr
;
1972 dictReleaseIterator(di
);
1977 dictReleaseIterator(di
);
1980 if (rdbSaveType(fp
,REDIS_EOF
) == -1) goto werr
;
1982 /* Make sure data will not remain on the OS's output buffers */
1987 /* Use RENAME to make sure the DB file is changed atomically only
1988 * if the generate DB file is ok. */
1989 if (rename(tmpfile
,filename
) == -1) {
1990 redisLog(REDIS_WARNING
,"Error moving temp DB file on the final destionation: %s", strerror(errno
));
1994 redisLog(REDIS_NOTICE
,"DB saved on disk");
1996 server
.lastsave
= time(NULL
);
2002 redisLog(REDIS_WARNING
,"Write error saving DB on disk: %s", strerror(errno
));
2003 if (di
) dictReleaseIterator(di
);
2007 static int rdbSaveBackground(char *filename
) {
2010 if (server
.bgsaveinprogress
) return REDIS_ERR
;
2011 if ((childpid
= fork()) == 0) {
2014 if (rdbSave(filename
) == REDIS_OK
) {
2021 if (childpid
== -1) {
2022 redisLog(REDIS_WARNING
,"Can't save in background: fork: %s",
2026 redisLog(REDIS_NOTICE
,"Background saving started by pid %d",childpid
);
2027 server
.bgsaveinprogress
= 1;
2028 server
.bgsavechildpid
= childpid
;
2031 return REDIS_OK
; /* unreached */
2034 static void rdbRemoveTempFile(pid_t childpid
) {
2037 snprintf(tmpfile
,256,"temp-%d.rdb", (int) childpid
);
2041 static int rdbLoadType(FILE *fp
) {
2043 if (fread(&type
,1,1,fp
) == 0) return -1;
2047 static time_t rdbLoadTime(FILE *fp
) {
2049 if (fread(&t32
,4,1,fp
) == 0) return -1;
2050 return (time_t) t32
;
2053 /* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
2054 * of this file for a description of how this are stored on disk.
2056 * isencoded is set to 1 if the readed length is not actually a length but
2057 * an "encoding type", check the above comments for more info */
2058 static uint32_t rdbLoadLen(FILE *fp
, int rdbver
, int *isencoded
) {
2059 unsigned char buf
[2];
2062 if (isencoded
) *isencoded
= 0;
2064 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
2069 if (fread(buf
,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2070 type
= (buf
[0]&0xC0)>>6;
2071 if (type
== REDIS_RDB_6BITLEN
) {
2072 /* Read a 6 bit len */
2074 } else if (type
== REDIS_RDB_ENCVAL
) {
2075 /* Read a 6 bit len encoding type */
2076 if (isencoded
) *isencoded
= 1;
2078 } else if (type
== REDIS_RDB_14BITLEN
) {
2079 /* Read a 14 bit len */
2080 if (fread(buf
+1,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2081 return ((buf
[0]&0x3F)<<8)|buf
[1];
2083 /* Read a 32 bit len */
2084 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
2090 static robj
*rdbLoadIntegerObject(FILE *fp
, int enctype
) {
2091 unsigned char enc
[4];
2094 if (enctype
== REDIS_RDB_ENC_INT8
) {
2095 if (fread(enc
,1,1,fp
) == 0) return NULL
;
2096 val
= (signed char)enc
[0];
2097 } else if (enctype
== REDIS_RDB_ENC_INT16
) {
2099 if (fread(enc
,2,1,fp
) == 0) return NULL
;
2100 v
= enc
[0]|(enc
[1]<<8);
2102 } else if (enctype
== REDIS_RDB_ENC_INT32
) {
2104 if (fread(enc
,4,1,fp
) == 0) return NULL
;
2105 v
= enc
[0]|(enc
[1]<<8)|(enc
[2]<<16)|(enc
[3]<<24);
2108 val
= 0; /* anti-warning */
2111 return createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",val
));
2114 static robj
*rdbLoadLzfStringObject(FILE*fp
, int rdbver
) {
2115 unsigned int len
, clen
;
2116 unsigned char *c
= NULL
;
2119 if ((clen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2120 if ((len
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2121 if ((c
= zmalloc(clen
)) == NULL
) goto err
;
2122 if ((val
= sdsnewlen(NULL
,len
)) == NULL
) goto err
;
2123 if (fread(c
,clen
,1,fp
) == 0) goto err
;
2124 if (lzf_decompress(c
,clen
,val
,len
) == 0) goto err
;
2126 return createObject(REDIS_STRING
,val
);
2133 static robj
*rdbLoadStringObject(FILE*fp
, int rdbver
) {
2138 len
= rdbLoadLen(fp
,rdbver
,&isencoded
);
2141 case REDIS_RDB_ENC_INT8
:
2142 case REDIS_RDB_ENC_INT16
:
2143 case REDIS_RDB_ENC_INT32
:
2144 return tryObjectSharing(rdbLoadIntegerObject(fp
,len
));
2145 case REDIS_RDB_ENC_LZF
:
2146 return tryObjectSharing(rdbLoadLzfStringObject(fp
,rdbver
));
2152 if (len
== REDIS_RDB_LENERR
) return NULL
;
2153 val
= sdsnewlen(NULL
,len
);
2154 if (len
&& fread(val
,len
,1,fp
) == 0) {
2158 return tryObjectSharing(createObject(REDIS_STRING
,val
));
2161 static int rdbLoad(char *filename
) {
2163 robj
*keyobj
= NULL
;
2165 int type
, retval
, rdbver
;
2166 dict
*d
= server
.db
[0].dict
;
2167 redisDb
*db
= server
.db
+0;
2169 time_t expiretime
= -1, now
= time(NULL
);
2171 fp
= fopen(filename
,"r");
2172 if (!fp
) return REDIS_ERR
;
2173 if (fread(buf
,9,1,fp
) == 0) goto eoferr
;
2175 if (memcmp(buf
,"REDIS",5) != 0) {
2177 redisLog(REDIS_WARNING
,"Wrong signature trying to load DB from file");
2180 rdbver
= atoi(buf
+5);
2183 redisLog(REDIS_WARNING
,"Can't handle RDB format version %d",rdbver
);
2190 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
2191 if (type
== REDIS_EXPIRETIME
) {
2192 if ((expiretime
= rdbLoadTime(fp
)) == -1) goto eoferr
;
2193 /* We read the time so we need to read the object type again */
2194 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
2196 if (type
== REDIS_EOF
) break;
2197 /* Handle SELECT DB opcode as a special case */
2198 if (type
== REDIS_SELECTDB
) {
2199 if ((dbid
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2201 if (dbid
>= (unsigned)server
.dbnum
) {
2202 redisLog(REDIS_WARNING
,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server
.dbnum
);
2205 db
= server
.db
+dbid
;
2210 if ((keyobj
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2212 if (type
== REDIS_STRING
) {
2213 /* Read string value */
2214 if ((o
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2215 } else if (type
== REDIS_LIST
|| type
== REDIS_SET
) {
2216 /* Read list/set value */
2219 if ((listlen
= rdbLoadLen(fp
,rdbver
,NULL
)) == REDIS_RDB_LENERR
)
2221 o
= (type
== REDIS_LIST
) ? createListObject() : createSetObject();
2222 /* Load every single element of the list/set */
2226 if ((ele
= rdbLoadStringObject(fp
,rdbver
)) == NULL
) goto eoferr
;
2227 if (type
== REDIS_LIST
) {
2228 if (!listAddNodeTail((list
*)o
->ptr
,ele
))
2229 oom("listAddNodeTail");
2231 if (dictAdd((dict
*)o
->ptr
,ele
,NULL
) == DICT_ERR
)
2238 /* Add the new object in the hash table */
2239 retval
= dictAdd(d
,keyobj
,o
);
2240 if (retval
== DICT_ERR
) {
2241 redisLog(REDIS_WARNING
,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj
->ptr
);
2244 /* Set the expire time if needed */
2245 if (expiretime
!= -1) {
2246 setExpire(db
,keyobj
,expiretime
);
2247 /* Delete this key if already expired */
2248 if (expiretime
< now
) deleteKey(db
,keyobj
);
2256 eoferr
: /* unexpected end of file is handled here with a fatal exit */
2257 if (keyobj
) decrRefCount(keyobj
);
2258 redisLog(REDIS_WARNING
,"Short read or OOM loading DB. Unrecoverable error, exiting now.");
2260 return REDIS_ERR
; /* Just to avoid warning */
2263 /*================================== Commands =============================== */
2265 static void authCommand(redisClient
*c
) {
2266 if (!server
.requirepass
|| !strcmp(c
->argv
[1]->ptr
, server
.requirepass
)) {
2267 c
->authenticated
= 1;
2268 addReply(c
,shared
.ok
);
2270 c
->authenticated
= 0;
2271 addReply(c
,shared
.err
);
2275 static void pingCommand(redisClient
*c
) {
2276 addReply(c
,shared
.pong
);
2279 static void echoCommand(redisClient
*c
) {
2280 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",
2281 (int)sdslen(c
->argv
[1]->ptr
)));
2282 addReply(c
,c
->argv
[1]);
2283 addReply(c
,shared
.crlf
);
2286 /*=================================== Strings =============================== */
2288 static void setGenericCommand(redisClient
*c
, int nx
) {
2291 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2292 if (retval
== DICT_ERR
) {
2294 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2295 incrRefCount(c
->argv
[2]);
2297 addReply(c
,shared
.czero
);
2301 incrRefCount(c
->argv
[1]);
2302 incrRefCount(c
->argv
[2]);
2305 removeExpire(c
->db
,c
->argv
[1]);
2306 addReply(c
, nx
? shared
.cone
: shared
.ok
);
2309 static void setCommand(redisClient
*c
) {
2310 setGenericCommand(c
,0);
2313 static void setnxCommand(redisClient
*c
) {
2314 setGenericCommand(c
,1);
2317 static void getCommand(redisClient
*c
) {
2318 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2321 addReply(c
,shared
.nullbulk
);
2323 if (o
->type
!= REDIS_STRING
) {
2324 addReply(c
,shared
.wrongtypeerr
);
2326 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(o
->ptr
)));
2328 addReply(c
,shared
.crlf
);
2333 static void getSetCommand(redisClient
*c
) {
2335 if (dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]) == DICT_ERR
) {
2336 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
2338 incrRefCount(c
->argv
[1]);
2340 incrRefCount(c
->argv
[2]);
2342 removeExpire(c
->db
,c
->argv
[1]);
2345 static void mgetCommand(redisClient
*c
) {
2348 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",c
->argc
-1));
2349 for (j
= 1; j
< c
->argc
; j
++) {
2350 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
2352 addReply(c
,shared
.nullbulk
);
2354 if (o
->type
!= REDIS_STRING
) {
2355 addReply(c
,shared
.nullbulk
);
2357 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(o
->ptr
)));
2359 addReply(c
,shared
.crlf
);
2365 static void incrDecrCommand(redisClient
*c
, long long incr
) {
2370 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2374 if (o
->type
!= REDIS_STRING
) {
2379 value
= strtoll(o
->ptr
, &eptr
, 10);
2384 o
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",value
));
2385 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],o
);
2386 if (retval
== DICT_ERR
) {
2387 dictReplace(c
->db
->dict
,c
->argv
[1],o
);
2388 removeExpire(c
->db
,c
->argv
[1]);
2390 incrRefCount(c
->argv
[1]);
2393 addReply(c
,shared
.colon
);
2395 addReply(c
,shared
.crlf
);
2398 static void incrCommand(redisClient
*c
) {
2399 incrDecrCommand(c
,1);
2402 static void decrCommand(redisClient
*c
) {
2403 incrDecrCommand(c
,-1);
2406 static void incrbyCommand(redisClient
*c
) {
2407 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
2408 incrDecrCommand(c
,incr
);
2411 static void decrbyCommand(redisClient
*c
) {
2412 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
2413 incrDecrCommand(c
,-incr
);
2416 /* ========================= Type agnostic commands ========================= */
2418 static void delCommand(redisClient
*c
) {
2421 for (j
= 1; j
< c
->argc
; j
++) {
2422 if (deleteKey(c
->db
,c
->argv
[j
])) {
2429 addReply(c
,shared
.czero
);
2432 addReply(c
,shared
.cone
);
2435 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",deleted
));
2440 static void existsCommand(redisClient
*c
) {
2441 addReply(c
,lookupKeyRead(c
->db
,c
->argv
[1]) ? shared
.cone
: shared
.czero
);
2444 static void selectCommand(redisClient
*c
) {
2445 int id
= atoi(c
->argv
[1]->ptr
);
2447 if (selectDb(c
,id
) == REDIS_ERR
) {
2448 addReplySds(c
,sdsnew("-ERR invalid DB index\r\n"));
2450 addReply(c
,shared
.ok
);
2454 static void randomkeyCommand(redisClient
*c
) {
2458 de
= dictGetRandomKey(c
->db
->dict
);
2459 if (!de
|| expireIfNeeded(c
->db
,dictGetEntryKey(de
)) == 0) break;
2462 addReply(c
,shared
.plus
);
2463 addReply(c
,shared
.crlf
);
2465 addReply(c
,shared
.plus
);
2466 addReply(c
,dictGetEntryKey(de
));
2467 addReply(c
,shared
.crlf
);
2471 static void keysCommand(redisClient
*c
) {
2474 sds pattern
= c
->argv
[1]->ptr
;
2475 int plen
= sdslen(pattern
);
2476 int numkeys
= 0, keyslen
= 0;
2477 robj
*lenobj
= createObject(REDIS_STRING
,NULL
);
2479 di
= dictGetIterator(c
->db
->dict
);
2480 if (!di
) oom("dictGetIterator");
2482 decrRefCount(lenobj
);
2483 while((de
= dictNext(di
)) != NULL
) {
2484 robj
*keyobj
= dictGetEntryKey(de
);
2486 sds key
= keyobj
->ptr
;
2487 if ((pattern
[0] == '*' && pattern
[1] == '\0') ||
2488 stringmatchlen(pattern
,plen
,key
,sdslen(key
),0)) {
2489 if (expireIfNeeded(c
->db
,keyobj
) == 0) {
2491 addReply(c
,shared
.space
);
2494 keyslen
+= sdslen(key
);
2498 dictReleaseIterator(di
);
2499 lenobj
->ptr
= sdscatprintf(sdsempty(),"$%lu\r\n",keyslen
+(numkeys
? (numkeys
-1) : 0));
2500 addReply(c
,shared
.crlf
);
2503 static void dbsizeCommand(redisClient
*c
) {
2505 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c
->db
->dict
)));
2508 static void lastsaveCommand(redisClient
*c
) {
2510 sdscatprintf(sdsempty(),":%lu\r\n",server
.lastsave
));
2513 static void typeCommand(redisClient
*c
) {
2517 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2522 case REDIS_STRING
: type
= "+string"; break;
2523 case REDIS_LIST
: type
= "+list"; break;
2524 case REDIS_SET
: type
= "+set"; break;
2525 default: type
= "unknown"; break;
2528 addReplySds(c
,sdsnew(type
));
2529 addReply(c
,shared
.crlf
);
2532 static void saveCommand(redisClient
*c
) {
2533 if (server
.bgsaveinprogress
) {
2534 addReplySds(c
,sdsnew("-ERR background save in progress\r\n"));
2537 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
2538 addReply(c
,shared
.ok
);
2540 addReply(c
,shared
.err
);
2544 static void bgsaveCommand(redisClient
*c
) {
2545 if (server
.bgsaveinprogress
) {
2546 addReplySds(c
,sdsnew("-ERR background save already in progress\r\n"));
2549 if (rdbSaveBackground(server
.dbfilename
) == REDIS_OK
) {
2550 addReply(c
,shared
.ok
);
2552 addReply(c
,shared
.err
);
2556 static void shutdownCommand(redisClient
*c
) {
2557 redisLog(REDIS_WARNING
,"User requested shutdown, saving DB...");
2558 /* Kill the saving child if there is a background saving in progress.
2559 We want to avoid race conditions, for instance our saving child may
2560 overwrite the synchronous saving did by SHUTDOWN. */
2561 if (server
.bgsaveinprogress
) {
2562 redisLog(REDIS_WARNING
,"There is a live saving child. Killing it!");
2563 kill(server
.bgsavechildpid
,SIGKILL
);
2564 rdbRemoveTempFile(server
.bgsavechildpid
);
2567 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
2568 if (server
.daemonize
)
2569 unlink(server
.pidfile
);
2570 redisLog(REDIS_WARNING
,"%zu bytes used at exit",zmalloc_used_memory());
2571 redisLog(REDIS_WARNING
,"Server exit now, bye bye...");
2574 /* Ooops.. error saving! The best we can do is to continue operating.
2575 * Note that if there was a background saving process, in the next
2576 * cron() Redis will be notified that the background saving aborted,
2577 * handling special stuff like slaves pending for synchronization... */
2578 redisLog(REDIS_WARNING
,"Error trying to save the DB, can't exit");
2579 addReplySds(c
,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
2583 static void renameGenericCommand(redisClient
*c
, int nx
) {
2586 /* To use the same key as src and dst is probably an error */
2587 if (sdscmp(c
->argv
[1]->ptr
,c
->argv
[2]->ptr
) == 0) {
2588 addReply(c
,shared
.sameobjecterr
);
2592 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2594 addReply(c
,shared
.nokeyerr
);
2598 deleteIfVolatile(c
->db
,c
->argv
[2]);
2599 if (dictAdd(c
->db
->dict
,c
->argv
[2],o
) == DICT_ERR
) {
2602 addReply(c
,shared
.czero
);
2605 dictReplace(c
->db
->dict
,c
->argv
[2],o
);
2607 incrRefCount(c
->argv
[2]);
2609 deleteKey(c
->db
,c
->argv
[1]);
2611 addReply(c
,nx
? shared
.cone
: shared
.ok
);
2614 static void renameCommand(redisClient
*c
) {
2615 renameGenericCommand(c
,0);
2618 static void renamenxCommand(redisClient
*c
) {
2619 renameGenericCommand(c
,1);
2622 static void moveCommand(redisClient
*c
) {
2627 /* Obtain source and target DB pointers */
2630 if (selectDb(c
,atoi(c
->argv
[2]->ptr
)) == REDIS_ERR
) {
2631 addReply(c
,shared
.outofrangeerr
);
2635 selectDb(c
,srcid
); /* Back to the source DB */
2637 /* If the user is moving using as target the same
2638 * DB as the source DB it is probably an error. */
2640 addReply(c
,shared
.sameobjecterr
);
2644 /* Check if the element exists and get a reference */
2645 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2647 addReply(c
,shared
.czero
);
2651 /* Try to add the element to the target DB */
2652 deleteIfVolatile(dst
,c
->argv
[1]);
2653 if (dictAdd(dst
->dict
,c
->argv
[1],o
) == DICT_ERR
) {
2654 addReply(c
,shared
.czero
);
2657 incrRefCount(c
->argv
[1]);
2660 /* OK! key moved, free the entry in the source DB */
2661 deleteKey(src
,c
->argv
[1]);
2663 addReply(c
,shared
.cone
);
2666 /* =================================== Lists ================================ */
2667 static void pushGenericCommand(redisClient
*c
, int where
) {
2671 lobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2673 lobj
= createListObject();
2675 if (where
== REDIS_HEAD
) {
2676 if (!listAddNodeHead(list
,c
->argv
[2])) oom("listAddNodeHead");
2678 if (!listAddNodeTail(list
,c
->argv
[2])) oom("listAddNodeTail");
2680 dictAdd(c
->db
->dict
,c
->argv
[1],lobj
);
2681 incrRefCount(c
->argv
[1]);
2682 incrRefCount(c
->argv
[2]);
2684 if (lobj
->type
!= REDIS_LIST
) {
2685 addReply(c
,shared
.wrongtypeerr
);
2689 if (where
== REDIS_HEAD
) {
2690 if (!listAddNodeHead(list
,c
->argv
[2])) oom("listAddNodeHead");
2692 if (!listAddNodeTail(list
,c
->argv
[2])) oom("listAddNodeTail");
2694 incrRefCount(c
->argv
[2]);
2697 addReply(c
,shared
.ok
);
2700 static void lpushCommand(redisClient
*c
) {
2701 pushGenericCommand(c
,REDIS_HEAD
);
2704 static void rpushCommand(redisClient
*c
) {
2705 pushGenericCommand(c
,REDIS_TAIL
);
2708 static void llenCommand(redisClient
*c
) {
2712 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2714 addReply(c
,shared
.czero
);
2717 if (o
->type
!= REDIS_LIST
) {
2718 addReply(c
,shared
.wrongtypeerr
);
2721 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",listLength(l
)));
2726 static void lindexCommand(redisClient
*c
) {
2728 int index
= atoi(c
->argv
[2]->ptr
);
2730 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2732 addReply(c
,shared
.nullbulk
);
2734 if (o
->type
!= REDIS_LIST
) {
2735 addReply(c
,shared
.wrongtypeerr
);
2737 list
*list
= o
->ptr
;
2740 ln
= listIndex(list
, index
);
2742 addReply(c
,shared
.nullbulk
);
2744 robj
*ele
= listNodeValue(ln
);
2745 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele
->ptr
)));
2747 addReply(c
,shared
.crlf
);
2753 static void lsetCommand(redisClient
*c
) {
2755 int index
= atoi(c
->argv
[2]->ptr
);
2757 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2759 addReply(c
,shared
.nokeyerr
);
2761 if (o
->type
!= REDIS_LIST
) {
2762 addReply(c
,shared
.wrongtypeerr
);
2764 list
*list
= o
->ptr
;
2767 ln
= listIndex(list
, index
);
2769 addReply(c
,shared
.outofrangeerr
);
2771 robj
*ele
= listNodeValue(ln
);
2774 listNodeValue(ln
) = c
->argv
[3];
2775 incrRefCount(c
->argv
[3]);
2776 addReply(c
,shared
.ok
);
2783 static void popGenericCommand(redisClient
*c
, int where
) {
2786 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2788 addReply(c
,shared
.nullbulk
);
2790 if (o
->type
!= REDIS_LIST
) {
2791 addReply(c
,shared
.wrongtypeerr
);
2793 list
*list
= o
->ptr
;
2796 if (where
== REDIS_HEAD
)
2797 ln
= listFirst(list
);
2799 ln
= listLast(list
);
2802 addReply(c
,shared
.nullbulk
);
2804 robj
*ele
= listNodeValue(ln
);
2805 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele
->ptr
)));
2807 addReply(c
,shared
.crlf
);
2808 listDelNode(list
,ln
);
2815 static void lpopCommand(redisClient
*c
) {
2816 popGenericCommand(c
,REDIS_HEAD
);
2819 static void rpopCommand(redisClient
*c
) {
2820 popGenericCommand(c
,REDIS_TAIL
);
2823 static void lrangeCommand(redisClient
*c
) {
2825 int start
= atoi(c
->argv
[2]->ptr
);
2826 int end
= atoi(c
->argv
[3]->ptr
);
2828 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
2830 addReply(c
,shared
.nullmultibulk
);
2832 if (o
->type
!= REDIS_LIST
) {
2833 addReply(c
,shared
.wrongtypeerr
);
2835 list
*list
= o
->ptr
;
2837 int llen
= listLength(list
);
2841 /* convert negative indexes */
2842 if (start
< 0) start
= llen
+start
;
2843 if (end
< 0) end
= llen
+end
;
2844 if (start
< 0) start
= 0;
2845 if (end
< 0) end
= 0;
2847 /* indexes sanity checks */
2848 if (start
> end
|| start
>= llen
) {
2849 /* Out of range start or start > end result in empty list */
2850 addReply(c
,shared
.emptymultibulk
);
2853 if (end
>= llen
) end
= llen
-1;
2854 rangelen
= (end
-start
)+1;
2856 /* Return the result in form of a multi-bulk reply */
2857 ln
= listIndex(list
, start
);
2858 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",rangelen
));
2859 for (j
= 0; j
< rangelen
; j
++) {
2860 ele
= listNodeValue(ln
);
2861 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele
->ptr
)));
2863 addReply(c
,shared
.crlf
);
2870 static void ltrimCommand(redisClient
*c
) {
2872 int start
= atoi(c
->argv
[2]->ptr
);
2873 int end
= atoi(c
->argv
[3]->ptr
);
2875 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2877 addReply(c
,shared
.nokeyerr
);
2879 if (o
->type
!= REDIS_LIST
) {
2880 addReply(c
,shared
.wrongtypeerr
);
2882 list
*list
= o
->ptr
;
2884 int llen
= listLength(list
);
2885 int j
, ltrim
, rtrim
;
2887 /* convert negative indexes */
2888 if (start
< 0) start
= llen
+start
;
2889 if (end
< 0) end
= llen
+end
;
2890 if (start
< 0) start
= 0;
2891 if (end
< 0) end
= 0;
2893 /* indexes sanity checks */
2894 if (start
> end
|| start
>= llen
) {
2895 /* Out of range start or start > end result in empty list */
2899 if (end
>= llen
) end
= llen
-1;
2904 /* Remove list elements to perform the trim */
2905 for (j
= 0; j
< ltrim
; j
++) {
2906 ln
= listFirst(list
);
2907 listDelNode(list
,ln
);
2909 for (j
= 0; j
< rtrim
; j
++) {
2910 ln
= listLast(list
);
2911 listDelNode(list
,ln
);
2914 addReply(c
,shared
.ok
);
2919 static void lremCommand(redisClient
*c
) {
2922 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2924 addReply(c
,shared
.czero
);
2926 if (o
->type
!= REDIS_LIST
) {
2927 addReply(c
,shared
.wrongtypeerr
);
2929 list
*list
= o
->ptr
;
2930 listNode
*ln
, *next
;
2931 int toremove
= atoi(c
->argv
[2]->ptr
);
2936 toremove
= -toremove
;
2939 ln
= fromtail
? list
->tail
: list
->head
;
2941 robj
*ele
= listNodeValue(ln
);
2943 next
= fromtail
? ln
->prev
: ln
->next
;
2944 if (sdscmp(ele
->ptr
,c
->argv
[3]->ptr
) == 0) {
2945 listDelNode(list
,ln
);
2948 if (toremove
&& removed
== toremove
) break;
2952 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",removed
));
2957 /* ==================================== Sets ================================ */
2959 static void saddCommand(redisClient
*c
) {
2962 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2964 set
= createSetObject();
2965 dictAdd(c
->db
->dict
,c
->argv
[1],set
);
2966 incrRefCount(c
->argv
[1]);
2968 if (set
->type
!= REDIS_SET
) {
2969 addReply(c
,shared
.wrongtypeerr
);
2973 if (dictAdd(set
->ptr
,c
->argv
[2],NULL
) == DICT_OK
) {
2974 incrRefCount(c
->argv
[2]);
2976 addReply(c
,shared
.cone
);
2978 addReply(c
,shared
.czero
);
2982 static void sremCommand(redisClient
*c
) {
2985 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
2987 addReply(c
,shared
.czero
);
2989 if (set
->type
!= REDIS_SET
) {
2990 addReply(c
,shared
.wrongtypeerr
);
2993 if (dictDelete(set
->ptr
,c
->argv
[2]) == DICT_OK
) {
2995 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
2996 addReply(c
,shared
.cone
);
2998 addReply(c
,shared
.czero
);
3003 static void smoveCommand(redisClient
*c
) {
3004 robj
*srcset
, *dstset
;
3006 srcset
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3007 dstset
= lookupKeyWrite(c
->db
,c
->argv
[2]);
3009 /* If the source key does not exist return 0, if it's of the wrong type
3011 if (srcset
== NULL
|| srcset
->type
!= REDIS_SET
) {
3012 addReply(c
, srcset
? shared
.wrongtypeerr
: shared
.czero
);
3015 /* Error if the destination key is not a set as well */
3016 if (dstset
&& dstset
->type
!= REDIS_SET
) {
3017 addReply(c
,shared
.wrongtypeerr
);
3020 /* Remove the element from the source set */
3021 if (dictDelete(srcset
->ptr
,c
->argv
[3]) == DICT_ERR
) {
3022 /* Key not found in the src set! return zero */
3023 addReply(c
,shared
.czero
);
3027 /* Add the element to the destination set */
3029 dstset
= createSetObject();
3030 dictAdd(c
->db
->dict
,c
->argv
[2],dstset
);
3031 incrRefCount(c
->argv
[2]);
3033 if (dictAdd(dstset
->ptr
,c
->argv
[3],NULL
) == DICT_OK
)
3034 incrRefCount(c
->argv
[3]);
3035 addReply(c
,shared
.cone
);
3038 static void sismemberCommand(redisClient
*c
) {
3041 set
= lookupKeyRead(c
->db
,c
->argv
[1]);
3043 addReply(c
,shared
.czero
);
3045 if (set
->type
!= REDIS_SET
) {
3046 addReply(c
,shared
.wrongtypeerr
);
3049 if (dictFind(set
->ptr
,c
->argv
[2]))
3050 addReply(c
,shared
.cone
);
3052 addReply(c
,shared
.czero
);
3056 static void scardCommand(redisClient
*c
) {
3060 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3062 addReply(c
,shared
.czero
);
3065 if (o
->type
!= REDIS_SET
) {
3066 addReply(c
,shared
.wrongtypeerr
);
3069 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3075 static void spopCommand(redisClient
*c
) {
3079 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3081 addReply(c
,shared
.nullbulk
);
3083 if (set
->type
!= REDIS_SET
) {
3084 addReply(c
,shared
.wrongtypeerr
);
3087 de
= dictGetRandomKey(set
->ptr
);
3089 addReply(c
,shared
.nullbulk
);
3091 robj
*ele
= dictGetEntryKey(de
);
3093 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(ele
->ptr
)));
3095 addReply(c
,shared
.crlf
);
3096 dictDelete(set
->ptr
,ele
);
3097 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
3103 static int qsortCompareSetsByCardinality(const void *s1
, const void *s2
) {
3104 dict
**d1
= (void*) s1
, **d2
= (void*) s2
;
3106 return dictSize(*d1
)-dictSize(*d2
);
3109 static void sinterGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
) {
3110 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
3113 robj
*lenobj
= NULL
, *dstset
= NULL
;
3114 int j
, cardinality
= 0;
3116 if (!dv
) oom("sinterGenericCommand");
3117 for (j
= 0; j
< setsnum
; j
++) {
3121 lookupKeyWrite(c
->db
,setskeys
[j
]) :
3122 lookupKeyRead(c
->db
,setskeys
[j
]);
3126 deleteKey(c
->db
,dstkey
);
3127 addReply(c
,shared
.ok
);
3129 addReply(c
,shared
.nullmultibulk
);
3133 if (setobj
->type
!= REDIS_SET
) {
3135 addReply(c
,shared
.wrongtypeerr
);
3138 dv
[j
] = setobj
->ptr
;
3140 /* Sort sets from the smallest to largest, this will improve our
3141 * algorithm's performace */
3142 qsort(dv
,setsnum
,sizeof(dict
*),qsortCompareSetsByCardinality
);
3144 /* The first thing we should output is the total number of elements...
3145 * since this is a multi-bulk write, but at this stage we don't know
3146 * the intersection set size, so we use a trick, append an empty object
3147 * to the output list and save the pointer to later modify it with the
3150 lenobj
= createObject(REDIS_STRING
,NULL
);
3152 decrRefCount(lenobj
);
3154 /* If we have a target key where to store the resulting set
3155 * create this key with an empty set inside */
3156 dstset
= createSetObject();
3159 /* Iterate all the elements of the first (smallest) set, and test
3160 * the element against all the other sets, if at least one set does
3161 * not include the element it is discarded */
3162 di
= dictGetIterator(dv
[0]);
3163 if (!di
) oom("dictGetIterator");
3165 while((de
= dictNext(di
)) != NULL
) {
3168 for (j
= 1; j
< setsnum
; j
++)
3169 if (dictFind(dv
[j
],dictGetEntryKey(de
)) == NULL
) break;
3171 continue; /* at least one set does not contain the member */
3172 ele
= dictGetEntryKey(de
);
3174 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(ele
->ptr
)));
3176 addReply(c
,shared
.crlf
);
3179 dictAdd(dstset
->ptr
,ele
,NULL
);
3183 dictReleaseIterator(di
);
3186 /* Store the resulting set into the target */
3187 deleteKey(c
->db
,dstkey
);
3188 dictAdd(c
->db
->dict
,dstkey
,dstset
);
3189 incrRefCount(dstkey
);
3193 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%d\r\n",cardinality
);
3195 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3196 dictSize((dict
*)dstset
->ptr
)));
3202 static void sinterCommand(redisClient
*c
) {
3203 sinterGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
);
3206 static void sinterstoreCommand(redisClient
*c
) {
3207 sinterGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1]);
3210 #define REDIS_OP_UNION 0
3211 #define REDIS_OP_DIFF 1
3213 static void sunionDiffGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
, int op
) {
3214 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
3217 robj
*dstset
= NULL
;
3218 int j
, cardinality
= 0;
3220 if (!dv
) oom("sunionDiffGenericCommand");
3221 for (j
= 0; j
< setsnum
; j
++) {
3225 lookupKeyWrite(c
->db
,setskeys
[j
]) :
3226 lookupKeyRead(c
->db
,setskeys
[j
]);
3231 if (setobj
->type
!= REDIS_SET
) {
3233 addReply(c
,shared
.wrongtypeerr
);
3236 dv
[j
] = setobj
->ptr
;
3239 /* We need a temp set object to store our union. If the dstkey
3240 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
3241 * this set object will be the resulting object to set into the target key*/
3242 dstset
= createSetObject();
3244 /* Iterate all the elements of all the sets, add every element a single
3245 * time to the result set */
3246 for (j
= 0; j
< setsnum
; j
++) {
3247 if (op
== REDIS_OP_DIFF
&& j
== 0 && !dv
[j
]) break; /* result set is empty */
3248 if (!dv
[j
]) continue; /* non existing keys are like empty sets */
3250 di
= dictGetIterator(dv
[j
]);
3251 if (!di
) oom("dictGetIterator");
3253 while((de
= dictNext(di
)) != NULL
) {
3256 /* dictAdd will not add the same element multiple times */
3257 ele
= dictGetEntryKey(de
);
3258 if (op
== REDIS_OP_UNION
|| j
== 0) {
3259 if (dictAdd(dstset
->ptr
,ele
,NULL
) == DICT_OK
) {
3263 } else if (op
== REDIS_OP_DIFF
) {
3264 if (dictDelete(dstset
->ptr
,ele
) == DICT_OK
) {
3269 dictReleaseIterator(di
);
3271 if (op
== REDIS_OP_DIFF
&& cardinality
== 0) break; /* result set is empty */
3274 /* Output the content of the resulting set, if not in STORE mode */
3276 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",cardinality
));
3277 di
= dictGetIterator(dstset
->ptr
);
3278 if (!di
) oom("dictGetIterator");
3279 while((de
= dictNext(di
)) != NULL
) {
3282 ele
= dictGetEntryKey(de
);
3283 addReplySds(c
,sdscatprintf(sdsempty(),
3284 "$%d\r\n",sdslen(ele
->ptr
)));
3286 addReply(c
,shared
.crlf
);
3288 dictReleaseIterator(di
);
3290 /* If we have a target key where to store the resulting set
3291 * create this key with the result set inside */
3292 deleteKey(c
->db
,dstkey
);
3293 dictAdd(c
->db
->dict
,dstkey
,dstset
);
3294 incrRefCount(dstkey
);
3299 decrRefCount(dstset
);
3301 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",
3302 dictSize((dict
*)dstset
->ptr
)));
3308 static void sunionCommand(redisClient
*c
) {
3309 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_UNION
);
3312 static void sunionstoreCommand(redisClient
*c
) {
3313 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_UNION
);
3316 static void sdiffCommand(redisClient
*c
) {
3317 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_DIFF
);
3320 static void sdiffstoreCommand(redisClient
*c
) {
3321 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_DIFF
);
3324 static void flushdbCommand(redisClient
*c
) {
3325 server
.dirty
+= dictSize(c
->db
->dict
);
3326 dictEmpty(c
->db
->dict
);
3327 dictEmpty(c
->db
->expires
);
3328 addReply(c
,shared
.ok
);
3331 static void flushallCommand(redisClient
*c
) {
3332 server
.dirty
+= emptyDb();
3333 addReply(c
,shared
.ok
);
3334 rdbSave(server
.dbfilename
);
3338 static redisSortOperation
*createSortOperation(int type
, robj
*pattern
) {
3339 redisSortOperation
*so
= zmalloc(sizeof(*so
));
3340 if (!so
) oom("createSortOperation");
3342 so
->pattern
= pattern
;
3346 /* Return the value associated to the key with a name obtained
3347 * substituting the first occurence of '*' in 'pattern' with 'subst' */
3348 static robj
*lookupKeyByPattern(redisDb
*db
, robj
*pattern
, robj
*subst
) {
3352 int prefixlen
, sublen
, postfixlen
;
3353 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
3357 char buf
[REDIS_SORTKEY_MAX
+1];
3360 spat
= pattern
->ptr
;
3362 if (sdslen(spat
)+sdslen(ssub
)-1 > REDIS_SORTKEY_MAX
) return NULL
;
3363 p
= strchr(spat
,'*');
3364 if (!p
) return NULL
;
3367 sublen
= sdslen(ssub
);
3368 postfixlen
= sdslen(spat
)-(prefixlen
+1);
3369 memcpy(keyname
.buf
,spat
,prefixlen
);
3370 memcpy(keyname
.buf
+prefixlen
,ssub
,sublen
);
3371 memcpy(keyname
.buf
+prefixlen
+sublen
,p
+1,postfixlen
);
3372 keyname
.buf
[prefixlen
+sublen
+postfixlen
] = '\0';
3373 keyname
.len
= prefixlen
+sublen
+postfixlen
;
3375 keyobj
.refcount
= 1;
3376 keyobj
.type
= REDIS_STRING
;
3377 keyobj
.ptr
= ((char*)&keyname
)+(sizeof(long)*2);
3379 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
3380 return lookupKeyRead(db
,&keyobj
);
3383 /* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
3384 * the additional parameter is not standard but a BSD-specific we have to
3385 * pass sorting parameters via the global 'server' structure */
3386 static int sortCompare(const void *s1
, const void *s2
) {
3387 const redisSortObject
*so1
= s1
, *so2
= s2
;
3390 if (!server
.sort_alpha
) {
3391 /* Numeric sorting. Here it's trivial as we precomputed scores */
3392 if (so1
->u
.score
> so2
->u
.score
) {
3394 } else if (so1
->u
.score
< so2
->u
.score
) {
3400 /* Alphanumeric sorting */
3401 if (server
.sort_bypattern
) {
3402 if (!so1
->u
.cmpobj
|| !so2
->u
.cmpobj
) {
3403 /* At least one compare object is NULL */
3404 if (so1
->u
.cmpobj
== so2
->u
.cmpobj
)
3406 else if (so1
->u
.cmpobj
== NULL
)
3411 /* We have both the objects, use strcoll */
3412 cmp
= strcoll(so1
->u
.cmpobj
->ptr
,so2
->u
.cmpobj
->ptr
);
3415 /* Compare elements directly */
3416 cmp
= strcoll(so1
->obj
->ptr
,so2
->obj
->ptr
);
3419 return server
.sort_desc
? -cmp
: cmp
;
3422 /* The SORT command is the most complex command in Redis. Warning: this code
3423 * is optimized for speed and a bit less for readability */
3424 static void sortCommand(redisClient
*c
) {
3427 int desc
= 0, alpha
= 0;
3428 int limit_start
= 0, limit_count
= -1, start
, end
;
3429 int j
, dontsort
= 0, vectorlen
;
3430 int getop
= 0; /* GET operation counter */
3431 robj
*sortval
, *sortby
= NULL
;
3432 redisSortObject
*vector
; /* Resulting vector to sort */
3434 /* Lookup the key to sort. It must be of the right types */
3435 sortval
= lookupKeyRead(c
->db
,c
->argv
[1]);
3436 if (sortval
== NULL
) {
3437 addReply(c
,shared
.nokeyerr
);
3440 if (sortval
->type
!= REDIS_SET
&& sortval
->type
!= REDIS_LIST
) {
3441 addReply(c
,shared
.wrongtypeerr
);
3445 /* Create a list of operations to perform for every sorted element.
3446 * Operations can be GET/DEL/INCR/DECR */
3447 operations
= listCreate();
3448 listSetFreeMethod(operations
,zfree
);
3451 /* Now we need to protect sortval incrementing its count, in the future
3452 * SORT may have options able to overwrite/delete keys during the sorting
3453 * and the sorted key itself may get destroied */
3454 incrRefCount(sortval
);
3456 /* The SORT command has an SQL-alike syntax, parse it */
3457 while(j
< c
->argc
) {
3458 int leftargs
= c
->argc
-j
-1;
3459 if (!strcasecmp(c
->argv
[j
]->ptr
,"asc")) {
3461 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"desc")) {
3463 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"alpha")) {
3465 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"limit") && leftargs
>= 2) {
3466 limit_start
= atoi(c
->argv
[j
+1]->ptr
);
3467 limit_count
= atoi(c
->argv
[j
+2]->ptr
);
3469 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"by") && leftargs
>= 1) {
3470 sortby
= c
->argv
[j
+1];
3471 /* If the BY pattern does not contain '*', i.e. it is constant,
3472 * we don't need to sort nor to lookup the weight keys. */
3473 if (strchr(c
->argv
[j
+1]->ptr
,'*') == NULL
) dontsort
= 1;
3475 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
3476 listAddNodeTail(operations
,createSortOperation(
3477 REDIS_SORT_GET
,c
->argv
[j
+1]));
3480 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"del") && leftargs
>= 1) {
3481 listAddNodeTail(operations
,createSortOperation(
3482 REDIS_SORT_DEL
,c
->argv
[j
+1]));
3484 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"incr") && leftargs
>= 1) {
3485 listAddNodeTail(operations
,createSortOperation(
3486 REDIS_SORT_INCR
,c
->argv
[j
+1]));
3488 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
3489 listAddNodeTail(operations
,createSortOperation(
3490 REDIS_SORT_DECR
,c
->argv
[j
+1]));
3493 decrRefCount(sortval
);
3494 listRelease(operations
);
3495 addReply(c
,shared
.syntaxerr
);
3501 /* Load the sorting vector with all the objects to sort */
3502 vectorlen
= (sortval
->type
== REDIS_LIST
) ?
3503 listLength((list
*)sortval
->ptr
) :
3504 dictSize((dict
*)sortval
->ptr
);
3505 vector
= zmalloc(sizeof(redisSortObject
)*vectorlen
);
3506 if (!vector
) oom("allocating objects vector for SORT");
3508 if (sortval
->type
== REDIS_LIST
) {
3509 list
*list
= sortval
->ptr
;
3513 while((ln
= listYield(list
))) {
3514 robj
*ele
= ln
->value
;
3515 vector
[j
].obj
= ele
;
3516 vector
[j
].u
.score
= 0;
3517 vector
[j
].u
.cmpobj
= NULL
;
3521 dict
*set
= sortval
->ptr
;
3525 di
= dictGetIterator(set
);
3526 if (!di
) oom("dictGetIterator");
3527 while((setele
= dictNext(di
)) != NULL
) {
3528 vector
[j
].obj
= dictGetEntryKey(setele
);
3529 vector
[j
].u
.score
= 0;
3530 vector
[j
].u
.cmpobj
= NULL
;
3533 dictReleaseIterator(di
);
3535 assert(j
== vectorlen
);
3537 /* Now it's time to load the right scores in the sorting vector */
3538 if (dontsort
== 0) {
3539 for (j
= 0; j
< vectorlen
; j
++) {
3543 byval
= lookupKeyByPattern(c
->db
,sortby
,vector
[j
].obj
);
3544 if (!byval
|| byval
->type
!= REDIS_STRING
) continue;
3546 vector
[j
].u
.cmpobj
= byval
;
3547 incrRefCount(byval
);
3549 vector
[j
].u
.score
= strtod(byval
->ptr
,NULL
);
3552 if (!alpha
) vector
[j
].u
.score
= strtod(vector
[j
].obj
->ptr
,NULL
);
3557 /* We are ready to sort the vector... perform a bit of sanity check
3558 * on the LIMIT option too. We'll use a partial version of quicksort. */
3559 start
= (limit_start
< 0) ? 0 : limit_start
;
3560 end
= (limit_count
< 0) ? vectorlen
-1 : start
+limit_count
-1;
3561 if (start
>= vectorlen
) {
3562 start
= vectorlen
-1;
3565 if (end
>= vectorlen
) end
= vectorlen
-1;
3567 if (dontsort
== 0) {
3568 server
.sort_desc
= desc
;
3569 server
.sort_alpha
= alpha
;
3570 server
.sort_bypattern
= sortby
? 1 : 0;
3571 if (sortby
&& (start
!= 0 || end
!= vectorlen
-1))
3572 pqsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
, start
,end
);
3574 qsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
);
3577 /* Send command output to the output buffer, performing the specified
3578 * GET/DEL/INCR/DECR operations if any. */
3579 outputlen
= getop
? getop
*(end
-start
+1) : end
-start
+1;
3580 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",outputlen
));
3581 for (j
= start
; j
<= end
; j
++) {
3584 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",
3585 sdslen(vector
[j
].obj
->ptr
)));
3586 addReply(c
,vector
[j
].obj
);
3587 addReply(c
,shared
.crlf
);
3589 listRewind(operations
);
3590 while((ln
= listYield(operations
))) {
3591 redisSortOperation
*sop
= ln
->value
;
3592 robj
*val
= lookupKeyByPattern(c
->db
,sop
->pattern
,
3595 if (sop
->type
== REDIS_SORT_GET
) {
3596 if (!val
|| val
->type
!= REDIS_STRING
) {
3597 addReply(c
,shared
.nullbulk
);
3599 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",
3602 addReply(c
,shared
.crlf
);
3604 } else if (sop
->type
== REDIS_SORT_DEL
) {
3611 decrRefCount(sortval
);
3612 listRelease(operations
);
3613 for (j
= 0; j
< vectorlen
; j
++) {
3614 if (sortby
&& alpha
&& vector
[j
].u
.cmpobj
)
3615 decrRefCount(vector
[j
].u
.cmpobj
);
3620 static void infoCommand(redisClient
*c
) {
3622 time_t uptime
= time(NULL
)-server
.stat_starttime
;
3625 info
= sdscatprintf(sdsempty(),
3626 "redis_version:%s\r\n"
3627 "uptime_in_seconds:%d\r\n"
3628 "uptime_in_days:%d\r\n"
3629 "connected_clients:%d\r\n"
3630 "connected_slaves:%d\r\n"
3631 "used_memory:%zu\r\n"
3632 "changes_since_last_save:%lld\r\n"
3633 "bgsave_in_progress:%d\r\n"
3634 "last_save_time:%d\r\n"
3635 "total_connections_received:%lld\r\n"
3636 "total_commands_processed:%lld\r\n"
3641 listLength(server
.clients
)-listLength(server
.slaves
),
3642 listLength(server
.slaves
),
3645 server
.bgsaveinprogress
,
3647 server
.stat_numconnections
,
3648 server
.stat_numcommands
,
3649 server
.masterhost
== NULL
? "master" : "slave"
3651 if (server
.masterhost
) {
3652 info
= sdscatprintf(info
,
3653 "master_host:%s\r\n"
3654 "master_port:%d\r\n"
3655 "master_link_status:%s\r\n"
3656 "master_last_io_seconds_ago:%d\r\n"
3659 (server
.replstate
== REDIS_REPL_CONNECTED
) ?
3661 (int)(time(NULL
)-server
.master
->lastinteraction
)
3664 for (j
= 0; j
< server
.dbnum
; j
++) {
3665 long long keys
, vkeys
;
3667 keys
= dictSize(server
.db
[j
].dict
);
3668 vkeys
= dictSize(server
.db
[j
].expires
);
3669 if (keys
|| vkeys
) {
3670 info
= sdscatprintf(info
, "db%d: keys=%lld,expires=%lld\r\n",
3674 addReplySds(c
,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(info
)));
3675 addReplySds(c
,info
);
3676 addReply(c
,shared
.crlf
);
3679 static void monitorCommand(redisClient
*c
) {
3680 /* ignore MONITOR if aleady slave or in monitor mode */
3681 if (c
->flags
& REDIS_SLAVE
) return;
3683 c
->flags
|= (REDIS_SLAVE
|REDIS_MONITOR
);
3685 if (!listAddNodeTail(server
.monitors
,c
)) oom("listAddNodeTail");
3686 addReply(c
,shared
.ok
);
3689 /* ================================= Expire ================================= */
3690 static int removeExpire(redisDb
*db
, robj
*key
) {
3691 if (dictDelete(db
->expires
,key
) == DICT_OK
) {
3698 static int setExpire(redisDb
*db
, robj
*key
, time_t when
) {
3699 if (dictAdd(db
->expires
,key
,(void*)when
) == DICT_ERR
) {
3707 /* Return the expire time of the specified key, or -1 if no expire
3708 * is associated with this key (i.e. the key is non volatile) */
3709 static time_t getExpire(redisDb
*db
, robj
*key
) {
3712 /* No expire? return ASAP */
3713 if (dictSize(db
->expires
) == 0 ||
3714 (de
= dictFind(db
->expires
,key
)) == NULL
) return -1;
3716 return (time_t) dictGetEntryVal(de
);
3719 static int expireIfNeeded(redisDb
*db
, robj
*key
) {
3723 /* No expire? return ASAP */
3724 if (dictSize(db
->expires
) == 0 ||
3725 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
3727 /* Lookup the expire */
3728 when
= (time_t) dictGetEntryVal(de
);
3729 if (time(NULL
) <= when
) return 0;
3731 /* Delete the key */
3732 dictDelete(db
->expires
,key
);
3733 return dictDelete(db
->dict
,key
) == DICT_OK
;
3736 static int deleteIfVolatile(redisDb
*db
, robj
*key
) {
3739 /* No expire? return ASAP */
3740 if (dictSize(db
->expires
) == 0 ||
3741 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
3743 /* Delete the key */
3745 dictDelete(db
->expires
,key
);
3746 return dictDelete(db
->dict
,key
) == DICT_OK
;
3749 static void expireCommand(redisClient
*c
) {
3751 int seconds
= atoi(c
->argv
[2]->ptr
);
3753 de
= dictFind(c
->db
->dict
,c
->argv
[1]);
3755 addReply(c
,shared
.czero
);
3759 addReply(c
, shared
.czero
);
3762 time_t when
= time(NULL
)+seconds
;
3763 if (setExpire(c
->db
,c
->argv
[1],when
)) {
3764 addReply(c
,shared
.cone
);
3767 addReply(c
,shared
.czero
);
3773 static void ttlCommand(redisClient
*c
) {
3777 expire
= getExpire(c
->db
,c
->argv
[1]);
3779 ttl
= (int) (expire
-time(NULL
));
3780 if (ttl
< 0) ttl
= -1;
3782 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",ttl
));
3785 /* =============================== Replication ============================= */
3787 static int syncWrite(int fd
, char *ptr
, ssize_t size
, int timeout
) {
3788 ssize_t nwritten
, ret
= size
;
3789 time_t start
= time(NULL
);
3793 if (aeWait(fd
,AE_WRITABLE
,1000) & AE_WRITABLE
) {
3794 nwritten
= write(fd
,ptr
,size
);
3795 if (nwritten
== -1) return -1;
3799 if ((time(NULL
)-start
) > timeout
) {
3807 static int syncRead(int fd
, char *ptr
, ssize_t size
, int timeout
) {
3808 ssize_t nread
, totread
= 0;
3809 time_t start
= time(NULL
);
3813 if (aeWait(fd
,AE_READABLE
,1000) & AE_READABLE
) {
3814 nread
= read(fd
,ptr
,size
);
3815 if (nread
== -1) return -1;
3820 if ((time(NULL
)-start
) > timeout
) {
3828 static int syncReadLine(int fd
, char *ptr
, ssize_t size
, int timeout
) {
3835 if (syncRead(fd
,&c
,1,timeout
) == -1) return -1;
3838 if (nread
&& *(ptr
-1) == '\r') *(ptr
-1) = '\0';
3849 static void syncCommand(redisClient
*c
) {
3850 /* ignore SYNC if aleady slave or in monitor mode */
3851 if (c
->flags
& REDIS_SLAVE
) return;
3853 /* SYNC can't be issued when the server has pending data to send to
3854 * the client about already issued commands. We need a fresh reply
3855 * buffer registering the differences between the BGSAVE and the current
3856 * dataset, so that we can copy to other slaves if needed. */
3857 if (listLength(c
->reply
) != 0) {
3858 addReplySds(c
,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
3862 redisLog(REDIS_NOTICE
,"Slave ask for synchronization");
3863 /* Here we need to check if there is a background saving operation
3864 * in progress, or if it is required to start one */
3865 if (server
.bgsaveinprogress
) {
3866 /* Ok a background save is in progress. Let's check if it is a good
3867 * one for replication, i.e. if there is another slave that is
3868 * registering differences since the server forked to save */
3872 listRewind(server
.slaves
);
3873 while((ln
= listYield(server
.slaves
))) {
3875 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) break;
3878 /* Perfect, the server is already registering differences for
3879 * another slave. Set the right state, and copy the buffer. */
3880 listRelease(c
->reply
);
3881 c
->reply
= listDup(slave
->reply
);
3882 if (!c
->reply
) oom("listDup copying slave reply list");
3883 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
3884 redisLog(REDIS_NOTICE
,"Waiting for end of BGSAVE for SYNC");
3886 /* No way, we need to wait for the next BGSAVE in order to
3887 * register differences */
3888 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
3889 redisLog(REDIS_NOTICE
,"Waiting for next BGSAVE for SYNC");
3892 /* Ok we don't have a BGSAVE in progress, let's start one */
3893 redisLog(REDIS_NOTICE
,"Starting BGSAVE for SYNC");
3894 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
3895 redisLog(REDIS_NOTICE
,"Replication failed, can't BGSAVE");
3896 addReplySds(c
,sdsnew("-ERR Unalbe to perform background save\r\n"));
3899 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
3902 c
->flags
|= REDIS_SLAVE
;
3904 if (!listAddNodeTail(server
.slaves
,c
)) oom("listAddNodeTail");
3908 static void sendBulkToSlave(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
3909 redisClient
*slave
= privdata
;
3911 REDIS_NOTUSED(mask
);
3912 char buf
[REDIS_IOBUF_LEN
];
3913 ssize_t nwritten
, buflen
;
3915 if (slave
->repldboff
== 0) {
3916 /* Write the bulk write count before to transfer the DB. In theory here
3917 * we don't know how much room there is in the output buffer of the
3918 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
3919 * operations) will never be smaller than the few bytes we need. */
3922 bulkcount
= sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
3924 if (write(fd
,bulkcount
,sdslen(bulkcount
)) != (signed)sdslen(bulkcount
))
3932 lseek(slave
->repldbfd
,slave
->repldboff
,SEEK_SET
);
3933 buflen
= read(slave
->repldbfd
,buf
,REDIS_IOBUF_LEN
);
3935 redisLog(REDIS_WARNING
,"Read error sending DB to slave: %s",
3936 (buflen
== 0) ? "premature EOF" : strerror(errno
));
3940 if ((nwritten
= write(fd
,buf
,buflen
)) == -1) {
3941 redisLog(REDIS_DEBUG
,"Write error sending DB to slave: %s",
3946 slave
->repldboff
+= nwritten
;
3947 if (slave
->repldboff
== slave
->repldbsize
) {
3948 close(slave
->repldbfd
);
3949 slave
->repldbfd
= -1;
3950 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
3951 slave
->replstate
= REDIS_REPL_ONLINE
;
3952 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
,
3953 sendReplyToClient
, slave
, NULL
) == AE_ERR
) {
3957 addReplySds(slave
,sdsempty());
3958 redisLog(REDIS_NOTICE
,"Synchronization with slave succeeded");
3962 /* This function is called at the end of every backgrond saving.
3963 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
3964 * otherwise REDIS_ERR is passed to the function.
3966 * The goal of this function is to handle slaves waiting for a successful
3967 * background saving in order to perform non-blocking synchronization. */
3968 static void updateSlavesWaitingBgsave(int bgsaveerr
) {
3970 int startbgsave
= 0;
3972 listRewind(server
.slaves
);
3973 while((ln
= listYield(server
.slaves
))) {
3974 redisClient
*slave
= ln
->value
;
3976 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) {
3978 slave
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
3979 } else if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) {
3980 struct redis_stat buf
;
3982 if (bgsaveerr
!= REDIS_OK
) {
3984 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE child returned an error");
3987 if ((slave
->repldbfd
= open(server
.dbfilename
,O_RDONLY
)) == -1 ||
3988 redis_fstat(slave
->repldbfd
,&buf
) == -1) {
3990 redisLog(REDIS_WARNING
,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno
));
3993 slave
->repldboff
= 0;
3994 slave
->repldbsize
= buf
.st_size
;
3995 slave
->replstate
= REDIS_REPL_SEND_BULK
;
3996 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
3997 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
, sendBulkToSlave
, slave
, NULL
) == AE_ERR
) {
4004 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
4005 listRewind(server
.slaves
);
4006 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE failed");
4007 while((ln
= listYield(server
.slaves
))) {
4008 redisClient
*slave
= ln
->value
;
4010 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
)
4017 static int syncWithMaster(void) {
4018 char buf
[1024], tmpfile
[256];
4020 int fd
= anetTcpConnect(NULL
,server
.masterhost
,server
.masterport
);
4024 redisLog(REDIS_WARNING
,"Unable to connect to MASTER: %s",
4028 /* Issue the SYNC command */
4029 if (syncWrite(fd
,"SYNC \r\n",7,5) == -1) {
4031 redisLog(REDIS_WARNING
,"I/O error writing to MASTER: %s",
4035 /* Read the bulk write count */
4036 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
4038 redisLog(REDIS_WARNING
,"I/O error reading bulk count from MASTER: %s",
4042 dumpsize
= atoi(buf
+1);
4043 redisLog(REDIS_NOTICE
,"Receiving %d bytes data dump from MASTER",dumpsize
);
4044 /* Read the bulk write data on a temp file */
4045 snprintf(tmpfile
,256,"temp-%d.%ld.rdb",(int)time(NULL
),(long int)random());
4046 dfd
= open(tmpfile
,O_CREAT
|O_WRONLY
,0644);
4049 redisLog(REDIS_WARNING
,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno
));
4053 int nread
, nwritten
;
4055 nread
= read(fd
,buf
,(dumpsize
< 1024)?dumpsize
:1024);
4057 redisLog(REDIS_WARNING
,"I/O error trying to sync with MASTER: %s",
4063 nwritten
= write(dfd
,buf
,nread
);
4064 if (nwritten
== -1) {
4065 redisLog(REDIS_WARNING
,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno
));
4073 if (rename(tmpfile
,server
.dbfilename
) == -1) {
4074 redisLog(REDIS_WARNING
,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno
));
4080 if (rdbLoad(server
.dbfilename
) != REDIS_OK
) {
4081 redisLog(REDIS_WARNING
,"Failed trying to load the MASTER synchronization DB from disk");
4085 server
.master
= createClient(fd
);
4086 server
.master
->flags
|= REDIS_MASTER
;
4087 server
.replstate
= REDIS_REPL_CONNECTED
;
4091 static void slaveofCommand(redisClient
*c
) {
4092 if (!strcasecmp(c
->argv
[1]->ptr
,"no") &&
4093 !strcasecmp(c
->argv
[2]->ptr
,"one")) {
4094 if (server
.masterhost
) {
4095 sdsfree(server
.masterhost
);
4096 server
.masterhost
= NULL
;
4097 if (server
.master
) freeClient(server
.master
);
4098 server
.replstate
= REDIS_REPL_NONE
;
4099 redisLog(REDIS_NOTICE
,"MASTER MODE enabled (user request)");
4102 sdsfree(server
.masterhost
);
4103 server
.masterhost
= sdsdup(c
->argv
[1]->ptr
);
4104 server
.masterport
= atoi(c
->argv
[2]->ptr
);
4105 if (server
.master
) freeClient(server
.master
);
4106 server
.replstate
= REDIS_REPL_CONNECT
;
4107 redisLog(REDIS_NOTICE
,"SLAVE OF %s:%d enabled (user request)",
4108 server
.masterhost
, server
.masterport
);
4110 addReply(c
,shared
.ok
);
4113 /* ============================ Maxmemory directive ======================== */
4115 /* This function gets called when 'maxmemory' is set on the config file to limit
4116 * the max memory used by the server, and we are out of memory.
4117 * This function will try to, in order:
4119 * - Free objects from the free list
4120 * - Try to remove keys with an EXPIRE set
4122 * It is not possible to free enough memory to reach used-memory < maxmemory
4123 * the server will start refusing commands that will enlarge even more the
4126 static void freeMemoryIfNeeded(void) {
4127 while (server
.maxmemory
&& zmalloc_used_memory() > server
.maxmemory
) {
4128 if (listLength(server
.objfreelist
)) {
4131 listNode
*head
= listFirst(server
.objfreelist
);
4132 o
= listNodeValue(head
);
4133 listDelNode(server
.objfreelist
,head
);
4136 int j
, k
, freed
= 0;
4138 for (j
= 0; j
< server
.dbnum
; j
++) {
4140 robj
*minkey
= NULL
;
4141 struct dictEntry
*de
;
4143 if (dictSize(server
.db
[j
].expires
)) {
4145 /* From a sample of three keys drop the one nearest to
4146 * the natural expire */
4147 for (k
= 0; k
< 3; k
++) {
4150 de
= dictGetRandomKey(server
.db
[j
].expires
);
4151 t
= (time_t) dictGetEntryVal(de
);
4152 if (minttl
== -1 || t
< minttl
) {
4153 minkey
= dictGetEntryKey(de
);
4157 deleteKey(server
.db
+j
,minkey
);
4160 if (!freed
) return; /* nothing to free... */
4165 /* ================================= Debugging ============================== */
4167 static void debugCommand(redisClient
*c
) {
4168 if (!strcasecmp(c
->argv
[1]->ptr
,"segfault")) {
4170 } else if (!strcasecmp(c
->argv
[1]->ptr
,"object") && c
->argc
== 3) {
4171 dictEntry
*de
= dictFind(c
->db
->dict
,c
->argv
[2]);
4175 addReply(c
,shared
.nokeyerr
);
4178 key
= dictGetEntryKey(de
);
4179 val
= dictGetEntryVal(de
);
4180 addReplySds(c
,sdscatprintf(sdsempty(),
4181 "+Key at:%p refcount:%d, value at:%p refcount:%d\r\n",
4182 key
, key
->refcount
, val
, val
->refcount
));
4184 addReplySds(c
,sdsnew(
4185 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>]\r\n"));
4189 #ifdef HAVE_BACKTRACE
4190 static struct redisFunctionSym symsTable
[] = {
4191 {"freeStringObject", (unsigned long)freeStringObject
},
4192 {"freeListObject", (unsigned long)freeListObject
},
4193 {"freeSetObject", (unsigned long)freeSetObject
},
4194 {"decrRefCount", (unsigned long)decrRefCount
},
4195 {"createObject", (unsigned long)createObject
},
4196 {"freeClient", (unsigned long)freeClient
},
4197 {"rdbLoad", (unsigned long)rdbLoad
},
4198 {"addReply", (unsigned long)addReply
},
4199 {"addReplySds", (unsigned long)addReplySds
},
4200 {"incrRefCount", (unsigned long)incrRefCount
},
4201 {"rdbSaveBackground", (unsigned long)rdbSaveBackground
},
4202 {"createStringObject", (unsigned long)createStringObject
},
4203 {"replicationFeedSlaves", (unsigned long)replicationFeedSlaves
},
4204 {"syncWithMaster", (unsigned long)syncWithMaster
},
4205 {"tryObjectSharing", (unsigned long)tryObjectSharing
},
4206 {"removeExpire", (unsigned long)removeExpire
},
4207 {"expireIfNeeded", (unsigned long)expireIfNeeded
},
4208 {"deleteIfVolatile", (unsigned long)deleteIfVolatile
},
4209 {"deleteKey", (unsigned long)deleteKey
},
4210 {"getExpire", (unsigned long)getExpire
},
4211 {"setExpire", (unsigned long)setExpire
},
4212 {"updateSlavesWaitingBgsave", (unsigned long)updateSlavesWaitingBgsave
},
4213 {"freeMemoryIfNeeded", (unsigned long)freeMemoryIfNeeded
},
4214 {"authCommand", (unsigned long)authCommand
},
4215 {"pingCommand", (unsigned long)pingCommand
},
4216 {"echoCommand", (unsigned long)echoCommand
},
4217 {"setCommand", (unsigned long)setCommand
},
4218 {"setnxCommand", (unsigned long)setnxCommand
},
4219 {"getCommand", (unsigned long)getCommand
},
4220 {"delCommand", (unsigned long)delCommand
},
4221 {"existsCommand", (unsigned long)existsCommand
},
4222 {"incrCommand", (unsigned long)incrCommand
},
4223 {"decrCommand", (unsigned long)decrCommand
},
4224 {"incrbyCommand", (unsigned long)incrbyCommand
},
4225 {"decrbyCommand", (unsigned long)decrbyCommand
},
4226 {"selectCommand", (unsigned long)selectCommand
},
4227 {"randomkeyCommand", (unsigned long)randomkeyCommand
},
4228 {"keysCommand", (unsigned long)keysCommand
},
4229 {"dbsizeCommand", (unsigned long)dbsizeCommand
},
4230 {"lastsaveCommand", (unsigned long)lastsaveCommand
},
4231 {"saveCommand", (unsigned long)saveCommand
},
4232 {"bgsaveCommand", (unsigned long)bgsaveCommand
},
4233 {"shutdownCommand", (unsigned long)shutdownCommand
},
4234 {"moveCommand", (unsigned long)moveCommand
},
4235 {"renameCommand", (unsigned long)renameCommand
},
4236 {"renamenxCommand", (unsigned long)renamenxCommand
},
4237 {"lpushCommand", (unsigned long)lpushCommand
},
4238 {"rpushCommand", (unsigned long)rpushCommand
},
4239 {"lpopCommand", (unsigned long)lpopCommand
},
4240 {"rpopCommand", (unsigned long)rpopCommand
},
4241 {"llenCommand", (unsigned long)llenCommand
},
4242 {"lindexCommand", (unsigned long)lindexCommand
},
4243 {"lrangeCommand", (unsigned long)lrangeCommand
},
4244 {"ltrimCommand", (unsigned long)ltrimCommand
},
4245 {"typeCommand", (unsigned long)typeCommand
},
4246 {"lsetCommand", (unsigned long)lsetCommand
},
4247 {"saddCommand", (unsigned long)saddCommand
},
4248 {"sremCommand", (unsigned long)sremCommand
},
4249 {"smoveCommand", (unsigned long)smoveCommand
},
4250 {"sismemberCommand", (unsigned long)sismemberCommand
},
4251 {"scardCommand", (unsigned long)scardCommand
},
4252 {"spopCommand", (unsigned long)spopCommand
},
4253 {"sinterCommand", (unsigned long)sinterCommand
},
4254 {"sinterstoreCommand", (unsigned long)sinterstoreCommand
},
4255 {"sunionCommand", (unsigned long)sunionCommand
},
4256 {"sunionstoreCommand", (unsigned long)sunionstoreCommand
},
4257 {"sdiffCommand", (unsigned long)sdiffCommand
},
4258 {"sdiffstoreCommand", (unsigned long)sdiffstoreCommand
},
4259 {"syncCommand", (unsigned long)syncCommand
},
4260 {"flushdbCommand", (unsigned long)flushdbCommand
},
4261 {"flushallCommand", (unsigned long)flushallCommand
},
4262 {"sortCommand", (unsigned long)sortCommand
},
4263 {"lremCommand", (unsigned long)lremCommand
},
4264 {"infoCommand", (unsigned long)infoCommand
},
4265 {"mgetCommand", (unsigned long)mgetCommand
},
4266 {"monitorCommand", (unsigned long)monitorCommand
},
4267 {"expireCommand", (unsigned long)expireCommand
},
4268 {"getSetCommand", (unsigned long)getSetCommand
},
4269 {"ttlCommand", (unsigned long)ttlCommand
},
4270 {"slaveofCommand", (unsigned long)slaveofCommand
},
4271 {"debugCommand", (unsigned long)debugCommand
},
4272 {"processCommand", (unsigned long)processCommand
},
4273 {"setupSigSegvAction", (unsigned long)setupSigSegvAction
},
4274 {"readQueryFromClient", (unsigned long)readQueryFromClient
},
4275 {"rdbRemoveTempFile", (unsigned long)rdbRemoveTempFile
},
4279 /* This function try to convert a pointer into a function name. It's used in
4280 * oreder to provide a backtrace under segmentation fault that's able to
4281 * display functions declared as static (otherwise the backtrace is useless). */
4282 static char *findFuncName(void *pointer
, unsigned long *offset
){
4284 unsigned long off
, minoff
= 0;
4286 /* Try to match against the Symbol with the smallest offset */
4287 for (i
=0; symsTable
[i
].pointer
; i
++) {
4288 unsigned long lp
= (unsigned long) pointer
;
4290 if (lp
!= (unsigned long)-1 && lp
>= symsTable
[i
].pointer
) {
4291 off
=lp
-symsTable
[i
].pointer
;
4292 if (ret
< 0 || off
< minoff
) {
4298 if (ret
== -1) return NULL
;
4300 return symsTable
[ret
].name
;
4303 static void *getMcontextEip(ucontext_t
*uc
) {
4304 #if defined(__FreeBSD__)
4305 return (void*) uc
->uc_mcontext
.mc_eip
;
4306 #elif defined(__dietlibc__)
4307 return (void*) uc
->uc_mcontext
.eip
;
4308 #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
4309 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
4310 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
4311 #ifdef _STRUCT_X86_THREAD_STATE64
4312 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
4314 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
4316 #elif defined(__i386__) || defined(__X86_64__) /* Linux x86 */
4317 return (void*) uc
->uc_mcontext
.gregs
[REG_EIP
];
4318 #elif defined(__ia64__) /* Linux IA64 */
4319 return (void*) uc
->uc_mcontext
.sc_ip
;
4325 static void segvHandler(int sig
, siginfo_t
*info
, void *secret
) {
4327 char **messages
= NULL
;
4328 int i
, trace_size
= 0;
4329 unsigned long offset
=0;
4330 time_t uptime
= time(NULL
)-server
.stat_starttime
;
4331 ucontext_t
*uc
= (ucontext_t
*) secret
;
4332 REDIS_NOTUSED(info
);
4334 redisLog(REDIS_WARNING
,
4335 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION
, sig
);
4336 redisLog(REDIS_WARNING
, "%s", sdscatprintf(sdsempty(),
4337 "redis_version:%s; "
4338 "uptime_in_seconds:%d; "
4339 "connected_clients:%d; "
4340 "connected_slaves:%d; "
4342 "changes_since_last_save:%lld; "
4343 "bgsave_in_progress:%d; "
4344 "last_save_time:%d; "
4345 "total_connections_received:%lld; "
4346 "total_commands_processed:%lld; "
4350 listLength(server
.clients
)-listLength(server
.slaves
),
4351 listLength(server
.slaves
),
4354 server
.bgsaveinprogress
,
4356 server
.stat_numconnections
,
4357 server
.stat_numcommands
,
4358 server
.masterhost
== NULL
? "master" : "slave"
4361 trace_size
= backtrace(trace
, 100);
4362 /* overwrite sigaction with caller's address */
4363 if (getMcontextEip(uc
) != NULL
) {
4364 trace
[1] = getMcontextEip(uc
);
4366 messages
= backtrace_symbols(trace
, trace_size
);
4368 for (i
=1; i
<trace_size
; ++i
) {
4369 char *fn
= findFuncName(trace
[i
], &offset
), *p
;
4371 p
= strchr(messages
[i
],'+');
4372 if (!fn
|| (p
&& ((unsigned long)strtol(p
+1,NULL
,10)) < offset
)) {
4373 redisLog(REDIS_WARNING
,"%s", messages
[i
]);
4375 redisLog(REDIS_WARNING
,"%d redis-server %p %s + %d", i
, trace
[i
], fn
, (unsigned int)offset
);
4382 static void setupSigSegvAction(void) {
4383 struct sigaction act
;
4385 sigemptyset (&act
.sa_mask
);
4386 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
4387 * is used. Otherwise, sa_handler is used */
4388 act
.sa_flags
= SA_NODEFER
| SA_ONSTACK
| SA_RESETHAND
| SA_SIGINFO
;
4389 act
.sa_sigaction
= segvHandler
;
4390 sigaction (SIGSEGV
, &act
, NULL
);
4391 sigaction (SIGBUS
, &act
, NULL
);
4392 sigaction (SIGFPE
, &act
, NULL
);
4393 sigaction (SIGILL
, &act
, NULL
);
4394 sigaction (SIGBUS
, &act
, NULL
);
4397 #else /* HAVE_BACKTRACE */
4398 static void setupSigSegvAction(void) {
4400 #endif /* HAVE_BACKTRACE */
4402 /* =================================== Main! ================================ */
4405 int linuxOvercommitMemoryValue(void) {
4406 FILE *fp
= fopen("/proc/sys/vm/overcommit_memory","r");
4410 if (fgets(buf
,64,fp
) == NULL
) {
4419 void linuxOvercommitMemoryWarning(void) {
4420 if (linuxOvercommitMemoryValue() == 0) {
4421 redisLog(REDIS_WARNING
,"WARNING overcommit_memory is set to 0! Background save may fail under low condition memory. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.");
4424 #endif /* __linux__ */
4426 static void daemonize(void) {
4430 if (fork() != 0) exit(0); /* parent exits */
4431 setsid(); /* create a new session */
4433 /* Every output goes to /dev/null. If Redis is daemonized but
4434 * the 'logfile' is set to 'stdout' in the configuration file
4435 * it will not log at all. */
4436 if ((fd
= open("/dev/null", O_RDWR
, 0)) != -1) {
4437 dup2(fd
, STDIN_FILENO
);
4438 dup2(fd
, STDOUT_FILENO
);
4439 dup2(fd
, STDERR_FILENO
);
4440 if (fd
> STDERR_FILENO
) close(fd
);
4442 /* Try to write the pid file */
4443 fp
= fopen(server
.pidfile
,"w");
4445 fprintf(fp
,"%d\n",getpid());
4450 int main(int argc
, char **argv
) {
4453 ResetServerSaveParams();
4454 loadServerConfig(argv
[1]);
4455 } else if (argc
> 2) {
4456 fprintf(stderr
,"Usage: ./redis-server [/path/to/redis.conf]\n");
4459 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'");
4462 if (server
.daemonize
) daemonize();
4463 redisLog(REDIS_NOTICE
,"Server started, Redis version " REDIS_VERSION
);
4465 linuxOvercommitMemoryWarning();
4467 if (rdbLoad(server
.dbfilename
) == REDIS_OK
)
4468 redisLog(REDIS_NOTICE
,"DB loaded from disk");
4469 if (aeCreateFileEvent(server
.el
, server
.fd
, AE_READABLE
,
4470 acceptHandler
, NULL
, NULL
) == AE_ERR
) oom("creating file event");
4471 redisLog(REDIS_NOTICE
,"The server is now ready to accept connections on port %d", server
.port
);
4473 aeDeleteEventLoop(server
.el
);