2 * Copyright (c) 2006-2009, Salvatore Sanfilippo <antirez at gmail dot com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Redis nor the names of its contributors may be used
14 * to endorse or promote products derived from this software without
15 * specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
30 #define REDIS_VERSION "1.3.2"
40 #define __USE_POSIX199309
46 #endif /* HAVE_BACKTRACE */
54 #include <arpa/inet.h>
58 #include <sys/resource.h>
64 #include "solarisfixes.h"
68 #include "ae.h" /* Event driven programming library */
69 #include "sds.h" /* Dynamic safe strings */
70 #include "anet.h" /* Networking the easy way */
71 #include "dict.h" /* Hash tables */
72 #include "adlist.h" /* Linked lists */
73 #include "zmalloc.h" /* total memory usage aware version of malloc/free */
74 #include "lzf.h" /* LZF compression library */
75 #include "pqsort.h" /* Partial qsort for SORT+LIMIT */
81 /* Static server configuration */
82 #define REDIS_SERVERPORT 6379 /* TCP port */
83 #define REDIS_MAXIDLETIME (60*5) /* default client timeout */
84 #define REDIS_IOBUF_LEN 1024
85 #define REDIS_LOADBUF_LEN 1024
86 #define REDIS_STATIC_ARGS 4
87 #define REDIS_DEFAULT_DBNUM 16
88 #define REDIS_CONFIGLINE_MAX 1024
89 #define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
90 #define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
91 #define REDIS_EXPIRELOOKUPS_PER_CRON 100 /* try to expire 100 keys/second */
92 #define REDIS_MAX_WRITE_PER_EVENT (1024*64)
93 #define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
95 /* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
96 #define REDIS_WRITEV_THRESHOLD 3
97 /* Max number of iovecs used for each writev call */
98 #define REDIS_WRITEV_IOVEC_COUNT 256
100 /* Hash table parameters */
101 #define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
104 #define REDIS_CMD_BULK 1 /* Bulk write command */
105 #define REDIS_CMD_INLINE 2 /* Inline command */
106 /* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
107 this flags will return an error when the 'maxmemory' option is set in the
108 config file and the server is using more than maxmemory bytes of memory.
109 In short this commands are denied on low memory conditions. */
110 #define REDIS_CMD_DENYOOM 4
113 #define REDIS_STRING 0
119 /* Objects encoding */
120 #define REDIS_ENCODING_RAW 0 /* Raw representation */
121 #define REDIS_ENCODING_INT 1 /* Encoded as integer */
123 /* Object types only used for dumping to disk */
124 #define REDIS_EXPIRETIME 253
125 #define REDIS_SELECTDB 254
126 #define REDIS_EOF 255
128 /* Defines related to the dump file format. To store 32 bits lengths for short
129 * keys requires a lot of space, so we check the most significant 2 bits of
130 * the first byte to interpreter the length:
132 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
133 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
134 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
135 * 11|000000 this means: specially encoded object will follow. The six bits
136 * number specify the kind of object that follows.
137 * See the REDIS_RDB_ENC_* defines.
139 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
140 * values, will fit inside. */
141 #define REDIS_RDB_6BITLEN 0
142 #define REDIS_RDB_14BITLEN 1
143 #define REDIS_RDB_32BITLEN 2
144 #define REDIS_RDB_ENCVAL 3
145 #define REDIS_RDB_LENERR UINT_MAX
147 /* When a length of a string object stored on disk has the first two bits
148 * set, the remaining two bits specify a special encoding for the object
149 * accordingly to the following defines: */
150 #define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
151 #define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
152 #define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
153 #define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
155 /* Virtual memory object->where field. */
156 #define REDIS_VM_MEMORY 0 /* The object is on memory */
157 #define REDIS_VM_SWAPPED 1 /* The object is on disk */
158 #define REDIS_VM_SWAPPING 2 /* Redis is swapping this object on disk */
159 #define REDIS_VM_LOADING 3 /* Redis is loading this object from disk */
161 /* Virtual memory static configuration stuff.
162 * Check vmFindContiguousPages() to know more about this magic numbers. */
163 #define REDIS_VM_MAX_NEAR_PAGES 65536
164 #define REDIS_VM_MAX_RANDOM_JUMP 4096
167 #define REDIS_CLOSE 1 /* This client connection should be closed ASAP */
168 #define REDIS_SLAVE 2 /* This client is a slave server */
169 #define REDIS_MASTER 4 /* This client is a master server */
170 #define REDIS_MONITOR 8 /* This client is a slave monitor, see MONITOR */
171 #define REDIS_MULTI 16 /* This client is in a MULTI context */
172 #define REDIS_BLOCKED 32 /* The client is waiting in a blocking operation */
174 /* Slave replication state - slave side */
175 #define REDIS_REPL_NONE 0 /* No active replication */
176 #define REDIS_REPL_CONNECT 1 /* Must connect to master */
177 #define REDIS_REPL_CONNECTED 2 /* Connected to master */
179 /* Slave replication state - from the point of view of master
180 * Note that in SEND_BULK and ONLINE state the slave receives new updates
181 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
182 * to start the next background saving in order to send updates to it. */
183 #define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
184 #define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
185 #define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
186 #define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
188 /* List related stuff */
192 /* Sort operations */
193 #define REDIS_SORT_GET 0
194 #define REDIS_SORT_ASC 1
195 #define REDIS_SORT_DESC 2
196 #define REDIS_SORTKEY_MAX 1024
199 #define REDIS_DEBUG 0
200 #define REDIS_NOTICE 1
201 #define REDIS_WARNING 2
203 /* Anti-warning macro... */
204 #define REDIS_NOTUSED(V) ((void) V)
206 #define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
207 #define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
209 /* Append only defines */
210 #define APPENDFSYNC_NO 0
211 #define APPENDFSYNC_ALWAYS 1
212 #define APPENDFSYNC_EVERYSEC 2
214 /* We can print the stacktrace, so our assert is defined this way: */
215 #define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e),exit(1)))
216 static void _redisAssert(char *estr
);
218 /*================================= Data types ============================== */
220 /* A redis object, that is a type able to hold a string / list / set */
222 /* The VM object structure */
223 struct redisObjectVM
{
224 off_t page
; /* the page at witch the object is stored on disk */
225 off_t usedpages
; /* number of pages used on disk */
226 time_t atime
; /* Last access time */
229 /* The actual Redis Object */
230 typedef struct redisObject
{
233 unsigned char encoding
;
234 unsigned char storage
; /* where? REDIS_VM_MEMORY, REDIS_VM_SWAPPED, ... */
235 unsigned char notused
;
237 /* VM fields, this are only allocated if VM is active, otherwise the
238 * object allocation function will just allocate
239 * sizeof(redisObjct) minus sizeof(redisObjectVM), so using
240 * Redis without VM active will not have any overhead. */
241 struct redisObjectVM vm
;
244 /* Macro used to initalize a Redis object allocated on the stack.
245 * Note that this macro is taken near the structure definition to make sure
246 * we'll update it when the structure is changed, to avoid bugs like
247 * bug #85 introduced exactly in this way. */
248 #define initStaticStringObject(_var,_ptr) do { \
250 _var.type = REDIS_STRING; \
251 _var.encoding = REDIS_ENCODING_RAW; \
253 if (server.vm_enabled) _var.storage = REDIS_VM_MEMORY; \
256 typedef struct redisDb
{
257 dict
*dict
; /* The keyspace for this DB */
258 dict
*expires
; /* Timeout of keys with a timeout set */
259 dict
*blockingkeys
; /* Keys with clients waiting for data (BLPOP) */
263 /* Client MULTI/EXEC state */
264 typedef struct multiCmd
{
267 struct redisCommand
*cmd
;
270 typedef struct multiState
{
271 multiCmd
*commands
; /* Array of MULTI commands */
272 int count
; /* Total number of MULTI commands */
275 /* With multiplexing we need to take per-clinet state.
276 * Clients are taken in a liked list. */
277 typedef struct redisClient
{
282 robj
**argv
, **mbargv
;
284 int bulklen
; /* bulk read len. -1 if not in bulk read mode */
285 int multibulk
; /* multi bulk command format active */
288 time_t lastinteraction
; /* time of the last interaction, used for timeout */
289 int flags
; /* REDIS_CLOSE | REDIS_SLAVE | REDIS_MONITOR */
291 int slaveseldb
; /* slave selected db, if this client is a slave */
292 int authenticated
; /* when requirepass is non-NULL */
293 int replstate
; /* replication state if this is a slave */
294 int repldbfd
; /* replication DB file descriptor */
295 long repldboff
; /* replication DB file offset */
296 off_t repldbsize
; /* replication DB file size */
297 multiState mstate
; /* MULTI/EXEC state */
298 robj
**blockingkeys
; /* The key we waiting to terminate a blocking
299 * operation such as BLPOP. Otherwise NULL. */
300 int blockingkeysnum
; /* Number of blocking keys */
301 time_t blockingto
; /* Blocking operation timeout. If UNIX current time
302 * is >= blockingto then the operation timed out. */
310 /* Global server state structure */
315 dict
*sharingpool
; /* Poll used for object sharing */
316 unsigned int sharingpoolsize
;
317 long long dirty
; /* changes to DB from the last save */
319 list
*slaves
, *monitors
;
320 char neterr
[ANET_ERR_LEN
];
322 int cronloops
; /* number of times the cron function run */
323 list
*objfreelist
; /* A list of freed objects to avoid malloc() */
324 time_t lastsave
; /* Unix time of last save succeeede */
325 size_t usedmemory
; /* Used memory in megabytes */
326 /* Fields used only for stats */
327 time_t stat_starttime
; /* server start time */
328 long long stat_numcommands
; /* number of processed commands */
329 long long stat_numconnections
; /* number of connections received */
342 pid_t bgsavechildpid
;
343 pid_t bgrewritechildpid
;
344 sds bgrewritebuf
; /* buffer taken by parent during oppend only rewrite */
345 struct saveparam
*saveparams
;
350 char *appendfilename
;
354 /* Replication related */
359 redisClient
*master
; /* client that is master for this slave */
361 unsigned int maxclients
;
362 unsigned long maxmemory
;
363 unsigned int blockedclients
;
364 /* Sort parameters - qsort_r() is only available under BSD so we
365 * have to take this state global, in order to pass it to sortCompare() */
369 /* Virtual memory configuration */
374 /* Virtual memory state */
377 off_t vm_next_page
; /* Next probably empty page */
378 off_t vm_near_pages
; /* Number of pages allocated sequentially */
379 unsigned char *vm_bitmap
; /* Bitmap of free/used pages */
380 time_t unixtime
; /* Unix time sampled every second. */
383 typedef void redisCommandProc(redisClient
*c
);
384 struct redisCommand
{
386 redisCommandProc
*proc
;
391 struct redisFunctionSym
{
393 unsigned long pointer
;
396 typedef struct _redisSortObject
{
404 typedef struct _redisSortOperation
{
407 } redisSortOperation
;
409 /* ZSETs use a specialized version of Skiplists */
411 typedef struct zskiplistNode
{
412 struct zskiplistNode
**forward
;
413 struct zskiplistNode
*backward
;
418 typedef struct zskiplist
{
419 struct zskiplistNode
*header
, *tail
;
420 unsigned long length
;
424 typedef struct zset
{
429 /* Our shared "common" objects */
431 struct sharedObjectsStruct
{
432 robj
*crlf
, *ok
, *err
, *emptybulk
, *czero
, *cone
, *pong
, *space
,
433 *colon
, *nullbulk
, *nullmultibulk
, *queued
,
434 *emptymultibulk
, *wrongtypeerr
, *nokeyerr
, *syntaxerr
, *sameobjecterr
,
435 *outofrangeerr
, *plus
,
436 *select0
, *select1
, *select2
, *select3
, *select4
,
437 *select5
, *select6
, *select7
, *select8
, *select9
;
440 /* Global vars that are actally used as constants. The following double
441 * values are used for double on-disk serialization, and are initialized
442 * at runtime to avoid strange compiler optimizations. */
444 static double R_Zero
, R_PosInf
, R_NegInf
, R_Nan
;
446 /*================================ Prototypes =============================== */
448 static void freeStringObject(robj
*o
);
449 static void freeListObject(robj
*o
);
450 static void freeSetObject(robj
*o
);
451 static void decrRefCount(void *o
);
452 static robj
*createObject(int type
, void *ptr
);
453 static void freeClient(redisClient
*c
);
454 static int rdbLoad(char *filename
);
455 static void addReply(redisClient
*c
, robj
*obj
);
456 static void addReplySds(redisClient
*c
, sds s
);
457 static void incrRefCount(robj
*o
);
458 static int rdbSaveBackground(char *filename
);
459 static robj
*createStringObject(char *ptr
, size_t len
);
460 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
);
461 static void feedAppendOnlyFile(struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
);
462 static int syncWithMaster(void);
463 static robj
*tryObjectSharing(robj
*o
);
464 static int tryObjectEncoding(robj
*o
);
465 static robj
*getDecodedObject(robj
*o
);
466 static int removeExpire(redisDb
*db
, robj
*key
);
467 static int expireIfNeeded(redisDb
*db
, robj
*key
);
468 static int deleteIfVolatile(redisDb
*db
, robj
*key
);
469 static int deleteKey(redisDb
*db
, robj
*key
);
470 static time_t getExpire(redisDb
*db
, robj
*key
);
471 static int setExpire(redisDb
*db
, robj
*key
, time_t when
);
472 static void updateSlavesWaitingBgsave(int bgsaveerr
);
473 static void freeMemoryIfNeeded(void);
474 static int processCommand(redisClient
*c
);
475 static void setupSigSegvAction(void);
476 static void rdbRemoveTempFile(pid_t childpid
);
477 static void aofRemoveTempFile(pid_t childpid
);
478 static size_t stringObjectLen(robj
*o
);
479 static void processInputBuffer(redisClient
*c
);
480 static zskiplist
*zslCreate(void);
481 static void zslFree(zskiplist
*zsl
);
482 static void zslInsert(zskiplist
*zsl
, double score
, robj
*obj
);
483 static void sendReplyToClientWritev(aeEventLoop
*el
, int fd
, void *privdata
, int mask
);
484 static void initClientMultiState(redisClient
*c
);
485 static void freeClientMultiState(redisClient
*c
);
486 static void queueMultiCommand(redisClient
*c
, struct redisCommand
*cmd
);
487 static void unblockClient(redisClient
*c
);
488 static int handleClientsWaitingListPush(redisClient
*c
, robj
*key
, robj
*ele
);
489 static void vmInit(void);
490 static void vmMarkPagesFree(off_t page
, off_t count
);
491 static robj
*vmLoadObject(robj
*key
);
493 static void authCommand(redisClient
*c
);
494 static void pingCommand(redisClient
*c
);
495 static void echoCommand(redisClient
*c
);
496 static void setCommand(redisClient
*c
);
497 static void setnxCommand(redisClient
*c
);
498 static void getCommand(redisClient
*c
);
499 static void delCommand(redisClient
*c
);
500 static void existsCommand(redisClient
*c
);
501 static void incrCommand(redisClient
*c
);
502 static void decrCommand(redisClient
*c
);
503 static void incrbyCommand(redisClient
*c
);
504 static void decrbyCommand(redisClient
*c
);
505 static void selectCommand(redisClient
*c
);
506 static void randomkeyCommand(redisClient
*c
);
507 static void keysCommand(redisClient
*c
);
508 static void dbsizeCommand(redisClient
*c
);
509 static void lastsaveCommand(redisClient
*c
);
510 static void saveCommand(redisClient
*c
);
511 static void bgsaveCommand(redisClient
*c
);
512 static void bgrewriteaofCommand(redisClient
*c
);
513 static void shutdownCommand(redisClient
*c
);
514 static void moveCommand(redisClient
*c
);
515 static void renameCommand(redisClient
*c
);
516 static void renamenxCommand(redisClient
*c
);
517 static void lpushCommand(redisClient
*c
);
518 static void rpushCommand(redisClient
*c
);
519 static void lpopCommand(redisClient
*c
);
520 static void rpopCommand(redisClient
*c
);
521 static void llenCommand(redisClient
*c
);
522 static void lindexCommand(redisClient
*c
);
523 static void lrangeCommand(redisClient
*c
);
524 static void ltrimCommand(redisClient
*c
);
525 static void typeCommand(redisClient
*c
);
526 static void lsetCommand(redisClient
*c
);
527 static void saddCommand(redisClient
*c
);
528 static void sremCommand(redisClient
*c
);
529 static void smoveCommand(redisClient
*c
);
530 static void sismemberCommand(redisClient
*c
);
531 static void scardCommand(redisClient
*c
);
532 static void spopCommand(redisClient
*c
);
533 static void srandmemberCommand(redisClient
*c
);
534 static void sinterCommand(redisClient
*c
);
535 static void sinterstoreCommand(redisClient
*c
);
536 static void sunionCommand(redisClient
*c
);
537 static void sunionstoreCommand(redisClient
*c
);
538 static void sdiffCommand(redisClient
*c
);
539 static void sdiffstoreCommand(redisClient
*c
);
540 static void syncCommand(redisClient
*c
);
541 static void flushdbCommand(redisClient
*c
);
542 static void flushallCommand(redisClient
*c
);
543 static void sortCommand(redisClient
*c
);
544 static void lremCommand(redisClient
*c
);
545 static void rpoplpushcommand(redisClient
*c
);
546 static void infoCommand(redisClient
*c
);
547 static void mgetCommand(redisClient
*c
);
548 static void monitorCommand(redisClient
*c
);
549 static void expireCommand(redisClient
*c
);
550 static void expireatCommand(redisClient
*c
);
551 static void getsetCommand(redisClient
*c
);
552 static void ttlCommand(redisClient
*c
);
553 static void slaveofCommand(redisClient
*c
);
554 static void debugCommand(redisClient
*c
);
555 static void msetCommand(redisClient
*c
);
556 static void msetnxCommand(redisClient
*c
);
557 static void zaddCommand(redisClient
*c
);
558 static void zincrbyCommand(redisClient
*c
);
559 static void zrangeCommand(redisClient
*c
);
560 static void zrangebyscoreCommand(redisClient
*c
);
561 static void zrevrangeCommand(redisClient
*c
);
562 static void zcardCommand(redisClient
*c
);
563 static void zremCommand(redisClient
*c
);
564 static void zscoreCommand(redisClient
*c
);
565 static void zremrangebyscoreCommand(redisClient
*c
);
566 static void multiCommand(redisClient
*c
);
567 static void execCommand(redisClient
*c
);
568 static void blpopCommand(redisClient
*c
);
569 static void brpopCommand(redisClient
*c
);
571 /*================================= Globals ================================= */
574 static struct redisServer server
; /* server global state */
575 static struct redisCommand cmdTable
[] = {
576 {"get",getCommand
,2,REDIS_CMD_INLINE
},
577 {"set",setCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
578 {"setnx",setnxCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
579 {"del",delCommand
,-2,REDIS_CMD_INLINE
},
580 {"exists",existsCommand
,2,REDIS_CMD_INLINE
},
581 {"incr",incrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
582 {"decr",decrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
583 {"mget",mgetCommand
,-2,REDIS_CMD_INLINE
},
584 {"rpush",rpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
585 {"lpush",lpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
586 {"rpop",rpopCommand
,2,REDIS_CMD_INLINE
},
587 {"lpop",lpopCommand
,2,REDIS_CMD_INLINE
},
588 {"brpop",brpopCommand
,-3,REDIS_CMD_INLINE
},
589 {"blpop",blpopCommand
,-3,REDIS_CMD_INLINE
},
590 {"llen",llenCommand
,2,REDIS_CMD_INLINE
},
591 {"lindex",lindexCommand
,3,REDIS_CMD_INLINE
},
592 {"lset",lsetCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
593 {"lrange",lrangeCommand
,4,REDIS_CMD_INLINE
},
594 {"ltrim",ltrimCommand
,4,REDIS_CMD_INLINE
},
595 {"lrem",lremCommand
,4,REDIS_CMD_BULK
},
596 {"rpoplpush",rpoplpushcommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
597 {"sadd",saddCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
598 {"srem",sremCommand
,3,REDIS_CMD_BULK
},
599 {"smove",smoveCommand
,4,REDIS_CMD_BULK
},
600 {"sismember",sismemberCommand
,3,REDIS_CMD_BULK
},
601 {"scard",scardCommand
,2,REDIS_CMD_INLINE
},
602 {"spop",spopCommand
,2,REDIS_CMD_INLINE
},
603 {"srandmember",srandmemberCommand
,2,REDIS_CMD_INLINE
},
604 {"sinter",sinterCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
605 {"sinterstore",sinterstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
606 {"sunion",sunionCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
607 {"sunionstore",sunionstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
608 {"sdiff",sdiffCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
609 {"sdiffstore",sdiffstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
610 {"smembers",sinterCommand
,2,REDIS_CMD_INLINE
},
611 {"zadd",zaddCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
612 {"zincrby",zincrbyCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
613 {"zrem",zremCommand
,3,REDIS_CMD_BULK
},
614 {"zremrangebyscore",zremrangebyscoreCommand
,4,REDIS_CMD_INLINE
},
615 {"zrange",zrangeCommand
,-4,REDIS_CMD_INLINE
},
616 {"zrangebyscore",zrangebyscoreCommand
,-4,REDIS_CMD_INLINE
},
617 {"zrevrange",zrevrangeCommand
,-4,REDIS_CMD_INLINE
},
618 {"zcard",zcardCommand
,2,REDIS_CMD_INLINE
},
619 {"zscore",zscoreCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
620 {"incrby",incrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
621 {"decrby",decrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
622 {"getset",getsetCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
623 {"mset",msetCommand
,-3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
624 {"msetnx",msetnxCommand
,-3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
},
625 {"randomkey",randomkeyCommand
,1,REDIS_CMD_INLINE
},
626 {"select",selectCommand
,2,REDIS_CMD_INLINE
},
627 {"move",moveCommand
,3,REDIS_CMD_INLINE
},
628 {"rename",renameCommand
,3,REDIS_CMD_INLINE
},
629 {"renamenx",renamenxCommand
,3,REDIS_CMD_INLINE
},
630 {"expire",expireCommand
,3,REDIS_CMD_INLINE
},
631 {"expireat",expireatCommand
,3,REDIS_CMD_INLINE
},
632 {"keys",keysCommand
,2,REDIS_CMD_INLINE
},
633 {"dbsize",dbsizeCommand
,1,REDIS_CMD_INLINE
},
634 {"auth",authCommand
,2,REDIS_CMD_INLINE
},
635 {"ping",pingCommand
,1,REDIS_CMD_INLINE
},
636 {"echo",echoCommand
,2,REDIS_CMD_BULK
},
637 {"save",saveCommand
,1,REDIS_CMD_INLINE
},
638 {"bgsave",bgsaveCommand
,1,REDIS_CMD_INLINE
},
639 {"bgrewriteaof",bgrewriteaofCommand
,1,REDIS_CMD_INLINE
},
640 {"shutdown",shutdownCommand
,1,REDIS_CMD_INLINE
},
641 {"lastsave",lastsaveCommand
,1,REDIS_CMD_INLINE
},
642 {"type",typeCommand
,2,REDIS_CMD_INLINE
},
643 {"multi",multiCommand
,1,REDIS_CMD_INLINE
},
644 {"exec",execCommand
,1,REDIS_CMD_INLINE
},
645 {"sync",syncCommand
,1,REDIS_CMD_INLINE
},
646 {"flushdb",flushdbCommand
,1,REDIS_CMD_INLINE
},
647 {"flushall",flushallCommand
,1,REDIS_CMD_INLINE
},
648 {"sort",sortCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
},
649 {"info",infoCommand
,1,REDIS_CMD_INLINE
},
650 {"monitor",monitorCommand
,1,REDIS_CMD_INLINE
},
651 {"ttl",ttlCommand
,2,REDIS_CMD_INLINE
},
652 {"slaveof",slaveofCommand
,3,REDIS_CMD_INLINE
},
653 {"debug",debugCommand
,-2,REDIS_CMD_INLINE
},
657 /*============================ Utility functions ============================ */
659 /* Glob-style pattern matching. */
660 int stringmatchlen(const char *pattern
, int patternLen
,
661 const char *string
, int stringLen
, int nocase
)
666 while (pattern
[1] == '*') {
671 return 1; /* match */
673 if (stringmatchlen(pattern
+1, patternLen
-1,
674 string
, stringLen
, nocase
))
675 return 1; /* match */
679 return 0; /* no match */
683 return 0; /* no match */
693 not = pattern
[0] == '^';
700 if (pattern
[0] == '\\') {
703 if (pattern
[0] == string
[0])
705 } else if (pattern
[0] == ']') {
707 } else if (patternLen
== 0) {
711 } else if (pattern
[1] == '-' && patternLen
>= 3) {
712 int start
= pattern
[0];
713 int end
= pattern
[2];
721 start
= tolower(start
);
727 if (c
>= start
&& c
<= end
)
731 if (pattern
[0] == string
[0])
734 if (tolower((int)pattern
[0]) == tolower((int)string
[0]))
744 return 0; /* no match */
750 if (patternLen
>= 2) {
757 if (pattern
[0] != string
[0])
758 return 0; /* no match */
760 if (tolower((int)pattern
[0]) != tolower((int)string
[0]))
761 return 0; /* no match */
769 if (stringLen
== 0) {
770 while(*pattern
== '*') {
777 if (patternLen
== 0 && stringLen
== 0)
782 static void redisLog(int level
, const char *fmt
, ...) {
786 fp
= (server
.logfile
== NULL
) ? stdout
: fopen(server
.logfile
,"a");
790 if (level
>= server
.verbosity
) {
796 strftime(buf
,64,"%d %b %H:%M:%S",localtime(&now
));
797 fprintf(fp
,"%s %c ",buf
,c
[level
]);
798 vfprintf(fp
, fmt
, ap
);
804 if (server
.logfile
) fclose(fp
);
807 /*====================== Hash table type implementation ==================== */
809 /* This is an hash table type that uses the SDS dynamic strings libary as
810 * keys and radis objects as values (objects can hold SDS strings,
813 static void dictVanillaFree(void *privdata
, void *val
)
815 DICT_NOTUSED(privdata
);
819 static void dictListDestructor(void *privdata
, void *val
)
821 DICT_NOTUSED(privdata
);
822 listRelease((list
*)val
);
825 static int sdsDictKeyCompare(void *privdata
, const void *key1
,
829 DICT_NOTUSED(privdata
);
831 l1
= sdslen((sds
)key1
);
832 l2
= sdslen((sds
)key2
);
833 if (l1
!= l2
) return 0;
834 return memcmp(key1
, key2
, l1
) == 0;
837 static void dictRedisObjectDestructor(void *privdata
, void *val
)
839 DICT_NOTUSED(privdata
);
841 if (val
== NULL
) return; /* Values of swapped out keys as set to NULL */
845 static int dictObjKeyCompare(void *privdata
, const void *key1
,
848 const robj
*o1
= key1
, *o2
= key2
;
849 return sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
852 static unsigned int dictObjHash(const void *key
) {
854 return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
857 static int dictEncObjKeyCompare(void *privdata
, const void *key1
,
860 robj
*o1
= (robj
*) key1
, *o2
= (robj
*) key2
;
863 o1
= getDecodedObject(o1
);
864 o2
= getDecodedObject(o2
);
865 cmp
= sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
871 static unsigned int dictEncObjHash(const void *key
) {
872 robj
*o
= (robj
*) key
;
874 o
= getDecodedObject(o
);
875 unsigned int hash
= dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
880 static dictType setDictType
= {
881 dictEncObjHash
, /* hash function */
884 dictEncObjKeyCompare
, /* key compare */
885 dictRedisObjectDestructor
, /* key destructor */
886 NULL
/* val destructor */
889 static dictType zsetDictType
= {
890 dictEncObjHash
, /* hash function */
893 dictEncObjKeyCompare
, /* key compare */
894 dictRedisObjectDestructor
, /* key destructor */
895 dictVanillaFree
/* val destructor of malloc(sizeof(double)) */
898 static dictType hashDictType
= {
899 dictObjHash
, /* hash function */
902 dictObjKeyCompare
, /* key compare */
903 dictRedisObjectDestructor
, /* key destructor */
904 dictRedisObjectDestructor
/* val destructor */
907 /* Keylist hash table type has unencoded redis objects as keys and
908 * lists as values. It's used for blocking operations (BLPOP) */
909 static dictType keylistDictType
= {
910 dictObjHash
, /* hash function */
913 dictObjKeyCompare
, /* key compare */
914 dictRedisObjectDestructor
, /* key destructor */
915 dictListDestructor
/* val destructor */
918 /* ========================= Random utility functions ======================= */
920 /* Redis generally does not try to recover from out of memory conditions
921 * when allocating objects or strings, it is not clear if it will be possible
922 * to report this condition to the client since the networking layer itself
923 * is based on heap allocation for send buffers, so we simply abort.
924 * At least the code will be simpler to read... */
925 static void oom(const char *msg
) {
926 redisLog(REDIS_WARNING
, "%s: Out of memory\n",msg
);
931 /* ====================== Redis server networking stuff ===================== */
932 static void closeTimedoutClients(void) {
935 time_t now
= time(NULL
);
937 listRewind(server
.clients
);
938 while ((ln
= listYield(server
.clients
)) != NULL
) {
939 c
= listNodeValue(ln
);
940 if (server
.maxidletime
&&
941 !(c
->flags
& REDIS_SLAVE
) && /* no timeout for slaves */
942 !(c
->flags
& REDIS_MASTER
) && /* no timeout for masters */
943 (now
- c
->lastinteraction
> server
.maxidletime
))
945 redisLog(REDIS_DEBUG
,"Closing idle client");
947 } else if (c
->flags
& REDIS_BLOCKED
) {
948 if (c
->blockingto
!= 0 && c
->blockingto
< now
) {
949 addReply(c
,shared
.nullmultibulk
);
956 static int htNeedsResize(dict
*dict
) {
957 long long size
, used
;
959 size
= dictSlots(dict
);
960 used
= dictSize(dict
);
961 return (size
&& used
&& size
> DICT_HT_INITIAL_SIZE
&&
962 (used
*100/size
< REDIS_HT_MINFILL
));
965 /* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
966 * we resize the hash table to save memory */
967 static void tryResizeHashTables(void) {
970 for (j
= 0; j
< server
.dbnum
; j
++) {
971 if (htNeedsResize(server
.db
[j
].dict
)) {
972 redisLog(REDIS_DEBUG
,"The hash table %d is too sparse, resize it...",j
);
973 dictResize(server
.db
[j
].dict
);
974 redisLog(REDIS_DEBUG
,"Hash table %d resized.",j
);
976 if (htNeedsResize(server
.db
[j
].expires
))
977 dictResize(server
.db
[j
].expires
);
981 /* A background saving child (BGSAVE) terminated its work. Handle this. */
982 void backgroundSaveDoneHandler(int statloc
) {
983 int exitcode
= WEXITSTATUS(statloc
);
984 int bysignal
= WIFSIGNALED(statloc
);
986 if (!bysignal
&& exitcode
== 0) {
987 redisLog(REDIS_NOTICE
,
988 "Background saving terminated with success");
990 server
.lastsave
= time(NULL
);
991 } else if (!bysignal
&& exitcode
!= 0) {
992 redisLog(REDIS_WARNING
, "Background saving error");
994 redisLog(REDIS_WARNING
,
995 "Background saving terminated by signal");
996 rdbRemoveTempFile(server
.bgsavechildpid
);
998 server
.bgsavechildpid
= -1;
999 /* Possibly there are slaves waiting for a BGSAVE in order to be served
1000 * (the first stage of SYNC is a bulk transfer of dump.rdb) */
1001 updateSlavesWaitingBgsave(exitcode
== 0 ? REDIS_OK
: REDIS_ERR
);
1004 /* A background append only file rewriting (BGREWRITEAOF) terminated its work.
1006 void backgroundRewriteDoneHandler(int statloc
) {
1007 int exitcode
= WEXITSTATUS(statloc
);
1008 int bysignal
= WIFSIGNALED(statloc
);
1010 if (!bysignal
&& exitcode
== 0) {
1014 redisLog(REDIS_NOTICE
,
1015 "Background append only file rewriting terminated with success");
1016 /* Now it's time to flush the differences accumulated by the parent */
1017 snprintf(tmpfile
,256,"temp-rewriteaof-bg-%d.aof", (int) server
.bgrewritechildpid
);
1018 fd
= open(tmpfile
,O_WRONLY
|O_APPEND
);
1020 redisLog(REDIS_WARNING
, "Not able to open the temp append only file produced by the child: %s", strerror(errno
));
1023 /* Flush our data... */
1024 if (write(fd
,server
.bgrewritebuf
,sdslen(server
.bgrewritebuf
)) !=
1025 (signed) sdslen(server
.bgrewritebuf
)) {
1026 redisLog(REDIS_WARNING
, "Error or short write trying to flush the parent diff of the append log file in the child temp file: %s", strerror(errno
));
1030 redisLog(REDIS_NOTICE
,"Parent diff flushed into the new append log file with success (%lu bytes)",sdslen(server
.bgrewritebuf
));
1031 /* Now our work is to rename the temp file into the stable file. And
1032 * switch the file descriptor used by the server for append only. */
1033 if (rename(tmpfile
,server
.appendfilename
) == -1) {
1034 redisLog(REDIS_WARNING
,"Can't rename the temp append only file into the stable one: %s", strerror(errno
));
1038 /* Mission completed... almost */
1039 redisLog(REDIS_NOTICE
,"Append only file successfully rewritten.");
1040 if (server
.appendfd
!= -1) {
1041 /* If append only is actually enabled... */
1042 close(server
.appendfd
);
1043 server
.appendfd
= fd
;
1045 server
.appendseldb
= -1; /* Make sure it will issue SELECT */
1046 redisLog(REDIS_NOTICE
,"The new append only file was selected for future appends.");
1048 /* If append only is disabled we just generate a dump in this
1049 * format. Why not? */
1052 } else if (!bysignal
&& exitcode
!= 0) {
1053 redisLog(REDIS_WARNING
, "Background append only file rewriting error");
1055 redisLog(REDIS_WARNING
,
1056 "Background append only file rewriting terminated by signal");
1059 sdsfree(server
.bgrewritebuf
);
1060 server
.bgrewritebuf
= sdsempty();
1061 aofRemoveTempFile(server
.bgrewritechildpid
);
1062 server
.bgrewritechildpid
= -1;
1065 static int serverCron(struct aeEventLoop
*eventLoop
, long long id
, void *clientData
) {
1066 int j
, loops
= server
.cronloops
++;
1067 REDIS_NOTUSED(eventLoop
);
1069 REDIS_NOTUSED(clientData
);
1071 /* We take a cached value of the unix time in the global state because
1072 * with virtual memory and aging there is to store the current time
1073 * in objects at every object access, and accuracy is not needed.
1074 * To access a global var is faster than calling time(NULL) */
1075 server
.unixtime
= time(NULL
);
1077 /* Update the global state with the amount of used memory */
1078 server
.usedmemory
= zmalloc_used_memory();
1080 /* Show some info about non-empty databases */
1081 for (j
= 0; j
< server
.dbnum
; j
++) {
1082 long long size
, used
, vkeys
;
1084 size
= dictSlots(server
.db
[j
].dict
);
1085 used
= dictSize(server
.db
[j
].dict
);
1086 vkeys
= dictSize(server
.db
[j
].expires
);
1087 if (!(loops
% 5) && (used
|| vkeys
)) {
1088 redisLog(REDIS_DEBUG
,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j
,used
,vkeys
,size
);
1089 /* dictPrintStats(server.dict); */
1093 /* We don't want to resize the hash tables while a bacground saving
1094 * is in progress: the saving child is created using fork() that is
1095 * implemented with a copy-on-write semantic in most modern systems, so
1096 * if we resize the HT while there is the saving child at work actually
1097 * a lot of memory movements in the parent will cause a lot of pages
1099 if (server
.bgsavechildpid
== -1) tryResizeHashTables();
1101 /* Show information about connected clients */
1103 redisLog(REDIS_DEBUG
,"%d clients connected (%d slaves), %zu bytes in use, %d shared objects",
1104 listLength(server
.clients
)-listLength(server
.slaves
),
1105 listLength(server
.slaves
),
1107 dictSize(server
.sharingpool
));
1110 /* Close connections of timedout clients */
1111 if ((server
.maxidletime
&& !(loops
% 10)) || server
.blockedclients
)
1112 closeTimedoutClients();
1114 /* Check if a background saving or AOF rewrite in progress terminated */
1115 if (server
.bgsavechildpid
!= -1 || server
.bgrewritechildpid
!= -1) {
1119 if ((pid
= wait3(&statloc
,WNOHANG
,NULL
)) != 0) {
1120 if (pid
== server
.bgsavechildpid
) {
1121 backgroundSaveDoneHandler(statloc
);
1123 backgroundRewriteDoneHandler(statloc
);
1127 /* If there is not a background saving in progress check if
1128 * we have to save now */
1129 time_t now
= time(NULL
);
1130 for (j
= 0; j
< server
.saveparamslen
; j
++) {
1131 struct saveparam
*sp
= server
.saveparams
+j
;
1133 if (server
.dirty
>= sp
->changes
&&
1134 now
-server
.lastsave
> sp
->seconds
) {
1135 redisLog(REDIS_NOTICE
,"%d changes in %d seconds. Saving...",
1136 sp
->changes
, sp
->seconds
);
1137 rdbSaveBackground(server
.dbfilename
);
1143 /* Try to expire a few timed out keys. The algorithm used is adaptive and
1144 * will use few CPU cycles if there are few expiring keys, otherwise
1145 * it will get more aggressive to avoid that too much memory is used by
1146 * keys that can be removed from the keyspace. */
1147 for (j
= 0; j
< server
.dbnum
; j
++) {
1149 redisDb
*db
= server
.db
+j
;
1151 /* Continue to expire if at the end of the cycle more than 25%
1152 * of the keys were expired. */
1154 int num
= dictSize(db
->expires
);
1155 time_t now
= time(NULL
);
1158 if (num
> REDIS_EXPIRELOOKUPS_PER_CRON
)
1159 num
= REDIS_EXPIRELOOKUPS_PER_CRON
;
1164 if ((de
= dictGetRandomKey(db
->expires
)) == NULL
) break;
1165 t
= (time_t) dictGetEntryVal(de
);
1167 deleteKey(db
,dictGetEntryKey(de
));
1171 } while (expired
> REDIS_EXPIRELOOKUPS_PER_CRON
/4);
1174 /* Check if we should connect to a MASTER */
1175 if (server
.replstate
== REDIS_REPL_CONNECT
) {
1176 redisLog(REDIS_NOTICE
,"Connecting to MASTER...");
1177 if (syncWithMaster() == REDIS_OK
) {
1178 redisLog(REDIS_NOTICE
,"MASTER <-> SLAVE sync succeeded");
1184 static void createSharedObjects(void) {
1185 shared
.crlf
= createObject(REDIS_STRING
,sdsnew("\r\n"));
1186 shared
.ok
= createObject(REDIS_STRING
,sdsnew("+OK\r\n"));
1187 shared
.err
= createObject(REDIS_STRING
,sdsnew("-ERR\r\n"));
1188 shared
.emptybulk
= createObject(REDIS_STRING
,sdsnew("$0\r\n\r\n"));
1189 shared
.czero
= createObject(REDIS_STRING
,sdsnew(":0\r\n"));
1190 shared
.cone
= createObject(REDIS_STRING
,sdsnew(":1\r\n"));
1191 shared
.nullbulk
= createObject(REDIS_STRING
,sdsnew("$-1\r\n"));
1192 shared
.nullmultibulk
= createObject(REDIS_STRING
,sdsnew("*-1\r\n"));
1193 shared
.emptymultibulk
= createObject(REDIS_STRING
,sdsnew("*0\r\n"));
1194 shared
.pong
= createObject(REDIS_STRING
,sdsnew("+PONG\r\n"));
1195 shared
.queued
= createObject(REDIS_STRING
,sdsnew("+QUEUED\r\n"));
1196 shared
.wrongtypeerr
= createObject(REDIS_STRING
,sdsnew(
1197 "-ERR Operation against a key holding the wrong kind of value\r\n"));
1198 shared
.nokeyerr
= createObject(REDIS_STRING
,sdsnew(
1199 "-ERR no such key\r\n"));
1200 shared
.syntaxerr
= createObject(REDIS_STRING
,sdsnew(
1201 "-ERR syntax error\r\n"));
1202 shared
.sameobjecterr
= createObject(REDIS_STRING
,sdsnew(
1203 "-ERR source and destination objects are the same\r\n"));
1204 shared
.outofrangeerr
= createObject(REDIS_STRING
,sdsnew(
1205 "-ERR index out of range\r\n"));
1206 shared
.space
= createObject(REDIS_STRING
,sdsnew(" "));
1207 shared
.colon
= createObject(REDIS_STRING
,sdsnew(":"));
1208 shared
.plus
= createObject(REDIS_STRING
,sdsnew("+"));
1209 shared
.select0
= createStringObject("select 0\r\n",10);
1210 shared
.select1
= createStringObject("select 1\r\n",10);
1211 shared
.select2
= createStringObject("select 2\r\n",10);
1212 shared
.select3
= createStringObject("select 3\r\n",10);
1213 shared
.select4
= createStringObject("select 4\r\n",10);
1214 shared
.select5
= createStringObject("select 5\r\n",10);
1215 shared
.select6
= createStringObject("select 6\r\n",10);
1216 shared
.select7
= createStringObject("select 7\r\n",10);
1217 shared
.select8
= createStringObject("select 8\r\n",10);
1218 shared
.select9
= createStringObject("select 9\r\n",10);
1221 static void appendServerSaveParams(time_t seconds
, int changes
) {
1222 server
.saveparams
= zrealloc(server
.saveparams
,sizeof(struct saveparam
)*(server
.saveparamslen
+1));
1223 server
.saveparams
[server
.saveparamslen
].seconds
= seconds
;
1224 server
.saveparams
[server
.saveparamslen
].changes
= changes
;
1225 server
.saveparamslen
++;
1228 static void resetServerSaveParams() {
1229 zfree(server
.saveparams
);
1230 server
.saveparams
= NULL
;
1231 server
.saveparamslen
= 0;
1234 static void initServerConfig() {
1235 server
.dbnum
= REDIS_DEFAULT_DBNUM
;
1236 server
.port
= REDIS_SERVERPORT
;
1237 server
.verbosity
= REDIS_DEBUG
;
1238 server
.maxidletime
= REDIS_MAXIDLETIME
;
1239 server
.saveparams
= NULL
;
1240 server
.logfile
= NULL
; /* NULL = log on standard output */
1241 server
.bindaddr
= NULL
;
1242 server
.glueoutputbuf
= 1;
1243 server
.daemonize
= 0;
1244 server
.appendonly
= 0;
1245 server
.appendfsync
= APPENDFSYNC_ALWAYS
;
1246 server
.lastfsync
= time(NULL
);
1247 server
.appendfd
= -1;
1248 server
.appendseldb
= -1; /* Make sure the first time will not match */
1249 server
.pidfile
= "/var/run/redis.pid";
1250 server
.dbfilename
= "dump.rdb";
1251 server
.appendfilename
= "appendonly.aof";
1252 server
.requirepass
= NULL
;
1253 server
.shareobjects
= 0;
1254 server
.rdbcompression
= 1;
1255 server
.sharingpoolsize
= 1024;
1256 server
.maxclients
= 0;
1257 server
.blockedclients
= 0;
1258 server
.maxmemory
= 0;
1259 server
.vm_enabled
= 0;
1260 server
.vm_page_size
= 256; /* 256 bytes per page */
1261 server
.vm_pages
= 1024*1024*100; /* 104 millions of pages */
1262 server
.vm_max_memory
= 1024LL*1024*1024*1; /* 1 GB of RAM */
1264 resetServerSaveParams();
1266 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
1267 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
1268 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1269 /* Replication related */
1271 server
.masterauth
= NULL
;
1272 server
.masterhost
= NULL
;
1273 server
.masterport
= 6379;
1274 server
.master
= NULL
;
1275 server
.replstate
= REDIS_REPL_NONE
;
1277 /* Double constants initialization */
1279 R_PosInf
= 1.0/R_Zero
;
1280 R_NegInf
= -1.0/R_Zero
;
1281 R_Nan
= R_Zero
/R_Zero
;
1284 static void initServer() {
1287 signal(SIGHUP
, SIG_IGN
);
1288 signal(SIGPIPE
, SIG_IGN
);
1289 setupSigSegvAction();
1291 server
.clients
= listCreate();
1292 server
.slaves
= listCreate();
1293 server
.monitors
= listCreate();
1294 server
.objfreelist
= listCreate();
1295 createSharedObjects();
1296 server
.el
= aeCreateEventLoop();
1297 server
.db
= zmalloc(sizeof(redisDb
)*server
.dbnum
);
1298 server
.sharingpool
= dictCreate(&setDictType
,NULL
);
1299 server
.fd
= anetTcpServer(server
.neterr
, server
.port
, server
.bindaddr
);
1300 if (server
.fd
== -1) {
1301 redisLog(REDIS_WARNING
, "Opening TCP port: %s", server
.neterr
);
1304 for (j
= 0; j
< server
.dbnum
; j
++) {
1305 server
.db
[j
].dict
= dictCreate(&hashDictType
,NULL
);
1306 server
.db
[j
].expires
= dictCreate(&setDictType
,NULL
);
1307 server
.db
[j
].blockingkeys
= dictCreate(&keylistDictType
,NULL
);
1308 server
.db
[j
].id
= j
;
1310 server
.cronloops
= 0;
1311 server
.bgsavechildpid
= -1;
1312 server
.bgrewritechildpid
= -1;
1313 server
.bgrewritebuf
= sdsempty();
1314 server
.lastsave
= time(NULL
);
1316 server
.usedmemory
= 0;
1317 server
.stat_numcommands
= 0;
1318 server
.stat_numconnections
= 0;
1319 server
.stat_starttime
= time(NULL
);
1320 server
.unixtime
= time(NULL
);
1321 aeCreateTimeEvent(server
.el
, 1, serverCron
, NULL
, NULL
);
1323 if (server
.appendonly
) {
1324 server
.appendfd
= open(server
.appendfilename
,O_WRONLY
|O_APPEND
|O_CREAT
,0644);
1325 if (server
.appendfd
== -1) {
1326 redisLog(REDIS_WARNING
, "Can't open the append-only file: %s",
1332 if (server
.vm_enabled
) vmInit();
1335 /* Empty the whole database */
1336 static long long emptyDb() {
1338 long long removed
= 0;
1340 for (j
= 0; j
< server
.dbnum
; j
++) {
1341 removed
+= dictSize(server
.db
[j
].dict
);
1342 dictEmpty(server
.db
[j
].dict
);
1343 dictEmpty(server
.db
[j
].expires
);
1348 static int yesnotoi(char *s
) {
1349 if (!strcasecmp(s
,"yes")) return 1;
1350 else if (!strcasecmp(s
,"no")) return 0;
1354 /* I agree, this is a very rudimental way to load a configuration...
1355 will improve later if the config gets more complex */
1356 static void loadServerConfig(char *filename
) {
1358 char buf
[REDIS_CONFIGLINE_MAX
+1], *err
= NULL
;
1362 if (filename
[0] == '-' && filename
[1] == '\0')
1365 if ((fp
= fopen(filename
,"r")) == NULL
) {
1366 redisLog(REDIS_WARNING
,"Fatal error, can't open config file");
1371 while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) {
1377 line
= sdstrim(line
," \t\r\n");
1379 /* Skip comments and blank lines*/
1380 if (line
[0] == '#' || line
[0] == '\0') {
1385 /* Split into arguments */
1386 argv
= sdssplitlen(line
,sdslen(line
)," ",1,&argc
);
1387 sdstolower(argv
[0]);
1389 /* Execute config directives */
1390 if (!strcasecmp(argv
[0],"timeout") && argc
== 2) {
1391 server
.maxidletime
= atoi(argv
[1]);
1392 if (server
.maxidletime
< 0) {
1393 err
= "Invalid timeout value"; goto loaderr
;
1395 } else if (!strcasecmp(argv
[0],"port") && argc
== 2) {
1396 server
.port
= atoi(argv
[1]);
1397 if (server
.port
< 1 || server
.port
> 65535) {
1398 err
= "Invalid port"; goto loaderr
;
1400 } else if (!strcasecmp(argv
[0],"bind") && argc
== 2) {
1401 server
.bindaddr
= zstrdup(argv
[1]);
1402 } else if (!strcasecmp(argv
[0],"save") && argc
== 3) {
1403 int seconds
= atoi(argv
[1]);
1404 int changes
= atoi(argv
[2]);
1405 if (seconds
< 1 || changes
< 0) {
1406 err
= "Invalid save parameters"; goto loaderr
;
1408 appendServerSaveParams(seconds
,changes
);
1409 } else if (!strcasecmp(argv
[0],"dir") && argc
== 2) {
1410 if (chdir(argv
[1]) == -1) {
1411 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s",
1412 argv
[1], strerror(errno
));
1415 } else if (!strcasecmp(argv
[0],"loglevel") && argc
== 2) {
1416 if (!strcasecmp(argv
[1],"debug")) server
.verbosity
= REDIS_DEBUG
;
1417 else if (!strcasecmp(argv
[1],"notice")) server
.verbosity
= REDIS_NOTICE
;
1418 else if (!strcasecmp(argv
[1],"warning")) server
.verbosity
= REDIS_WARNING
;
1420 err
= "Invalid log level. Must be one of debug, notice, warning";
1423 } else if (!strcasecmp(argv
[0],"logfile") && argc
== 2) {
1426 server
.logfile
= zstrdup(argv
[1]);
1427 if (!strcasecmp(server
.logfile
,"stdout")) {
1428 zfree(server
.logfile
);
1429 server
.logfile
= NULL
;
1431 if (server
.logfile
) {
1432 /* Test if we are able to open the file. The server will not
1433 * be able to abort just for this problem later... */
1434 logfp
= fopen(server
.logfile
,"a");
1435 if (logfp
== NULL
) {
1436 err
= sdscatprintf(sdsempty(),
1437 "Can't open the log file: %s", strerror(errno
));
1442 } else if (!strcasecmp(argv
[0],"databases") && argc
== 2) {
1443 server
.dbnum
= atoi(argv
[1]);
1444 if (server
.dbnum
< 1) {
1445 err
= "Invalid number of databases"; goto loaderr
;
1447 } else if (!strcasecmp(argv
[0],"maxclients") && argc
== 2) {
1448 server
.maxclients
= atoi(argv
[1]);
1449 } else if (!strcasecmp(argv
[0],"maxmemory") && argc
== 2) {
1450 server
.maxmemory
= strtoll(argv
[1], NULL
, 10);
1451 } else if (!strcasecmp(argv
[0],"slaveof") && argc
== 3) {
1452 server
.masterhost
= sdsnew(argv
[1]);
1453 server
.masterport
= atoi(argv
[2]);
1454 server
.replstate
= REDIS_REPL_CONNECT
;
1455 } else if (!strcasecmp(argv
[0],"masterauth") && argc
== 2) {
1456 server
.masterauth
= zstrdup(argv
[1]);
1457 } else if (!strcasecmp(argv
[0],"glueoutputbuf") && argc
== 2) {
1458 if ((server
.glueoutputbuf
= yesnotoi(argv
[1])) == -1) {
1459 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1461 } else if (!strcasecmp(argv
[0],"shareobjects") && argc
== 2) {
1462 if ((server
.shareobjects
= yesnotoi(argv
[1])) == -1) {
1463 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1465 } else if (!strcasecmp(argv
[0],"rdbcompression") && argc
== 2) {
1466 if ((server
.rdbcompression
= yesnotoi(argv
[1])) == -1) {
1467 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1469 } else if (!strcasecmp(argv
[0],"shareobjectspoolsize") && argc
== 2) {
1470 server
.sharingpoolsize
= atoi(argv
[1]);
1471 if (server
.sharingpoolsize
< 1) {
1472 err
= "invalid object sharing pool size"; goto loaderr
;
1474 } else if (!strcasecmp(argv
[0],"daemonize") && argc
== 2) {
1475 if ((server
.daemonize
= yesnotoi(argv
[1])) == -1) {
1476 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1478 } else if (!strcasecmp(argv
[0],"appendonly") && argc
== 2) {
1479 if ((server
.appendonly
= yesnotoi(argv
[1])) == -1) {
1480 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1482 } else if (!strcasecmp(argv
[0],"appendfsync") && argc
== 2) {
1483 if (!strcasecmp(argv
[1],"no")) {
1484 server
.appendfsync
= APPENDFSYNC_NO
;
1485 } else if (!strcasecmp(argv
[1],"always")) {
1486 server
.appendfsync
= APPENDFSYNC_ALWAYS
;
1487 } else if (!strcasecmp(argv
[1],"everysec")) {
1488 server
.appendfsync
= APPENDFSYNC_EVERYSEC
;
1490 err
= "argument must be 'no', 'always' or 'everysec'";
1493 } else if (!strcasecmp(argv
[0],"requirepass") && argc
== 2) {
1494 server
.requirepass
= zstrdup(argv
[1]);
1495 } else if (!strcasecmp(argv
[0],"pidfile") && argc
== 2) {
1496 server
.pidfile
= zstrdup(argv
[1]);
1497 } else if (!strcasecmp(argv
[0],"dbfilename") && argc
== 2) {
1498 server
.dbfilename
= zstrdup(argv
[1]);
1499 } else if (!strcasecmp(argv
[0],"vm-enabled") && argc
== 2) {
1500 if ((server
.vm_enabled
= yesnotoi(argv
[1])) == -1) {
1501 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1504 err
= "Bad directive or wrong number of arguments"; goto loaderr
;
1506 for (j
= 0; j
< argc
; j
++)
1511 if (fp
!= stdin
) fclose(fp
);
1515 fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n");
1516 fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
);
1517 fprintf(stderr
, ">>> '%s'\n", line
);
1518 fprintf(stderr
, "%s\n", err
);
1522 static void freeClientArgv(redisClient
*c
) {
1525 for (j
= 0; j
< c
->argc
; j
++)
1526 decrRefCount(c
->argv
[j
]);
1527 for (j
= 0; j
< c
->mbargc
; j
++)
1528 decrRefCount(c
->mbargv
[j
]);
1533 static void freeClient(redisClient
*c
) {
1536 /* Note that if the client we are freeing is blocked into a blocking
1537 * call, we have to set querybuf to NULL *before* to call unblockClient()
1538 * to avoid processInputBuffer() will get called. Also it is important
1539 * to remove the file events after this, because this call adds
1540 * the READABLE event. */
1541 sdsfree(c
->querybuf
);
1543 if (c
->flags
& REDIS_BLOCKED
)
1546 aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
);
1547 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1548 listRelease(c
->reply
);
1551 ln
= listSearchKey(server
.clients
,c
);
1552 redisAssert(ln
!= NULL
);
1553 listDelNode(server
.clients
,ln
);
1554 if (c
->flags
& REDIS_SLAVE
) {
1555 if (c
->replstate
== REDIS_REPL_SEND_BULK
&& c
->repldbfd
!= -1)
1557 list
*l
= (c
->flags
& REDIS_MONITOR
) ? server
.monitors
: server
.slaves
;
1558 ln
= listSearchKey(l
,c
);
1559 redisAssert(ln
!= NULL
);
1562 if (c
->flags
& REDIS_MASTER
) {
1563 server
.master
= NULL
;
1564 server
.replstate
= REDIS_REPL_CONNECT
;
1568 freeClientMultiState(c
);
1572 #define GLUEREPLY_UP_TO (1024)
1573 static void glueReplyBuffersIfNeeded(redisClient
*c
) {
1575 char buf
[GLUEREPLY_UP_TO
];
1579 listRewind(c
->reply
);
1580 while((ln
= listYield(c
->reply
))) {
1584 objlen
= sdslen(o
->ptr
);
1585 if (copylen
+ objlen
<= GLUEREPLY_UP_TO
) {
1586 memcpy(buf
+copylen
,o
->ptr
,objlen
);
1588 listDelNode(c
->reply
,ln
);
1590 if (copylen
== 0) return;
1594 /* Now the output buffer is empty, add the new single element */
1595 o
= createObject(REDIS_STRING
,sdsnewlen(buf
,copylen
));
1596 listAddNodeHead(c
->reply
,o
);
1599 static void sendReplyToClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1600 redisClient
*c
= privdata
;
1601 int nwritten
= 0, totwritten
= 0, objlen
;
1604 REDIS_NOTUSED(mask
);
1606 /* Use writev() if we have enough buffers to send */
1607 if (!server
.glueoutputbuf
&&
1608 listLength(c
->reply
) > REDIS_WRITEV_THRESHOLD
&&
1609 !(c
->flags
& REDIS_MASTER
))
1611 sendReplyToClientWritev(el
, fd
, privdata
, mask
);
1615 while(listLength(c
->reply
)) {
1616 if (server
.glueoutputbuf
&& listLength(c
->reply
) > 1)
1617 glueReplyBuffersIfNeeded(c
);
1619 o
= listNodeValue(listFirst(c
->reply
));
1620 objlen
= sdslen(o
->ptr
);
1623 listDelNode(c
->reply
,listFirst(c
->reply
));
1627 if (c
->flags
& REDIS_MASTER
) {
1628 /* Don't reply to a master */
1629 nwritten
= objlen
- c
->sentlen
;
1631 nwritten
= write(fd
, ((char*)o
->ptr
)+c
->sentlen
, objlen
- c
->sentlen
);
1632 if (nwritten
<= 0) break;
1634 c
->sentlen
+= nwritten
;
1635 totwritten
+= nwritten
;
1636 /* If we fully sent the object on head go to the next one */
1637 if (c
->sentlen
== objlen
) {
1638 listDelNode(c
->reply
,listFirst(c
->reply
));
1641 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
1642 * bytes, in a single threaded server it's a good idea to serve
1643 * other clients as well, even if a very large request comes from
1644 * super fast link that is always able to accept data (in real world
1645 * scenario think about 'KEYS *' against the loopback interfae) */
1646 if (totwritten
> REDIS_MAX_WRITE_PER_EVENT
) break;
1648 if (nwritten
== -1) {
1649 if (errno
== EAGAIN
) {
1652 redisLog(REDIS_DEBUG
,
1653 "Error writing to client: %s", strerror(errno
));
1658 if (totwritten
> 0) c
->lastinteraction
= time(NULL
);
1659 if (listLength(c
->reply
) == 0) {
1661 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1665 static void sendReplyToClientWritev(aeEventLoop
*el
, int fd
, void *privdata
, int mask
)
1667 redisClient
*c
= privdata
;
1668 int nwritten
= 0, totwritten
= 0, objlen
, willwrite
;
1670 struct iovec iov
[REDIS_WRITEV_IOVEC_COUNT
];
1671 int offset
, ion
= 0;
1673 REDIS_NOTUSED(mask
);
1676 while (listLength(c
->reply
)) {
1677 offset
= c
->sentlen
;
1681 /* fill-in the iov[] array */
1682 for(node
= listFirst(c
->reply
); node
; node
= listNextNode(node
)) {
1683 o
= listNodeValue(node
);
1684 objlen
= sdslen(o
->ptr
);
1686 if (totwritten
+ objlen
- offset
> REDIS_MAX_WRITE_PER_EVENT
)
1689 if(ion
== REDIS_WRITEV_IOVEC_COUNT
)
1690 break; /* no more iovecs */
1692 iov
[ion
].iov_base
= ((char*)o
->ptr
) + offset
;
1693 iov
[ion
].iov_len
= objlen
- offset
;
1694 willwrite
+= objlen
- offset
;
1695 offset
= 0; /* just for the first item */
1702 /* write all collected blocks at once */
1703 if((nwritten
= writev(fd
, iov
, ion
)) < 0) {
1704 if (errno
!= EAGAIN
) {
1705 redisLog(REDIS_DEBUG
,
1706 "Error writing to client: %s", strerror(errno
));
1713 totwritten
+= nwritten
;
1714 offset
= c
->sentlen
;
1716 /* remove written robjs from c->reply */
1717 while (nwritten
&& listLength(c
->reply
)) {
1718 o
= listNodeValue(listFirst(c
->reply
));
1719 objlen
= sdslen(o
->ptr
);
1721 if(nwritten
>= objlen
- offset
) {
1722 listDelNode(c
->reply
, listFirst(c
->reply
));
1723 nwritten
-= objlen
- offset
;
1727 c
->sentlen
+= nwritten
;
1735 c
->lastinteraction
= time(NULL
);
1737 if (listLength(c
->reply
) == 0) {
1739 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1743 static struct redisCommand
*lookupCommand(char *name
) {
1745 while(cmdTable
[j
].name
!= NULL
) {
1746 if (!strcasecmp(name
,cmdTable
[j
].name
)) return &cmdTable
[j
];
1752 /* resetClient prepare the client to process the next command */
1753 static void resetClient(redisClient
*c
) {
1759 /* Call() is the core of Redis execution of a command */
1760 static void call(redisClient
*c
, struct redisCommand
*cmd
) {
1763 dirty
= server
.dirty
;
1765 if (server
.appendonly
&& server
.dirty
-dirty
)
1766 feedAppendOnlyFile(cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1767 if (server
.dirty
-dirty
&& listLength(server
.slaves
))
1768 replicationFeedSlaves(server
.slaves
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1769 if (listLength(server
.monitors
))
1770 replicationFeedSlaves(server
.monitors
,cmd
,c
->db
->id
,c
->argv
,c
->argc
);
1771 server
.stat_numcommands
++;
1774 /* If this function gets called we already read a whole
1775 * command, argments are in the client argv/argc fields.
1776 * processCommand() execute the command or prepare the
1777 * server for a bulk read from the client.
1779 * If 1 is returned the client is still alive and valid and
1780 * and other operations can be performed by the caller. Otherwise
1781 * if 0 is returned the client was destroied (i.e. after QUIT). */
1782 static int processCommand(redisClient
*c
) {
1783 struct redisCommand
*cmd
;
1785 /* Free some memory if needed (maxmemory setting) */
1786 if (server
.maxmemory
) freeMemoryIfNeeded();
1788 /* Handle the multi bulk command type. This is an alternative protocol
1789 * supported by Redis in order to receive commands that are composed of
1790 * multiple binary-safe "bulk" arguments. The latency of processing is
1791 * a bit higher but this allows things like multi-sets, so if this
1792 * protocol is used only for MSET and similar commands this is a big win. */
1793 if (c
->multibulk
== 0 && c
->argc
== 1 && ((char*)(c
->argv
[0]->ptr
))[0] == '*') {
1794 c
->multibulk
= atoi(((char*)c
->argv
[0]->ptr
)+1);
1795 if (c
->multibulk
<= 0) {
1799 decrRefCount(c
->argv
[c
->argc
-1]);
1803 } else if (c
->multibulk
) {
1804 if (c
->bulklen
== -1) {
1805 if (((char*)c
->argv
[0]->ptr
)[0] != '$') {
1806 addReplySds(c
,sdsnew("-ERR multi bulk protocol error\r\n"));
1810 int bulklen
= atoi(((char*)c
->argv
[0]->ptr
)+1);
1811 decrRefCount(c
->argv
[0]);
1812 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
1814 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
1819 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
1823 c
->mbargv
= zrealloc(c
->mbargv
,(sizeof(robj
*))*(c
->mbargc
+1));
1824 c
->mbargv
[c
->mbargc
] = c
->argv
[0];
1828 if (c
->multibulk
== 0) {
1832 /* Here we need to swap the multi-bulk argc/argv with the
1833 * normal argc/argv of the client structure. */
1835 c
->argv
= c
->mbargv
;
1836 c
->mbargv
= auxargv
;
1839 c
->argc
= c
->mbargc
;
1840 c
->mbargc
= auxargc
;
1842 /* We need to set bulklen to something different than -1
1843 * in order for the code below to process the command without
1844 * to try to read the last argument of a bulk command as
1845 * a special argument. */
1847 /* continue below and process the command */
1854 /* -- end of multi bulk commands processing -- */
1856 /* The QUIT command is handled as a special case. Normal command
1857 * procs are unable to close the client connection safely */
1858 if (!strcasecmp(c
->argv
[0]->ptr
,"quit")) {
1862 cmd
= lookupCommand(c
->argv
[0]->ptr
);
1865 sdscatprintf(sdsempty(), "-ERR unknown command '%s'\r\n",
1866 (char*)c
->argv
[0]->ptr
));
1869 } else if ((cmd
->arity
> 0 && cmd
->arity
!= c
->argc
) ||
1870 (c
->argc
< -cmd
->arity
)) {
1872 sdscatprintf(sdsempty(),
1873 "-ERR wrong number of arguments for '%s' command\r\n",
1877 } else if (server
.maxmemory
&& cmd
->flags
& REDIS_CMD_DENYOOM
&& zmalloc_used_memory() > server
.maxmemory
) {
1878 addReplySds(c
,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
1881 } else if (cmd
->flags
& REDIS_CMD_BULK
&& c
->bulklen
== -1) {
1882 int bulklen
= atoi(c
->argv
[c
->argc
-1]->ptr
);
1884 decrRefCount(c
->argv
[c
->argc
-1]);
1885 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
1887 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
1892 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
1893 /* It is possible that the bulk read is already in the
1894 * buffer. Check this condition and handle it accordingly.
1895 * This is just a fast path, alternative to call processInputBuffer().
1896 * It's a good idea since the code is small and this condition
1897 * happens most of the times. */
1898 if ((signed)sdslen(c
->querybuf
) >= c
->bulklen
) {
1899 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
1901 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
1906 /* Let's try to share objects on the command arguments vector */
1907 if (server
.shareobjects
) {
1909 for(j
= 1; j
< c
->argc
; j
++)
1910 c
->argv
[j
] = tryObjectSharing(c
->argv
[j
]);
1912 /* Let's try to encode the bulk object to save space. */
1913 if (cmd
->flags
& REDIS_CMD_BULK
)
1914 tryObjectEncoding(c
->argv
[c
->argc
-1]);
1916 /* Check if the user is authenticated */
1917 if (server
.requirepass
&& !c
->authenticated
&& cmd
->proc
!= authCommand
) {
1918 addReplySds(c
,sdsnew("-ERR operation not permitted\r\n"));
1923 /* Exec the command */
1924 if (c
->flags
& REDIS_MULTI
&& cmd
->proc
!= execCommand
) {
1925 queueMultiCommand(c
,cmd
);
1926 addReply(c
,shared
.queued
);
1931 /* Prepare the client for the next command */
1932 if (c
->flags
& REDIS_CLOSE
) {
1940 static void replicationFeedSlaves(list
*slaves
, struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
) {
1944 /* (args*2)+1 is enough room for args, spaces, newlines */
1945 robj
*static_outv
[REDIS_STATIC_ARGS
*2+1];
1947 if (argc
<= REDIS_STATIC_ARGS
) {
1950 outv
= zmalloc(sizeof(robj
*)*(argc
*2+1));
1953 for (j
= 0; j
< argc
; j
++) {
1954 if (j
!= 0) outv
[outc
++] = shared
.space
;
1955 if ((cmd
->flags
& REDIS_CMD_BULK
) && j
== argc
-1) {
1958 lenobj
= createObject(REDIS_STRING
,
1959 sdscatprintf(sdsempty(),"%lu\r\n",
1960 (unsigned long) stringObjectLen(argv
[j
])));
1961 lenobj
->refcount
= 0;
1962 outv
[outc
++] = lenobj
;
1964 outv
[outc
++] = argv
[j
];
1966 outv
[outc
++] = shared
.crlf
;
1968 /* Increment all the refcounts at start and decrement at end in order to
1969 * be sure to free objects if there is no slave in a replication state
1970 * able to be feed with commands */
1971 for (j
= 0; j
< outc
; j
++) incrRefCount(outv
[j
]);
1973 while((ln
= listYield(slaves
))) {
1974 redisClient
*slave
= ln
->value
;
1976 /* Don't feed slaves that are still waiting for BGSAVE to start */
1977 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) continue;
1979 /* Feed all the other slaves, MONITORs and so on */
1980 if (slave
->slaveseldb
!= dictid
) {
1984 case 0: selectcmd
= shared
.select0
; break;
1985 case 1: selectcmd
= shared
.select1
; break;
1986 case 2: selectcmd
= shared
.select2
; break;
1987 case 3: selectcmd
= shared
.select3
; break;
1988 case 4: selectcmd
= shared
.select4
; break;
1989 case 5: selectcmd
= shared
.select5
; break;
1990 case 6: selectcmd
= shared
.select6
; break;
1991 case 7: selectcmd
= shared
.select7
; break;
1992 case 8: selectcmd
= shared
.select8
; break;
1993 case 9: selectcmd
= shared
.select9
; break;
1995 selectcmd
= createObject(REDIS_STRING
,
1996 sdscatprintf(sdsempty(),"select %d\r\n",dictid
));
1997 selectcmd
->refcount
= 0;
2000 addReply(slave
,selectcmd
);
2001 slave
->slaveseldb
= dictid
;
2003 for (j
= 0; j
< outc
; j
++) addReply(slave
,outv
[j
]);
2005 for (j
= 0; j
< outc
; j
++) decrRefCount(outv
[j
]);
2006 if (outv
!= static_outv
) zfree(outv
);
2009 static void processInputBuffer(redisClient
*c
) {
2011 /* Before to process the input buffer, make sure the client is not
2012 * waitig for a blocking operation such as BLPOP. Note that the first
2013 * iteration the client is never blocked, otherwise the processInputBuffer
2014 * would not be called at all, but after the execution of the first commands
2015 * in the input buffer the client may be blocked, and the "goto again"
2016 * will try to reiterate. The following line will make it return asap. */
2017 if (c
->flags
& REDIS_BLOCKED
) return;
2018 if (c
->bulklen
== -1) {
2019 /* Read the first line of the query */
2020 char *p
= strchr(c
->querybuf
,'\n');
2027 query
= c
->querybuf
;
2028 c
->querybuf
= sdsempty();
2029 querylen
= 1+(p
-(query
));
2030 if (sdslen(query
) > querylen
) {
2031 /* leave data after the first line of the query in the buffer */
2032 c
->querybuf
= sdscatlen(c
->querybuf
,query
+querylen
,sdslen(query
)-querylen
);
2034 *p
= '\0'; /* remove "\n" */
2035 if (*(p
-1) == '\r') *(p
-1) = '\0'; /* and "\r" if any */
2036 sdsupdatelen(query
);
2038 /* Now we can split the query in arguments */
2039 argv
= sdssplitlen(query
,sdslen(query
)," ",1,&argc
);
2042 if (c
->argv
) zfree(c
->argv
);
2043 c
->argv
= zmalloc(sizeof(robj
*)*argc
);
2045 for (j
= 0; j
< argc
; j
++) {
2046 if (sdslen(argv
[j
])) {
2047 c
->argv
[c
->argc
] = createObject(REDIS_STRING
,argv
[j
]);
2055 /* Execute the command. If the client is still valid
2056 * after processCommand() return and there is something
2057 * on the query buffer try to process the next command. */
2058 if (processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
2060 /* Nothing to process, argc == 0. Just process the query
2061 * buffer if it's not empty or return to the caller */
2062 if (sdslen(c
->querybuf
)) goto again
;
2065 } else if (sdslen(c
->querybuf
) >= REDIS_REQUEST_MAX_SIZE
) {
2066 redisLog(REDIS_DEBUG
, "Client protocol error");
2071 /* Bulk read handling. Note that if we are at this point
2072 the client already sent a command terminated with a newline,
2073 we are reading the bulk data that is actually the last
2074 argument of the command. */
2075 int qbl
= sdslen(c
->querybuf
);
2077 if (c
->bulklen
<= qbl
) {
2078 /* Copy everything but the final CRLF as final argument */
2079 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
2081 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
2082 /* Process the command. If the client is still valid after
2083 * the processing and there is more data in the buffer
2084 * try to parse it. */
2085 if (processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
2091 static void readQueryFromClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
2092 redisClient
*c
= (redisClient
*) privdata
;
2093 char buf
[REDIS_IOBUF_LEN
];
2096 REDIS_NOTUSED(mask
);
2098 nread
= read(fd
, buf
, REDIS_IOBUF_LEN
);
2100 if (errno
== EAGAIN
) {
2103 redisLog(REDIS_DEBUG
, "Reading from client: %s",strerror(errno
));
2107 } else if (nread
== 0) {
2108 redisLog(REDIS_DEBUG
, "Client closed connection");
2113 c
->querybuf
= sdscatlen(c
->querybuf
, buf
, nread
);
2114 c
->lastinteraction
= time(NULL
);
2118 processInputBuffer(c
);
2121 static int selectDb(redisClient
*c
, int id
) {
2122 if (id
< 0 || id
>= server
.dbnum
)
2124 c
->db
= &server
.db
[id
];
2128 static void *dupClientReplyValue(void *o
) {
2129 incrRefCount((robj
*)o
);
2133 static redisClient
*createClient(int fd
) {
2134 redisClient
*c
= zmalloc(sizeof(*c
));
2136 anetNonBlock(NULL
,fd
);
2137 anetTcpNoDelay(NULL
,fd
);
2138 if (!c
) return NULL
;
2141 c
->querybuf
= sdsempty();
2150 c
->lastinteraction
= time(NULL
);
2151 c
->authenticated
= 0;
2152 c
->replstate
= REDIS_REPL_NONE
;
2153 c
->reply
= listCreate();
2154 c
->blockingkeys
= NULL
;
2155 c
->blockingkeysnum
= 0;
2156 listSetFreeMethod(c
->reply
,decrRefCount
);
2157 listSetDupMethod(c
->reply
,dupClientReplyValue
);
2158 if (aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
,
2159 readQueryFromClient
, c
) == AE_ERR
) {
2163 listAddNodeTail(server
.clients
,c
);
2164 initClientMultiState(c
);
2168 static void addReply(redisClient
*c
, robj
*obj
) {
2169 if (listLength(c
->reply
) == 0 &&
2170 (c
->replstate
== REDIS_REPL_NONE
||
2171 c
->replstate
== REDIS_REPL_ONLINE
) &&
2172 aeCreateFileEvent(server
.el
, c
->fd
, AE_WRITABLE
,
2173 sendReplyToClient
, c
) == AE_ERR
) return;
2174 listAddNodeTail(c
->reply
,getDecodedObject(obj
));
2177 static void addReplySds(redisClient
*c
, sds s
) {
2178 robj
*o
= createObject(REDIS_STRING
,s
);
2183 static void addReplyDouble(redisClient
*c
, double d
) {
2186 snprintf(buf
,sizeof(buf
),"%.17g",d
);
2187 addReplySds(c
,sdscatprintf(sdsempty(),"$%lu\r\n%s\r\n",
2188 (unsigned long) strlen(buf
),buf
));
2191 static void addReplyBulkLen(redisClient
*c
, robj
*obj
) {
2194 if (obj
->encoding
== REDIS_ENCODING_RAW
) {
2195 len
= sdslen(obj
->ptr
);
2197 long n
= (long)obj
->ptr
;
2199 /* Compute how many bytes will take this integer as a radix 10 string */
2205 while((n
= n
/10) != 0) {
2209 addReplySds(c
,sdscatprintf(sdsempty(),"$%lu\r\n",(unsigned long)len
));
2212 static void acceptHandler(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
2217 REDIS_NOTUSED(mask
);
2218 REDIS_NOTUSED(privdata
);
2220 cfd
= anetAccept(server
.neterr
, fd
, cip
, &cport
);
2221 if (cfd
== AE_ERR
) {
2222 redisLog(REDIS_DEBUG
,"Accepting client connection: %s", server
.neterr
);
2225 redisLog(REDIS_DEBUG
,"Accepted %s:%d", cip
, cport
);
2226 if ((c
= createClient(cfd
)) == NULL
) {
2227 redisLog(REDIS_WARNING
,"Error allocating resoures for the client");
2228 close(cfd
); /* May be already closed, just ingore errors */
2231 /* If maxclient directive is set and this is one client more... close the
2232 * connection. Note that we create the client instead to check before
2233 * for this condition, since now the socket is already set in nonblocking
2234 * mode and we can send an error for free using the Kernel I/O */
2235 if (server
.maxclients
&& listLength(server
.clients
) > server
.maxclients
) {
2236 char *err
= "-ERR max number of clients reached\r\n";
2238 /* That's a best effort error message, don't check write errors */
2239 if (write(c
->fd
,err
,strlen(err
)) == -1) {
2240 /* Nothing to do, Just to avoid the warning... */
2245 server
.stat_numconnections
++;
2248 /* ======================= Redis objects implementation ===================== */
2250 static robj
*createObject(int type
, void *ptr
) {
2253 if (listLength(server
.objfreelist
)) {
2254 listNode
*head
= listFirst(server
.objfreelist
);
2255 o
= listNodeValue(head
);
2256 listDelNode(server
.objfreelist
,head
);
2258 if (server
.vm_enabled
) {
2259 o
= zmalloc(sizeof(*o
));
2261 o
= zmalloc(sizeof(*o
)-sizeof(struct redisObjectVM
));
2265 o
->encoding
= REDIS_ENCODING_RAW
;
2268 if (server
.vm_enabled
) {
2269 o
->vm
.atime
= server
.unixtime
;
2270 o
->storage
= REDIS_VM_MEMORY
;
2275 static robj
*createStringObject(char *ptr
, size_t len
) {
2276 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
2279 static robj
*createListObject(void) {
2280 list
*l
= listCreate();
2282 listSetFreeMethod(l
,decrRefCount
);
2283 return createObject(REDIS_LIST
,l
);
2286 static robj
*createSetObject(void) {
2287 dict
*d
= dictCreate(&setDictType
,NULL
);
2288 return createObject(REDIS_SET
,d
);
2291 static robj
*createZsetObject(void) {
2292 zset
*zs
= zmalloc(sizeof(*zs
));
2294 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
2295 zs
->zsl
= zslCreate();
2296 return createObject(REDIS_ZSET
,zs
);
2299 static void freeStringObject(robj
*o
) {
2300 if (o
->encoding
== REDIS_ENCODING_RAW
) {
2305 static void freeListObject(robj
*o
) {
2306 listRelease((list
*) o
->ptr
);
2309 static void freeSetObject(robj
*o
) {
2310 dictRelease((dict
*) o
->ptr
);
2313 static void freeZsetObject(robj
*o
) {
2316 dictRelease(zs
->dict
);
2321 static void freeHashObject(robj
*o
) {
2322 dictRelease((dict
*) o
->ptr
);
2325 static void incrRefCount(robj
*o
) {
2326 assert(!server
.vm_enabled
|| o
->storage
== REDIS_VM_MEMORY
);
2330 static void decrRefCount(void *obj
) {
2333 /* REDIS_VM_SWAPPED */
2334 if (server
.vm_enabled
&& o
->storage
== REDIS_VM_SWAPPED
) {
2335 assert(o
->refcount
== 1);
2336 assert(o
->type
== REDIS_STRING
);
2337 freeStringObject(o
);
2338 vmMarkPagesFree(o
->vm
.page
,o
->vm
.usedpages
);
2339 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
2340 !listAddNodeHead(server
.objfreelist
,o
))
2344 /* REDIS_VM_MEMORY */
2345 if (--(o
->refcount
) == 0) {
2347 case REDIS_STRING
: freeStringObject(o
); break;
2348 case REDIS_LIST
: freeListObject(o
); break;
2349 case REDIS_SET
: freeSetObject(o
); break;
2350 case REDIS_ZSET
: freeZsetObject(o
); break;
2351 case REDIS_HASH
: freeHashObject(o
); break;
2352 default: redisAssert(0 != 0); break;
2354 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
2355 !listAddNodeHead(server
.objfreelist
,o
))
2360 static robj
*lookupKey(redisDb
*db
, robj
*key
) {
2361 dictEntry
*de
= dictFind(db
->dict
,key
);
2363 robj
*key
= dictGetEntryKey(de
);
2364 robj
*val
= dictGetEntryVal(de
);
2366 if (server
.vm_enabled
) {
2367 if (key
->storage
== REDIS_VM_MEMORY
) {
2368 /* Update the access time of the key for the aging algorithm. */
2369 key
->vm
.atime
= server
.unixtime
;
2371 /* Our value was swapped on disk. Bring it at home. */
2372 assert(val
== NULL
);
2373 val
= vmLoadObject(key
);
2374 dictGetEntryVal(de
) = val
;
2383 static robj
*lookupKeyRead(redisDb
*db
, robj
*key
) {
2384 expireIfNeeded(db
,key
);
2385 return lookupKey(db
,key
);
2388 static robj
*lookupKeyWrite(redisDb
*db
, robj
*key
) {
2389 deleteIfVolatile(db
,key
);
2390 return lookupKey(db
,key
);
2393 static int deleteKey(redisDb
*db
, robj
*key
) {
2396 /* We need to protect key from destruction: after the first dictDelete()
2397 * it may happen that 'key' is no longer valid if we don't increment
2398 * it's count. This may happen when we get the object reference directly
2399 * from the hash table with dictRandomKey() or dict iterators */
2401 if (dictSize(db
->expires
)) dictDelete(db
->expires
,key
);
2402 retval
= dictDelete(db
->dict
,key
);
2405 return retval
== DICT_OK
;
2408 /* Try to share an object against the shared objects pool */
2409 static robj
*tryObjectSharing(robj
*o
) {
2410 struct dictEntry
*de
;
2413 if (o
== NULL
|| server
.shareobjects
== 0) return o
;
2415 redisAssert(o
->type
== REDIS_STRING
);
2416 de
= dictFind(server
.sharingpool
,o
);
2418 robj
*shared
= dictGetEntryKey(de
);
2420 c
= ((unsigned long) dictGetEntryVal(de
))+1;
2421 dictGetEntryVal(de
) = (void*) c
;
2422 incrRefCount(shared
);
2426 /* Here we are using a stream algorihtm: Every time an object is
2427 * shared we increment its count, everytime there is a miss we
2428 * recrement the counter of a random object. If this object reaches
2429 * zero we remove the object and put the current object instead. */
2430 if (dictSize(server
.sharingpool
) >=
2431 server
.sharingpoolsize
) {
2432 de
= dictGetRandomKey(server
.sharingpool
);
2433 redisAssert(de
!= NULL
);
2434 c
= ((unsigned long) dictGetEntryVal(de
))-1;
2435 dictGetEntryVal(de
) = (void*) c
;
2437 dictDelete(server
.sharingpool
,de
->key
);
2440 c
= 0; /* If the pool is empty we want to add this object */
2445 retval
= dictAdd(server
.sharingpool
,o
,(void*)1);
2446 redisAssert(retval
== DICT_OK
);
2453 /* Check if the nul-terminated string 's' can be represented by a long
2454 * (that is, is a number that fits into long without any other space or
2455 * character before or after the digits).
2457 * If so, the function returns REDIS_OK and *longval is set to the value
2458 * of the number. Otherwise REDIS_ERR is returned */
2459 static int isStringRepresentableAsLong(sds s
, long *longval
) {
2460 char buf
[32], *endptr
;
2464 value
= strtol(s
, &endptr
, 10);
2465 if (endptr
[0] != '\0') return REDIS_ERR
;
2466 slen
= snprintf(buf
,32,"%ld",value
);
2468 /* If the number converted back into a string is not identical
2469 * then it's not possible to encode the string as integer */
2470 if (sdslen(s
) != (unsigned)slen
|| memcmp(buf
,s
,slen
)) return REDIS_ERR
;
2471 if (longval
) *longval
= value
;
2475 /* Try to encode a string object in order to save space */
2476 static int tryObjectEncoding(robj
*o
) {
2480 if (o
->encoding
!= REDIS_ENCODING_RAW
)
2481 return REDIS_ERR
; /* Already encoded */
2483 /* It's not save to encode shared objects: shared objects can be shared
2484 * everywhere in the "object space" of Redis. Encoded objects can only
2485 * appear as "values" (and not, for instance, as keys) */
2486 if (o
->refcount
> 1) return REDIS_ERR
;
2488 /* Currently we try to encode only strings */
2489 redisAssert(o
->type
== REDIS_STRING
);
2491 /* Check if we can represent this string as a long integer */
2492 if (isStringRepresentableAsLong(s
,&value
) == REDIS_ERR
) return REDIS_ERR
;
2494 /* Ok, this object can be encoded */
2495 o
->encoding
= REDIS_ENCODING_INT
;
2497 o
->ptr
= (void*) value
;
2501 /* Get a decoded version of an encoded object (returned as a new object).
2502 * If the object is already raw-encoded just increment the ref count. */
2503 static robj
*getDecodedObject(robj
*o
) {
2506 if (o
->encoding
== REDIS_ENCODING_RAW
) {
2510 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
2513 snprintf(buf
,32,"%ld",(long)o
->ptr
);
2514 dec
= createStringObject(buf
,strlen(buf
));
2517 redisAssert(1 != 1);
2521 /* Compare two string objects via strcmp() or alike.
2522 * Note that the objects may be integer-encoded. In such a case we
2523 * use snprintf() to get a string representation of the numbers on the stack
2524 * and compare the strings, it's much faster than calling getDecodedObject().
2526 * Important note: if objects are not integer encoded, but binary-safe strings,
2527 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
2529 static int compareStringObjects(robj
*a
, robj
*b
) {
2530 redisAssert(a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
2531 char bufa
[128], bufb
[128], *astr
, *bstr
;
2534 if (a
== b
) return 0;
2535 if (a
->encoding
!= REDIS_ENCODING_RAW
) {
2536 snprintf(bufa
,sizeof(bufa
),"%ld",(long) a
->ptr
);
2542 if (b
->encoding
!= REDIS_ENCODING_RAW
) {
2543 snprintf(bufb
,sizeof(bufb
),"%ld",(long) b
->ptr
);
2549 return bothsds
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
);
2552 static size_t stringObjectLen(robj
*o
) {
2553 redisAssert(o
->type
== REDIS_STRING
);
2554 if (o
->encoding
== REDIS_ENCODING_RAW
) {
2555 return sdslen(o
->ptr
);
2559 return snprintf(buf
,32,"%ld",(long)o
->ptr
);
2563 /*============================ RDB saving/loading =========================== */
2565 static int rdbSaveType(FILE *fp
, unsigned char type
) {
2566 if (fwrite(&type
,1,1,fp
) == 0) return -1;
2570 static int rdbSaveTime(FILE *fp
, time_t t
) {
2571 int32_t t32
= (int32_t) t
;
2572 if (fwrite(&t32
,4,1,fp
) == 0) return -1;
2576 /* check rdbLoadLen() comments for more info */
2577 static int rdbSaveLen(FILE *fp
, uint32_t len
) {
2578 unsigned char buf
[2];
2581 /* Save a 6 bit len */
2582 buf
[0] = (len
&0xFF)|(REDIS_RDB_6BITLEN
<<6);
2583 if (fwrite(buf
,1,1,fp
) == 0) return -1;
2584 } else if (len
< (1<<14)) {
2585 /* Save a 14 bit len */
2586 buf
[0] = ((len
>>8)&0xFF)|(REDIS_RDB_14BITLEN
<<6);
2588 if (fwrite(buf
,2,1,fp
) == 0) return -1;
2590 /* Save a 32 bit len */
2591 buf
[0] = (REDIS_RDB_32BITLEN
<<6);
2592 if (fwrite(buf
,1,1,fp
) == 0) return -1;
2594 if (fwrite(&len
,4,1,fp
) == 0) return -1;
2599 /* String objects in the form "2391" "-100" without any space and with a
2600 * range of values that can fit in an 8, 16 or 32 bit signed value can be
2601 * encoded as integers to save space */
2602 static int rdbTryIntegerEncoding(sds s
, unsigned char *enc
) {
2604 char *endptr
, buf
[32];
2606 /* Check if it's possible to encode this value as a number */
2607 value
= strtoll(s
, &endptr
, 10);
2608 if (endptr
[0] != '\0') return 0;
2609 snprintf(buf
,32,"%lld",value
);
2611 /* If the number converted back into a string is not identical
2612 * then it's not possible to encode the string as integer */
2613 if (strlen(buf
) != sdslen(s
) || memcmp(buf
,s
,sdslen(s
))) return 0;
2615 /* Finally check if it fits in our ranges */
2616 if (value
>= -(1<<7) && value
<= (1<<7)-1) {
2617 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT8
;
2618 enc
[1] = value
&0xFF;
2620 } else if (value
>= -(1<<15) && value
<= (1<<15)-1) {
2621 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT16
;
2622 enc
[1] = value
&0xFF;
2623 enc
[2] = (value
>>8)&0xFF;
2625 } else if (value
>= -((long long)1<<31) && value
<= ((long long)1<<31)-1) {
2626 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT32
;
2627 enc
[1] = value
&0xFF;
2628 enc
[2] = (value
>>8)&0xFF;
2629 enc
[3] = (value
>>16)&0xFF;
2630 enc
[4] = (value
>>24)&0xFF;
2637 static int rdbSaveLzfStringObject(FILE *fp
, robj
*obj
) {
2638 unsigned int comprlen
, outlen
;
2642 /* We require at least four bytes compression for this to be worth it */
2643 outlen
= sdslen(obj
->ptr
)-4;
2644 if (outlen
<= 0) return 0;
2645 if ((out
= zmalloc(outlen
+1)) == NULL
) return 0;
2646 comprlen
= lzf_compress(obj
->ptr
, sdslen(obj
->ptr
), out
, outlen
);
2647 if (comprlen
== 0) {
2651 /* Data compressed! Let's save it on disk */
2652 byte
= (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_LZF
;
2653 if (fwrite(&byte
,1,1,fp
) == 0) goto writeerr
;
2654 if (rdbSaveLen(fp
,comprlen
) == -1) goto writeerr
;
2655 if (rdbSaveLen(fp
,sdslen(obj
->ptr
)) == -1) goto writeerr
;
2656 if (fwrite(out
,comprlen
,1,fp
) == 0) goto writeerr
;
2665 /* Save a string objet as [len][data] on disk. If the object is a string
2666 * representation of an integer value we try to safe it in a special form */
2667 static int rdbSaveStringObjectRaw(FILE *fp
, robj
*obj
) {
2671 len
= sdslen(obj
->ptr
);
2673 /* Try integer encoding */
2675 unsigned char buf
[5];
2676 if ((enclen
= rdbTryIntegerEncoding(obj
->ptr
,buf
)) > 0) {
2677 if (fwrite(buf
,enclen
,1,fp
) == 0) return -1;
2682 /* Try LZF compression - under 20 bytes it's unable to compress even
2683 * aaaaaaaaaaaaaaaaaa so skip it */
2684 if (server
.rdbcompression
&& len
> 20) {
2687 retval
= rdbSaveLzfStringObject(fp
,obj
);
2688 if (retval
== -1) return -1;
2689 if (retval
> 0) return 0;
2690 /* retval == 0 means data can't be compressed, save the old way */
2693 /* Store verbatim */
2694 if (rdbSaveLen(fp
,len
) == -1) return -1;
2695 if (len
&& fwrite(obj
->ptr
,len
,1,fp
) == 0) return -1;
2699 /* Like rdbSaveStringObjectRaw() but handle encoded objects */
2700 static int rdbSaveStringObject(FILE *fp
, robj
*obj
) {
2703 obj
= getDecodedObject(obj
);
2704 retval
= rdbSaveStringObjectRaw(fp
,obj
);
2709 /* Save a double value. Doubles are saved as strings prefixed by an unsigned
2710 * 8 bit integer specifing the length of the representation.
2711 * This 8 bit integer has special values in order to specify the following
2717 static int rdbSaveDoubleValue(FILE *fp
, double val
) {
2718 unsigned char buf
[128];
2724 } else if (!isfinite(val
)) {
2726 buf
[0] = (val
< 0) ? 255 : 254;
2728 snprintf((char*)buf
+1,sizeof(buf
)-1,"%.17g",val
);
2729 buf
[0] = strlen((char*)buf
+1);
2732 if (fwrite(buf
,len
,1,fp
) == 0) return -1;
2736 /* Save a Redis object. */
2737 static int rdbSaveObject(FILE *fp
, robj
*o
) {
2738 if (o
->type
== REDIS_STRING
) {
2739 /* Save a string value */
2740 if (rdbSaveStringObject(fp
,o
) == -1) return -1;
2741 } else if (o
->type
== REDIS_LIST
) {
2742 /* Save a list value */
2743 list
*list
= o
->ptr
;
2747 if (rdbSaveLen(fp
,listLength(list
)) == -1) return -1;
2748 while((ln
= listYield(list
))) {
2749 robj
*eleobj
= listNodeValue(ln
);
2751 if (rdbSaveStringObject(fp
,eleobj
) == -1) return -1;
2753 } else if (o
->type
== REDIS_SET
) {
2754 /* Save a set value */
2756 dictIterator
*di
= dictGetIterator(set
);
2759 if (rdbSaveLen(fp
,dictSize(set
)) == -1) return -1;
2760 while((de
= dictNext(di
)) != NULL
) {
2761 robj
*eleobj
= dictGetEntryKey(de
);
2763 if (rdbSaveStringObject(fp
,eleobj
) == -1) return -1;
2765 dictReleaseIterator(di
);
2766 } else if (o
->type
== REDIS_ZSET
) {
2767 /* Save a set value */
2769 dictIterator
*di
= dictGetIterator(zs
->dict
);
2772 if (rdbSaveLen(fp
,dictSize(zs
->dict
)) == -1) return -1;
2773 while((de
= dictNext(di
)) != NULL
) {
2774 robj
*eleobj
= dictGetEntryKey(de
);
2775 double *score
= dictGetEntryVal(de
);
2777 if (rdbSaveStringObject(fp
,eleobj
) == -1) return -1;
2778 if (rdbSaveDoubleValue(fp
,*score
) == -1) return -1;
2780 dictReleaseIterator(di
);
2782 redisAssert(0 != 0);
2787 /* Return the length the object will have on disk if saved with
2788 * the rdbSaveObject() function. Currently we use a trick to get
2789 * this length with very little changes to the code. In the future
2790 * we could switch to a faster solution. */
2791 static off_t
rdbSavedObjectLen(robj
*o
) {
2792 static FILE *fp
= NULL
;
2794 if (fp
== NULL
) fp
= fopen("/dev/null","w");
2798 assert(rdbSaveObject(fp
,o
) != 1);
2802 /* Return the number of pages required to save this object in the swap file */
2803 static off_t
rdbSavedObjectPages(robj
*o
) {
2804 off_t bytes
= rdbSavedObjectLen(o
);
2806 return (bytes
+(server
.vm_page_size
-1))/server
.vm_page_size
;
2809 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
2810 static int rdbSave(char *filename
) {
2811 dictIterator
*di
= NULL
;
2816 time_t now
= time(NULL
);
2818 snprintf(tmpfile
,256,"temp-%d.rdb", (int) getpid());
2819 fp
= fopen(tmpfile
,"w");
2821 redisLog(REDIS_WARNING
, "Failed saving the DB: %s", strerror(errno
));
2824 if (fwrite("REDIS0001",9,1,fp
) == 0) goto werr
;
2825 for (j
= 0; j
< server
.dbnum
; j
++) {
2826 redisDb
*db
= server
.db
+j
;
2828 if (dictSize(d
) == 0) continue;
2829 di
= dictGetIterator(d
);
2835 /* Write the SELECT DB opcode */
2836 if (rdbSaveType(fp
,REDIS_SELECTDB
) == -1) goto werr
;
2837 if (rdbSaveLen(fp
,j
) == -1) goto werr
;
2839 /* Iterate this DB writing every entry */
2840 while((de
= dictNext(di
)) != NULL
) {
2841 robj
*key
= dictGetEntryKey(de
);
2842 robj
*o
= dictGetEntryVal(de
);
2843 time_t expiretime
= getExpire(db
,key
);
2845 /* Save the expire time */
2846 if (expiretime
!= -1) {
2847 /* If this key is already expired skip it */
2848 if (expiretime
< now
) continue;
2849 if (rdbSaveType(fp
,REDIS_EXPIRETIME
) == -1) goto werr
;
2850 if (rdbSaveTime(fp
,expiretime
) == -1) goto werr
;
2852 /* Save the key and associated value */
2853 if (rdbSaveType(fp
,o
->type
) == -1) goto werr
;
2854 if (rdbSaveStringObject(fp
,key
) == -1) goto werr
;
2855 /* Save the actual value */
2856 if (rdbSaveObject(fp
,o
) == -1) goto werr
;
2858 dictReleaseIterator(di
);
2861 if (rdbSaveType(fp
,REDIS_EOF
) == -1) goto werr
;
2863 /* Make sure data will not remain on the OS's output buffers */
2868 /* Use RENAME to make sure the DB file is changed atomically only
2869 * if the generate DB file is ok. */
2870 if (rename(tmpfile
,filename
) == -1) {
2871 redisLog(REDIS_WARNING
,"Error moving temp DB file on the final destination: %s", strerror(errno
));
2875 redisLog(REDIS_NOTICE
,"DB saved on disk");
2877 server
.lastsave
= time(NULL
);
2883 redisLog(REDIS_WARNING
,"Write error saving DB on disk: %s", strerror(errno
));
2884 if (di
) dictReleaseIterator(di
);
2888 static int rdbSaveBackground(char *filename
) {
2891 if (server
.bgsavechildpid
!= -1) return REDIS_ERR
;
2892 if ((childpid
= fork()) == 0) {
2895 if (rdbSave(filename
) == REDIS_OK
) {
2902 if (childpid
== -1) {
2903 redisLog(REDIS_WARNING
,"Can't save in background: fork: %s",
2907 redisLog(REDIS_NOTICE
,"Background saving started by pid %d",childpid
);
2908 server
.bgsavechildpid
= childpid
;
2911 return REDIS_OK
; /* unreached */
2914 static void rdbRemoveTempFile(pid_t childpid
) {
2917 snprintf(tmpfile
,256,"temp-%d.rdb", (int) childpid
);
2921 static int rdbLoadType(FILE *fp
) {
2923 if (fread(&type
,1,1,fp
) == 0) return -1;
2927 static time_t rdbLoadTime(FILE *fp
) {
2929 if (fread(&t32
,4,1,fp
) == 0) return -1;
2930 return (time_t) t32
;
2933 /* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
2934 * of this file for a description of how this are stored on disk.
2936 * isencoded is set to 1 if the readed length is not actually a length but
2937 * an "encoding type", check the above comments for more info */
2938 static uint32_t rdbLoadLen(FILE *fp
, int *isencoded
) {
2939 unsigned char buf
[2];
2943 if (isencoded
) *isencoded
= 0;
2944 if (fread(buf
,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2945 type
= (buf
[0]&0xC0)>>6;
2946 if (type
== REDIS_RDB_6BITLEN
) {
2947 /* Read a 6 bit len */
2949 } else if (type
== REDIS_RDB_ENCVAL
) {
2950 /* Read a 6 bit len encoding type */
2951 if (isencoded
) *isencoded
= 1;
2953 } else if (type
== REDIS_RDB_14BITLEN
) {
2954 /* Read a 14 bit len */
2955 if (fread(buf
+1,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
2956 return ((buf
[0]&0x3F)<<8)|buf
[1];
2958 /* Read a 32 bit len */
2959 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
2964 static robj
*rdbLoadIntegerObject(FILE *fp
, int enctype
) {
2965 unsigned char enc
[4];
2968 if (enctype
== REDIS_RDB_ENC_INT8
) {
2969 if (fread(enc
,1,1,fp
) == 0) return NULL
;
2970 val
= (signed char)enc
[0];
2971 } else if (enctype
== REDIS_RDB_ENC_INT16
) {
2973 if (fread(enc
,2,1,fp
) == 0) return NULL
;
2974 v
= enc
[0]|(enc
[1]<<8);
2976 } else if (enctype
== REDIS_RDB_ENC_INT32
) {
2978 if (fread(enc
,4,1,fp
) == 0) return NULL
;
2979 v
= enc
[0]|(enc
[1]<<8)|(enc
[2]<<16)|(enc
[3]<<24);
2982 val
= 0; /* anti-warning */
2985 return createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",val
));
2988 static robj
*rdbLoadLzfStringObject(FILE*fp
) {
2989 unsigned int len
, clen
;
2990 unsigned char *c
= NULL
;
2993 if ((clen
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2994 if ((len
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
2995 if ((c
= zmalloc(clen
)) == NULL
) goto err
;
2996 if ((val
= sdsnewlen(NULL
,len
)) == NULL
) goto err
;
2997 if (fread(c
,clen
,1,fp
) == 0) goto err
;
2998 if (lzf_decompress(c
,clen
,val
,len
) == 0) goto err
;
3000 return createObject(REDIS_STRING
,val
);
3007 static robj
*rdbLoadStringObject(FILE*fp
) {
3012 len
= rdbLoadLen(fp
,&isencoded
);
3015 case REDIS_RDB_ENC_INT8
:
3016 case REDIS_RDB_ENC_INT16
:
3017 case REDIS_RDB_ENC_INT32
:
3018 return tryObjectSharing(rdbLoadIntegerObject(fp
,len
));
3019 case REDIS_RDB_ENC_LZF
:
3020 return tryObjectSharing(rdbLoadLzfStringObject(fp
));
3026 if (len
== REDIS_RDB_LENERR
) return NULL
;
3027 val
= sdsnewlen(NULL
,len
);
3028 if (len
&& fread(val
,len
,1,fp
) == 0) {
3032 return tryObjectSharing(createObject(REDIS_STRING
,val
));
3035 /* For information about double serialization check rdbSaveDoubleValue() */
3036 static int rdbLoadDoubleValue(FILE *fp
, double *val
) {
3040 if (fread(&len
,1,1,fp
) == 0) return -1;
3042 case 255: *val
= R_NegInf
; return 0;
3043 case 254: *val
= R_PosInf
; return 0;
3044 case 253: *val
= R_Nan
; return 0;
3046 if (fread(buf
,len
,1,fp
) == 0) return -1;
3048 sscanf(buf
, "%lg", val
);
3053 /* Load a Redis object of the specified type from the specified file.
3054 * On success a newly allocated object is returned, otherwise NULL. */
3055 static robj
*rdbLoadObject(int type
, FILE *fp
) {
3058 if (type
== REDIS_STRING
) {
3059 /* Read string value */
3060 if ((o
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3061 tryObjectEncoding(o
);
3062 } else if (type
== REDIS_LIST
|| type
== REDIS_SET
) {
3063 /* Read list/set value */
3066 if ((listlen
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3067 o
= (type
== REDIS_LIST
) ? createListObject() : createSetObject();
3068 /* Load every single element of the list/set */
3072 if ((ele
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3073 tryObjectEncoding(ele
);
3074 if (type
== REDIS_LIST
) {
3075 listAddNodeTail((list
*)o
->ptr
,ele
);
3077 dictAdd((dict
*)o
->ptr
,ele
,NULL
);
3080 } else if (type
== REDIS_ZSET
) {
3081 /* Read list/set value */
3085 if ((zsetlen
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3086 o
= createZsetObject();
3088 /* Load every single element of the list/set */
3091 double *score
= zmalloc(sizeof(double));
3093 if ((ele
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3094 tryObjectEncoding(ele
);
3095 if (rdbLoadDoubleValue(fp
,score
) == -1) return NULL
;
3096 dictAdd(zs
->dict
,ele
,score
);
3097 zslInsert(zs
->zsl
,*score
,ele
);
3098 incrRefCount(ele
); /* added to skiplist */
3101 redisAssert(0 != 0);
3106 static int rdbLoad(char *filename
) {
3108 robj
*keyobj
= NULL
;
3110 int type
, retval
, rdbver
;
3111 dict
*d
= server
.db
[0].dict
;
3112 redisDb
*db
= server
.db
+0;
3114 time_t expiretime
= -1, now
= time(NULL
);
3116 fp
= fopen(filename
,"r");
3117 if (!fp
) return REDIS_ERR
;
3118 if (fread(buf
,9,1,fp
) == 0) goto eoferr
;
3120 if (memcmp(buf
,"REDIS",5) != 0) {
3122 redisLog(REDIS_WARNING
,"Wrong signature trying to load DB from file");
3125 rdbver
= atoi(buf
+5);
3128 redisLog(REDIS_WARNING
,"Can't handle RDB format version %d",rdbver
);
3135 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
3136 if (type
== REDIS_EXPIRETIME
) {
3137 if ((expiretime
= rdbLoadTime(fp
)) == -1) goto eoferr
;
3138 /* We read the time so we need to read the object type again */
3139 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
3141 if (type
== REDIS_EOF
) break;
3142 /* Handle SELECT DB opcode as a special case */
3143 if (type
== REDIS_SELECTDB
) {
3144 if ((dbid
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
)
3146 if (dbid
>= (unsigned)server
.dbnum
) {
3147 redisLog(REDIS_WARNING
,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server
.dbnum
);
3150 db
= server
.db
+dbid
;
3155 if ((keyobj
= rdbLoadStringObject(fp
)) == NULL
) goto eoferr
;
3157 if ((o
= rdbLoadObject(type
,fp
)) == NULL
) goto eoferr
;
3158 /* Add the new object in the hash table */
3159 retval
= dictAdd(d
,keyobj
,o
);
3160 if (retval
== DICT_ERR
) {
3161 redisLog(REDIS_WARNING
,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj
->ptr
);
3164 /* Set the expire time if needed */
3165 if (expiretime
!= -1) {
3166 setExpire(db
,keyobj
,expiretime
);
3167 /* Delete this key if already expired */
3168 if (expiretime
< now
) deleteKey(db
,keyobj
);
3176 eoferr
: /* unexpected end of file is handled here with a fatal exit */
3177 if (keyobj
) decrRefCount(keyobj
);
3178 redisLog(REDIS_WARNING
,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
3180 return REDIS_ERR
; /* Just to avoid warning */
3183 /*================================== Commands =============================== */
3185 static void authCommand(redisClient
*c
) {
3186 if (!server
.requirepass
|| !strcmp(c
->argv
[1]->ptr
, server
.requirepass
)) {
3187 c
->authenticated
= 1;
3188 addReply(c
,shared
.ok
);
3190 c
->authenticated
= 0;
3191 addReplySds(c
,sdscatprintf(sdsempty(),"-ERR invalid password\r\n"));
3195 static void pingCommand(redisClient
*c
) {
3196 addReply(c
,shared
.pong
);
3199 static void echoCommand(redisClient
*c
) {
3200 addReplyBulkLen(c
,c
->argv
[1]);
3201 addReply(c
,c
->argv
[1]);
3202 addReply(c
,shared
.crlf
);
3205 /*=================================== Strings =============================== */
3207 static void setGenericCommand(redisClient
*c
, int nx
) {
3210 if (nx
) deleteIfVolatile(c
->db
,c
->argv
[1]);
3211 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
3212 if (retval
== DICT_ERR
) {
3214 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
3215 incrRefCount(c
->argv
[2]);
3217 addReply(c
,shared
.czero
);
3221 incrRefCount(c
->argv
[1]);
3222 incrRefCount(c
->argv
[2]);
3225 removeExpire(c
->db
,c
->argv
[1]);
3226 addReply(c
, nx
? shared
.cone
: shared
.ok
);
3229 static void setCommand(redisClient
*c
) {
3230 setGenericCommand(c
,0);
3233 static void setnxCommand(redisClient
*c
) {
3234 setGenericCommand(c
,1);
3237 static int getGenericCommand(redisClient
*c
) {
3238 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3241 addReply(c
,shared
.nullbulk
);
3244 if (o
->type
!= REDIS_STRING
) {
3245 addReply(c
,shared
.wrongtypeerr
);
3248 addReplyBulkLen(c
,o
);
3250 addReply(c
,shared
.crlf
);
3256 static void getCommand(redisClient
*c
) {
3257 getGenericCommand(c
);
3260 static void getsetCommand(redisClient
*c
) {
3261 if (getGenericCommand(c
) == REDIS_ERR
) return;
3262 if (dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]) == DICT_ERR
) {
3263 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
3265 incrRefCount(c
->argv
[1]);
3267 incrRefCount(c
->argv
[2]);
3269 removeExpire(c
->db
,c
->argv
[1]);
3272 static void mgetCommand(redisClient
*c
) {
3275 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",c
->argc
-1));
3276 for (j
= 1; j
< c
->argc
; j
++) {
3277 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
3279 addReply(c
,shared
.nullbulk
);
3281 if (o
->type
!= REDIS_STRING
) {
3282 addReply(c
,shared
.nullbulk
);
3284 addReplyBulkLen(c
,o
);
3286 addReply(c
,shared
.crlf
);
3292 static void msetGenericCommand(redisClient
*c
, int nx
) {
3293 int j
, busykeys
= 0;
3295 if ((c
->argc
% 2) == 0) {
3296 addReplySds(c
,sdsnew("-ERR wrong number of arguments for MSET\r\n"));
3299 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
3300 * set nothing at all if at least one already key exists. */
3302 for (j
= 1; j
< c
->argc
; j
+= 2) {
3303 if (lookupKeyWrite(c
->db
,c
->argv
[j
]) != NULL
) {
3309 addReply(c
, shared
.czero
);
3313 for (j
= 1; j
< c
->argc
; j
+= 2) {
3316 tryObjectEncoding(c
->argv
[j
+1]);
3317 retval
= dictAdd(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
3318 if (retval
== DICT_ERR
) {
3319 dictReplace(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
3320 incrRefCount(c
->argv
[j
+1]);
3322 incrRefCount(c
->argv
[j
]);
3323 incrRefCount(c
->argv
[j
+1]);
3325 removeExpire(c
->db
,c
->argv
[j
]);
3327 server
.dirty
+= (c
->argc
-1)/2;
3328 addReply(c
, nx
? shared
.cone
: shared
.ok
);
3331 static void msetCommand(redisClient
*c
) {
3332 msetGenericCommand(c
,0);
3335 static void msetnxCommand(redisClient
*c
) {
3336 msetGenericCommand(c
,1);
3339 static void incrDecrCommand(redisClient
*c
, long long incr
) {
3344 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3348 if (o
->type
!= REDIS_STRING
) {
3353 if (o
->encoding
== REDIS_ENCODING_RAW
)
3354 value
= strtoll(o
->ptr
, &eptr
, 10);
3355 else if (o
->encoding
== REDIS_ENCODING_INT
)
3356 value
= (long)o
->ptr
;
3358 redisAssert(1 != 1);
3363 o
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",value
));
3364 tryObjectEncoding(o
);
3365 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],o
);
3366 if (retval
== DICT_ERR
) {
3367 dictReplace(c
->db
->dict
,c
->argv
[1],o
);
3368 removeExpire(c
->db
,c
->argv
[1]);
3370 incrRefCount(c
->argv
[1]);
3373 addReply(c
,shared
.colon
);
3375 addReply(c
,shared
.crlf
);
3378 static void incrCommand(redisClient
*c
) {
3379 incrDecrCommand(c
,1);
3382 static void decrCommand(redisClient
*c
) {
3383 incrDecrCommand(c
,-1);
3386 static void incrbyCommand(redisClient
*c
) {
3387 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
3388 incrDecrCommand(c
,incr
);
3391 static void decrbyCommand(redisClient
*c
) {
3392 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
3393 incrDecrCommand(c
,-incr
);
3396 /* ========================= Type agnostic commands ========================= */
3398 static void delCommand(redisClient
*c
) {
3401 for (j
= 1; j
< c
->argc
; j
++) {
3402 if (deleteKey(c
->db
,c
->argv
[j
])) {
3409 addReply(c
,shared
.czero
);
3412 addReply(c
,shared
.cone
);
3415 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",deleted
));
3420 static void existsCommand(redisClient
*c
) {
3421 addReply(c
,lookupKeyRead(c
->db
,c
->argv
[1]) ? shared
.cone
: shared
.czero
);
3424 static void selectCommand(redisClient
*c
) {
3425 int id
= atoi(c
->argv
[1]->ptr
);
3427 if (selectDb(c
,id
) == REDIS_ERR
) {
3428 addReplySds(c
,sdsnew("-ERR invalid DB index\r\n"));
3430 addReply(c
,shared
.ok
);
3434 static void randomkeyCommand(redisClient
*c
) {
3438 de
= dictGetRandomKey(c
->db
->dict
);
3439 if (!de
|| expireIfNeeded(c
->db
,dictGetEntryKey(de
)) == 0) break;
3442 addReply(c
,shared
.plus
);
3443 addReply(c
,shared
.crlf
);
3445 addReply(c
,shared
.plus
);
3446 addReply(c
,dictGetEntryKey(de
));
3447 addReply(c
,shared
.crlf
);
3451 static void keysCommand(redisClient
*c
) {
3454 sds pattern
= c
->argv
[1]->ptr
;
3455 int plen
= sdslen(pattern
);
3456 unsigned long numkeys
= 0, keyslen
= 0;
3457 robj
*lenobj
= createObject(REDIS_STRING
,NULL
);
3459 di
= dictGetIterator(c
->db
->dict
);
3461 decrRefCount(lenobj
);
3462 while((de
= dictNext(di
)) != NULL
) {
3463 robj
*keyobj
= dictGetEntryKey(de
);
3465 sds key
= keyobj
->ptr
;
3466 if ((pattern
[0] == '*' && pattern
[1] == '\0') ||
3467 stringmatchlen(pattern
,plen
,key
,sdslen(key
),0)) {
3468 if (expireIfNeeded(c
->db
,keyobj
) == 0) {
3470 addReply(c
,shared
.space
);
3473 keyslen
+= sdslen(key
);
3477 dictReleaseIterator(di
);
3478 lenobj
->ptr
= sdscatprintf(sdsempty(),"$%lu\r\n",keyslen
+(numkeys
? (numkeys
-1) : 0));
3479 addReply(c
,shared
.crlf
);
3482 static void dbsizeCommand(redisClient
*c
) {
3484 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c
->db
->dict
)));
3487 static void lastsaveCommand(redisClient
*c
) {
3489 sdscatprintf(sdsempty(),":%lu\r\n",server
.lastsave
));
3492 static void typeCommand(redisClient
*c
) {
3496 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3501 case REDIS_STRING
: type
= "+string"; break;
3502 case REDIS_LIST
: type
= "+list"; break;
3503 case REDIS_SET
: type
= "+set"; break;
3504 case REDIS_ZSET
: type
= "+zset"; break;
3505 default: type
= "unknown"; break;
3508 addReplySds(c
,sdsnew(type
));
3509 addReply(c
,shared
.crlf
);
3512 static void saveCommand(redisClient
*c
) {
3513 if (server
.bgsavechildpid
!= -1) {
3514 addReplySds(c
,sdsnew("-ERR background save in progress\r\n"));
3517 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
3518 addReply(c
,shared
.ok
);
3520 addReply(c
,shared
.err
);
3524 static void bgsaveCommand(redisClient
*c
) {
3525 if (server
.bgsavechildpid
!= -1) {
3526 addReplySds(c
,sdsnew("-ERR background save already in progress\r\n"));
3529 if (rdbSaveBackground(server
.dbfilename
) == REDIS_OK
) {
3530 char *status
= "+Background saving started\r\n";
3531 addReplySds(c
,sdsnew(status
));
3533 addReply(c
,shared
.err
);
3537 static void shutdownCommand(redisClient
*c
) {
3538 redisLog(REDIS_WARNING
,"User requested shutdown, saving DB...");
3539 /* Kill the saving child if there is a background saving in progress.
3540 We want to avoid race conditions, for instance our saving child may
3541 overwrite the synchronous saving did by SHUTDOWN. */
3542 if (server
.bgsavechildpid
!= -1) {
3543 redisLog(REDIS_WARNING
,"There is a live saving child. Killing it!");
3544 kill(server
.bgsavechildpid
,SIGKILL
);
3545 rdbRemoveTempFile(server
.bgsavechildpid
);
3547 if (server
.appendonly
) {
3548 /* Append only file: fsync() the AOF and exit */
3549 fsync(server
.appendfd
);
3552 /* Snapshotting. Perform a SYNC SAVE and exit */
3553 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
3554 if (server
.daemonize
)
3555 unlink(server
.pidfile
);
3556 redisLog(REDIS_WARNING
,"%zu bytes used at exit",zmalloc_used_memory());
3557 redisLog(REDIS_WARNING
,"Server exit now, bye bye...");
3560 /* Ooops.. error saving! The best we can do is to continue operating.
3561 * Note that if there was a background saving process, in the next
3562 * cron() Redis will be notified that the background saving aborted,
3563 * handling special stuff like slaves pending for synchronization... */
3564 redisLog(REDIS_WARNING
,"Error trying to save the DB, can't exit");
3565 addReplySds(c
,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
3570 static void renameGenericCommand(redisClient
*c
, int nx
) {
3573 /* To use the same key as src and dst is probably an error */
3574 if (sdscmp(c
->argv
[1]->ptr
,c
->argv
[2]->ptr
) == 0) {
3575 addReply(c
,shared
.sameobjecterr
);
3579 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3581 addReply(c
,shared
.nokeyerr
);
3585 deleteIfVolatile(c
->db
,c
->argv
[2]);
3586 if (dictAdd(c
->db
->dict
,c
->argv
[2],o
) == DICT_ERR
) {
3589 addReply(c
,shared
.czero
);
3592 dictReplace(c
->db
->dict
,c
->argv
[2],o
);
3594 incrRefCount(c
->argv
[2]);
3596 deleteKey(c
->db
,c
->argv
[1]);
3598 addReply(c
,nx
? shared
.cone
: shared
.ok
);
3601 static void renameCommand(redisClient
*c
) {
3602 renameGenericCommand(c
,0);
3605 static void renamenxCommand(redisClient
*c
) {
3606 renameGenericCommand(c
,1);
3609 static void moveCommand(redisClient
*c
) {
3614 /* Obtain source and target DB pointers */
3617 if (selectDb(c
,atoi(c
->argv
[2]->ptr
)) == REDIS_ERR
) {
3618 addReply(c
,shared
.outofrangeerr
);
3622 selectDb(c
,srcid
); /* Back to the source DB */
3624 /* If the user is moving using as target the same
3625 * DB as the source DB it is probably an error. */
3627 addReply(c
,shared
.sameobjecterr
);
3631 /* Check if the element exists and get a reference */
3632 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3634 addReply(c
,shared
.czero
);
3638 /* Try to add the element to the target DB */
3639 deleteIfVolatile(dst
,c
->argv
[1]);
3640 if (dictAdd(dst
->dict
,c
->argv
[1],o
) == DICT_ERR
) {
3641 addReply(c
,shared
.czero
);
3644 incrRefCount(c
->argv
[1]);
3647 /* OK! key moved, free the entry in the source DB */
3648 deleteKey(src
,c
->argv
[1]);
3650 addReply(c
,shared
.cone
);
3653 /* =================================== Lists ================================ */
3654 static void pushGenericCommand(redisClient
*c
, int where
) {
3658 lobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3660 if (handleClientsWaitingListPush(c
,c
->argv
[1],c
->argv
[2])) {
3661 addReply(c
,shared
.ok
);
3664 lobj
= createListObject();
3666 if (where
== REDIS_HEAD
) {
3667 listAddNodeHead(list
,c
->argv
[2]);
3669 listAddNodeTail(list
,c
->argv
[2]);
3671 dictAdd(c
->db
->dict
,c
->argv
[1],lobj
);
3672 incrRefCount(c
->argv
[1]);
3673 incrRefCount(c
->argv
[2]);
3675 if (lobj
->type
!= REDIS_LIST
) {
3676 addReply(c
,shared
.wrongtypeerr
);
3679 if (handleClientsWaitingListPush(c
,c
->argv
[1],c
->argv
[2])) {
3680 addReply(c
,shared
.ok
);
3684 if (where
== REDIS_HEAD
) {
3685 listAddNodeHead(list
,c
->argv
[2]);
3687 listAddNodeTail(list
,c
->argv
[2]);
3689 incrRefCount(c
->argv
[2]);
3692 addReply(c
,shared
.ok
);
3695 static void lpushCommand(redisClient
*c
) {
3696 pushGenericCommand(c
,REDIS_HEAD
);
3699 static void rpushCommand(redisClient
*c
) {
3700 pushGenericCommand(c
,REDIS_TAIL
);
3703 static void llenCommand(redisClient
*c
) {
3707 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3709 addReply(c
,shared
.czero
);
3712 if (o
->type
!= REDIS_LIST
) {
3713 addReply(c
,shared
.wrongtypeerr
);
3716 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",listLength(l
)));
3721 static void lindexCommand(redisClient
*c
) {
3723 int index
= atoi(c
->argv
[2]->ptr
);
3725 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3727 addReply(c
,shared
.nullbulk
);
3729 if (o
->type
!= REDIS_LIST
) {
3730 addReply(c
,shared
.wrongtypeerr
);
3732 list
*list
= o
->ptr
;
3735 ln
= listIndex(list
, index
);
3737 addReply(c
,shared
.nullbulk
);
3739 robj
*ele
= listNodeValue(ln
);
3740 addReplyBulkLen(c
,ele
);
3742 addReply(c
,shared
.crlf
);
3748 static void lsetCommand(redisClient
*c
) {
3750 int index
= atoi(c
->argv
[2]->ptr
);
3752 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3754 addReply(c
,shared
.nokeyerr
);
3756 if (o
->type
!= REDIS_LIST
) {
3757 addReply(c
,shared
.wrongtypeerr
);
3759 list
*list
= o
->ptr
;
3762 ln
= listIndex(list
, index
);
3764 addReply(c
,shared
.outofrangeerr
);
3766 robj
*ele
= listNodeValue(ln
);
3769 listNodeValue(ln
) = c
->argv
[3];
3770 incrRefCount(c
->argv
[3]);
3771 addReply(c
,shared
.ok
);
3778 static void popGenericCommand(redisClient
*c
, int where
) {
3781 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3783 addReply(c
,shared
.nullbulk
);
3785 if (o
->type
!= REDIS_LIST
) {
3786 addReply(c
,shared
.wrongtypeerr
);
3788 list
*list
= o
->ptr
;
3791 if (where
== REDIS_HEAD
)
3792 ln
= listFirst(list
);
3794 ln
= listLast(list
);
3797 addReply(c
,shared
.nullbulk
);
3799 robj
*ele
= listNodeValue(ln
);
3800 addReplyBulkLen(c
,ele
);
3802 addReply(c
,shared
.crlf
);
3803 listDelNode(list
,ln
);
3810 static void lpopCommand(redisClient
*c
) {
3811 popGenericCommand(c
,REDIS_HEAD
);
3814 static void rpopCommand(redisClient
*c
) {
3815 popGenericCommand(c
,REDIS_TAIL
);
3818 static void lrangeCommand(redisClient
*c
) {
3820 int start
= atoi(c
->argv
[2]->ptr
);
3821 int end
= atoi(c
->argv
[3]->ptr
);
3823 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
3825 addReply(c
,shared
.nullmultibulk
);
3827 if (o
->type
!= REDIS_LIST
) {
3828 addReply(c
,shared
.wrongtypeerr
);
3830 list
*list
= o
->ptr
;
3832 int llen
= listLength(list
);
3836 /* convert negative indexes */
3837 if (start
< 0) start
= llen
+start
;
3838 if (end
< 0) end
= llen
+end
;
3839 if (start
< 0) start
= 0;
3840 if (end
< 0) end
= 0;
3842 /* indexes sanity checks */
3843 if (start
> end
|| start
>= llen
) {
3844 /* Out of range start or start > end result in empty list */
3845 addReply(c
,shared
.emptymultibulk
);
3848 if (end
>= llen
) end
= llen
-1;
3849 rangelen
= (end
-start
)+1;
3851 /* Return the result in form of a multi-bulk reply */
3852 ln
= listIndex(list
, start
);
3853 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",rangelen
));
3854 for (j
= 0; j
< rangelen
; j
++) {
3855 ele
= listNodeValue(ln
);
3856 addReplyBulkLen(c
,ele
);
3858 addReply(c
,shared
.crlf
);
3865 static void ltrimCommand(redisClient
*c
) {
3867 int start
= atoi(c
->argv
[2]->ptr
);
3868 int end
= atoi(c
->argv
[3]->ptr
);
3870 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3872 addReply(c
,shared
.ok
);
3874 if (o
->type
!= REDIS_LIST
) {
3875 addReply(c
,shared
.wrongtypeerr
);
3877 list
*list
= o
->ptr
;
3879 int llen
= listLength(list
);
3880 int j
, ltrim
, rtrim
;
3882 /* convert negative indexes */
3883 if (start
< 0) start
= llen
+start
;
3884 if (end
< 0) end
= llen
+end
;
3885 if (start
< 0) start
= 0;
3886 if (end
< 0) end
= 0;
3888 /* indexes sanity checks */
3889 if (start
> end
|| start
>= llen
) {
3890 /* Out of range start or start > end result in empty list */
3894 if (end
>= llen
) end
= llen
-1;
3899 /* Remove list elements to perform the trim */
3900 for (j
= 0; j
< ltrim
; j
++) {
3901 ln
= listFirst(list
);
3902 listDelNode(list
,ln
);
3904 for (j
= 0; j
< rtrim
; j
++) {
3905 ln
= listLast(list
);
3906 listDelNode(list
,ln
);
3909 addReply(c
,shared
.ok
);
3914 static void lremCommand(redisClient
*c
) {
3917 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3919 addReply(c
,shared
.czero
);
3921 if (o
->type
!= REDIS_LIST
) {
3922 addReply(c
,shared
.wrongtypeerr
);
3924 list
*list
= o
->ptr
;
3925 listNode
*ln
, *next
;
3926 int toremove
= atoi(c
->argv
[2]->ptr
);
3931 toremove
= -toremove
;
3934 ln
= fromtail
? list
->tail
: list
->head
;
3936 robj
*ele
= listNodeValue(ln
);
3938 next
= fromtail
? ln
->prev
: ln
->next
;
3939 if (compareStringObjects(ele
,c
->argv
[3]) == 0) {
3940 listDelNode(list
,ln
);
3943 if (toremove
&& removed
== toremove
) break;
3947 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",removed
));
3952 /* This is the semantic of this command:
3953 * RPOPLPUSH srclist dstlist:
3954 * IF LLEN(srclist) > 0
3955 * element = RPOP srclist
3956 * LPUSH dstlist element
3963 * The idea is to be able to get an element from a list in a reliable way
3964 * since the element is not just returned but pushed against another list
3965 * as well. This command was originally proposed by Ezra Zygmuntowicz.
3967 static void rpoplpushcommand(redisClient
*c
) {
3970 sobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3972 addReply(c
,shared
.nullbulk
);
3974 if (sobj
->type
!= REDIS_LIST
) {
3975 addReply(c
,shared
.wrongtypeerr
);
3977 list
*srclist
= sobj
->ptr
;
3978 listNode
*ln
= listLast(srclist
);
3981 addReply(c
,shared
.nullbulk
);
3983 robj
*dobj
= lookupKeyWrite(c
->db
,c
->argv
[2]);
3984 robj
*ele
= listNodeValue(ln
);
3987 if (dobj
&& dobj
->type
!= REDIS_LIST
) {
3988 addReply(c
,shared
.wrongtypeerr
);
3992 /* Add the element to the target list (unless it's directly
3993 * passed to some BLPOP-ing client */
3994 if (!handleClientsWaitingListPush(c
,c
->argv
[2],ele
)) {
3996 /* Create the list if the key does not exist */
3997 dobj
= createListObject();
3998 dictAdd(c
->db
->dict
,c
->argv
[2],dobj
);
3999 incrRefCount(c
->argv
[2]);
4001 dstlist
= dobj
->ptr
;
4002 listAddNodeHead(dstlist
,ele
);
4006 /* Send the element to the client as reply as well */
4007 addReplyBulkLen(c
,ele
);
4009 addReply(c
,shared
.crlf
);
4011 /* Finally remove the element from the source list */
4012 listDelNode(srclist
,ln
);
4020 /* ==================================== Sets ================================ */
4022 static void saddCommand(redisClient
*c
) {
4025 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4027 set
= createSetObject();
4028 dictAdd(c
->db
->dict
,c
->argv
[1],set
);
4029 incrRefCount(c
->argv
[1]);
4031 if (set
->type
!= REDIS_SET
) {
4032 addReply(c
,shared
.wrongtypeerr
);
4036 if (dictAdd(set
->ptr
,c
->argv
[2],NULL
) == DICT_OK
) {
4037 incrRefCount(c
->argv
[2]);
4039 addReply(c
,shared
.cone
);
4041 addReply(c
,shared
.czero
);
4045 static void sremCommand(redisClient
*c
) {
4048 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4050 addReply(c
,shared
.czero
);
4052 if (set
->type
!= REDIS_SET
) {
4053 addReply(c
,shared
.wrongtypeerr
);
4056 if (dictDelete(set
->ptr
,c
->argv
[2]) == DICT_OK
) {
4058 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
4059 addReply(c
,shared
.cone
);
4061 addReply(c
,shared
.czero
);
4066 static void smoveCommand(redisClient
*c
) {
4067 robj
*srcset
, *dstset
;
4069 srcset
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4070 dstset
= lookupKeyWrite(c
->db
,c
->argv
[2]);
4072 /* If the source key does not exist return 0, if it's of the wrong type
4074 if (srcset
== NULL
|| srcset
->type
!= REDIS_SET
) {
4075 addReply(c
, srcset
? shared
.wrongtypeerr
: shared
.czero
);
4078 /* Error if the destination key is not a set as well */
4079 if (dstset
&& dstset
->type
!= REDIS_SET
) {
4080 addReply(c
,shared
.wrongtypeerr
);
4083 /* Remove the element from the source set */
4084 if (dictDelete(srcset
->ptr
,c
->argv
[3]) == DICT_ERR
) {
4085 /* Key not found in the src set! return zero */
4086 addReply(c
,shared
.czero
);
4090 /* Add the element to the destination set */
4092 dstset
= createSetObject();
4093 dictAdd(c
->db
->dict
,c
->argv
[2],dstset
);
4094 incrRefCount(c
->argv
[2]);
4096 if (dictAdd(dstset
->ptr
,c
->argv
[3],NULL
) == DICT_OK
)
4097 incrRefCount(c
->argv
[3]);
4098 addReply(c
,shared
.cone
);
4101 static void sismemberCommand(redisClient
*c
) {
4104 set
= lookupKeyRead(c
->db
,c
->argv
[1]);
4106 addReply(c
,shared
.czero
);
4108 if (set
->type
!= REDIS_SET
) {
4109 addReply(c
,shared
.wrongtypeerr
);
4112 if (dictFind(set
->ptr
,c
->argv
[2]))
4113 addReply(c
,shared
.cone
);
4115 addReply(c
,shared
.czero
);
4119 static void scardCommand(redisClient
*c
) {
4123 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4125 addReply(c
,shared
.czero
);
4128 if (o
->type
!= REDIS_SET
) {
4129 addReply(c
,shared
.wrongtypeerr
);
4132 addReplySds(c
,sdscatprintf(sdsempty(),":%lu\r\n",
4138 static void spopCommand(redisClient
*c
) {
4142 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4144 addReply(c
,shared
.nullbulk
);
4146 if (set
->type
!= REDIS_SET
) {
4147 addReply(c
,shared
.wrongtypeerr
);
4150 de
= dictGetRandomKey(set
->ptr
);
4152 addReply(c
,shared
.nullbulk
);
4154 robj
*ele
= dictGetEntryKey(de
);
4156 addReplyBulkLen(c
,ele
);
4158 addReply(c
,shared
.crlf
);
4159 dictDelete(set
->ptr
,ele
);
4160 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
4166 static void srandmemberCommand(redisClient
*c
) {
4170 set
= lookupKeyRead(c
->db
,c
->argv
[1]);
4172 addReply(c
,shared
.nullbulk
);
4174 if (set
->type
!= REDIS_SET
) {
4175 addReply(c
,shared
.wrongtypeerr
);
4178 de
= dictGetRandomKey(set
->ptr
);
4180 addReply(c
,shared
.nullbulk
);
4182 robj
*ele
= dictGetEntryKey(de
);
4184 addReplyBulkLen(c
,ele
);
4186 addReply(c
,shared
.crlf
);
4191 static int qsortCompareSetsByCardinality(const void *s1
, const void *s2
) {
4192 dict
**d1
= (void*) s1
, **d2
= (void*) s2
;
4194 return dictSize(*d1
)-dictSize(*d2
);
4197 static void sinterGenericCommand(redisClient
*c
, robj
**setskeys
, unsigned long setsnum
, robj
*dstkey
) {
4198 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
4201 robj
*lenobj
= NULL
, *dstset
= NULL
;
4202 unsigned long j
, cardinality
= 0;
4204 for (j
= 0; j
< setsnum
; j
++) {
4208 lookupKeyWrite(c
->db
,setskeys
[j
]) :
4209 lookupKeyRead(c
->db
,setskeys
[j
]);
4213 if (deleteKey(c
->db
,dstkey
))
4215 addReply(c
,shared
.czero
);
4217 addReply(c
,shared
.nullmultibulk
);
4221 if (setobj
->type
!= REDIS_SET
) {
4223 addReply(c
,shared
.wrongtypeerr
);
4226 dv
[j
] = setobj
->ptr
;
4228 /* Sort sets from the smallest to largest, this will improve our
4229 * algorithm's performace */
4230 qsort(dv
,setsnum
,sizeof(dict
*),qsortCompareSetsByCardinality
);
4232 /* The first thing we should output is the total number of elements...
4233 * since this is a multi-bulk write, but at this stage we don't know
4234 * the intersection set size, so we use a trick, append an empty object
4235 * to the output list and save the pointer to later modify it with the
4238 lenobj
= createObject(REDIS_STRING
,NULL
);
4240 decrRefCount(lenobj
);
4242 /* If we have a target key where to store the resulting set
4243 * create this key with an empty set inside */
4244 dstset
= createSetObject();
4247 /* Iterate all the elements of the first (smallest) set, and test
4248 * the element against all the other sets, if at least one set does
4249 * not include the element it is discarded */
4250 di
= dictGetIterator(dv
[0]);
4252 while((de
= dictNext(di
)) != NULL
) {
4255 for (j
= 1; j
< setsnum
; j
++)
4256 if (dictFind(dv
[j
],dictGetEntryKey(de
)) == NULL
) break;
4258 continue; /* at least one set does not contain the member */
4259 ele
= dictGetEntryKey(de
);
4261 addReplyBulkLen(c
,ele
);
4263 addReply(c
,shared
.crlf
);
4266 dictAdd(dstset
->ptr
,ele
,NULL
);
4270 dictReleaseIterator(di
);
4273 /* Store the resulting set into the target */
4274 deleteKey(c
->db
,dstkey
);
4275 dictAdd(c
->db
->dict
,dstkey
,dstset
);
4276 incrRefCount(dstkey
);
4280 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%lu\r\n",cardinality
);
4282 addReplySds(c
,sdscatprintf(sdsempty(),":%lu\r\n",
4283 dictSize((dict
*)dstset
->ptr
)));
4289 static void sinterCommand(redisClient
*c
) {
4290 sinterGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
);
4293 static void sinterstoreCommand(redisClient
*c
) {
4294 sinterGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1]);
4297 #define REDIS_OP_UNION 0
4298 #define REDIS_OP_DIFF 1
4300 static void sunionDiffGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
, int op
) {
4301 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
4304 robj
*dstset
= NULL
;
4305 int j
, cardinality
= 0;
4307 for (j
= 0; j
< setsnum
; j
++) {
4311 lookupKeyWrite(c
->db
,setskeys
[j
]) :
4312 lookupKeyRead(c
->db
,setskeys
[j
]);
4317 if (setobj
->type
!= REDIS_SET
) {
4319 addReply(c
,shared
.wrongtypeerr
);
4322 dv
[j
] = setobj
->ptr
;
4325 /* We need a temp set object to store our union. If the dstkey
4326 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
4327 * this set object will be the resulting object to set into the target key*/
4328 dstset
= createSetObject();
4330 /* Iterate all the elements of all the sets, add every element a single
4331 * time to the result set */
4332 for (j
= 0; j
< setsnum
; j
++) {
4333 if (op
== REDIS_OP_DIFF
&& j
== 0 && !dv
[j
]) break; /* result set is empty */
4334 if (!dv
[j
]) continue; /* non existing keys are like empty sets */
4336 di
= dictGetIterator(dv
[j
]);
4338 while((de
= dictNext(di
)) != NULL
) {
4341 /* dictAdd will not add the same element multiple times */
4342 ele
= dictGetEntryKey(de
);
4343 if (op
== REDIS_OP_UNION
|| j
== 0) {
4344 if (dictAdd(dstset
->ptr
,ele
,NULL
) == DICT_OK
) {
4348 } else if (op
== REDIS_OP_DIFF
) {
4349 if (dictDelete(dstset
->ptr
,ele
) == DICT_OK
) {
4354 dictReleaseIterator(di
);
4356 if (op
== REDIS_OP_DIFF
&& cardinality
== 0) break; /* result set is empty */
4359 /* Output the content of the resulting set, if not in STORE mode */
4361 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",cardinality
));
4362 di
= dictGetIterator(dstset
->ptr
);
4363 while((de
= dictNext(di
)) != NULL
) {
4366 ele
= dictGetEntryKey(de
);
4367 addReplyBulkLen(c
,ele
);
4369 addReply(c
,shared
.crlf
);
4371 dictReleaseIterator(di
);
4373 /* If we have a target key where to store the resulting set
4374 * create this key with the result set inside */
4375 deleteKey(c
->db
,dstkey
);
4376 dictAdd(c
->db
->dict
,dstkey
,dstset
);
4377 incrRefCount(dstkey
);
4382 decrRefCount(dstset
);
4384 addReplySds(c
,sdscatprintf(sdsempty(),":%lu\r\n",
4385 dictSize((dict
*)dstset
->ptr
)));
4391 static void sunionCommand(redisClient
*c
) {
4392 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_UNION
);
4395 static void sunionstoreCommand(redisClient
*c
) {
4396 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_UNION
);
4399 static void sdiffCommand(redisClient
*c
) {
4400 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_DIFF
);
4403 static void sdiffstoreCommand(redisClient
*c
) {
4404 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_DIFF
);
4407 /* ==================================== ZSets =============================== */
4409 /* ZSETs are ordered sets using two data structures to hold the same elements
4410 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
4413 * The elements are added to an hash table mapping Redis objects to scores.
4414 * At the same time the elements are added to a skip list mapping scores
4415 * to Redis objects (so objects are sorted by scores in this "view"). */
4417 /* This skiplist implementation is almost a C translation of the original
4418 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
4419 * Alternative to Balanced Trees", modified in three ways:
4420 * a) this implementation allows for repeated values.
4421 * b) the comparison is not just by key (our 'score') but by satellite data.
4422 * c) there is a back pointer, so it's a doubly linked list with the back
4423 * pointers being only at "level 1". This allows to traverse the list
4424 * from tail to head, useful for ZREVRANGE. */
4426 static zskiplistNode
*zslCreateNode(int level
, double score
, robj
*obj
) {
4427 zskiplistNode
*zn
= zmalloc(sizeof(*zn
));
4429 zn
->forward
= zmalloc(sizeof(zskiplistNode
*) * level
);
4435 static zskiplist
*zslCreate(void) {
4439 zsl
= zmalloc(sizeof(*zsl
));
4442 zsl
->header
= zslCreateNode(ZSKIPLIST_MAXLEVEL
,0,NULL
);
4443 for (j
= 0; j
< ZSKIPLIST_MAXLEVEL
; j
++)
4444 zsl
->header
->forward
[j
] = NULL
;
4445 zsl
->header
->backward
= NULL
;
4450 static void zslFreeNode(zskiplistNode
*node
) {
4451 decrRefCount(node
->obj
);
4452 zfree(node
->forward
);
4456 static void zslFree(zskiplist
*zsl
) {
4457 zskiplistNode
*node
= zsl
->header
->forward
[0], *next
;
4459 zfree(zsl
->header
->forward
);
4462 next
= node
->forward
[0];
4469 static int zslRandomLevel(void) {
4471 while ((random()&0xFFFF) < (ZSKIPLIST_P
* 0xFFFF))
4476 static void zslInsert(zskiplist
*zsl
, double score
, robj
*obj
) {
4477 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
4481 for (i
= zsl
->level
-1; i
>= 0; i
--) {
4482 while (x
->forward
[i
] &&
4483 (x
->forward
[i
]->score
< score
||
4484 (x
->forward
[i
]->score
== score
&&
4485 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0)))
4489 /* we assume the key is not already inside, since we allow duplicated
4490 * scores, and the re-insertion of score and redis object should never
4491 * happpen since the caller of zslInsert() should test in the hash table
4492 * if the element is already inside or not. */
4493 level
= zslRandomLevel();
4494 if (level
> zsl
->level
) {
4495 for (i
= zsl
->level
; i
< level
; i
++)
4496 update
[i
] = zsl
->header
;
4499 x
= zslCreateNode(level
,score
,obj
);
4500 for (i
= 0; i
< level
; i
++) {
4501 x
->forward
[i
] = update
[i
]->forward
[i
];
4502 update
[i
]->forward
[i
] = x
;
4504 x
->backward
= (update
[0] == zsl
->header
) ? NULL
: update
[0];
4506 x
->forward
[0]->backward
= x
;
4512 /* Delete an element with matching score/object from the skiplist. */
4513 static int zslDelete(zskiplist
*zsl
, double score
, robj
*obj
) {
4514 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
4518 for (i
= zsl
->level
-1; i
>= 0; i
--) {
4519 while (x
->forward
[i
] &&
4520 (x
->forward
[i
]->score
< score
||
4521 (x
->forward
[i
]->score
== score
&&
4522 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0)))
4526 /* We may have multiple elements with the same score, what we need
4527 * is to find the element with both the right score and object. */
4529 if (x
&& score
== x
->score
&& compareStringObjects(x
->obj
,obj
) == 0) {
4530 for (i
= 0; i
< zsl
->level
; i
++) {
4531 if (update
[i
]->forward
[i
] != x
) break;
4532 update
[i
]->forward
[i
] = x
->forward
[i
];
4534 if (x
->forward
[0]) {
4535 x
->forward
[0]->backward
= (x
->backward
== zsl
->header
) ?
4538 zsl
->tail
= x
->backward
;
4541 while(zsl
->level
> 1 && zsl
->header
->forward
[zsl
->level
-1] == NULL
)
4546 return 0; /* not found */
4548 return 0; /* not found */
4551 /* Delete all the elements with score between min and max from the skiplist.
4552 * Min and mx are inclusive, so a score >= min || score <= max is deleted.
4553 * Note that this function takes the reference to the hash table view of the
4554 * sorted set, in order to remove the elements from the hash table too. */
4555 static unsigned long zslDeleteRange(zskiplist
*zsl
, double min
, double max
, dict
*dict
) {
4556 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
4557 unsigned long removed
= 0;
4561 for (i
= zsl
->level
-1; i
>= 0; i
--) {
4562 while (x
->forward
[i
] && x
->forward
[i
]->score
< min
)
4566 /* We may have multiple elements with the same score, what we need
4567 * is to find the element with both the right score and object. */
4569 while (x
&& x
->score
<= max
) {
4570 zskiplistNode
*next
;
4572 for (i
= 0; i
< zsl
->level
; i
++) {
4573 if (update
[i
]->forward
[i
] != x
) break;
4574 update
[i
]->forward
[i
] = x
->forward
[i
];
4576 if (x
->forward
[0]) {
4577 x
->forward
[0]->backward
= (x
->backward
== zsl
->header
) ?
4580 zsl
->tail
= x
->backward
;
4582 next
= x
->forward
[0];
4583 dictDelete(dict
,x
->obj
);
4585 while(zsl
->level
> 1 && zsl
->header
->forward
[zsl
->level
-1] == NULL
)
4591 return removed
; /* not found */
4594 /* Find the first node having a score equal or greater than the specified one.
4595 * Returns NULL if there is no match. */
4596 static zskiplistNode
*zslFirstWithScore(zskiplist
*zsl
, double score
) {
4601 for (i
= zsl
->level
-1; i
>= 0; i
--) {
4602 while (x
->forward
[i
] && x
->forward
[i
]->score
< score
)
4605 /* We may have multiple elements with the same score, what we need
4606 * is to find the element with both the right score and object. */
4607 return x
->forward
[0];
4610 /* The actual Z-commands implementations */
4612 /* This generic command implements both ZADD and ZINCRBY.
4613 * scoreval is the score if the operation is a ZADD (doincrement == 0) or
4614 * the increment if the operation is a ZINCRBY (doincrement == 1). */
4615 static void zaddGenericCommand(redisClient
*c
, robj
*key
, robj
*ele
, double scoreval
, int doincrement
) {
4620 zsetobj
= lookupKeyWrite(c
->db
,key
);
4621 if (zsetobj
== NULL
) {
4622 zsetobj
= createZsetObject();
4623 dictAdd(c
->db
->dict
,key
,zsetobj
);
4626 if (zsetobj
->type
!= REDIS_ZSET
) {
4627 addReply(c
,shared
.wrongtypeerr
);
4633 /* Ok now since we implement both ZADD and ZINCRBY here the code
4634 * needs to handle the two different conditions. It's all about setting
4635 * '*score', that is, the new score to set, to the right value. */
4636 score
= zmalloc(sizeof(double));
4640 /* Read the old score. If the element was not present starts from 0 */
4641 de
= dictFind(zs
->dict
,ele
);
4643 double *oldscore
= dictGetEntryVal(de
);
4644 *score
= *oldscore
+ scoreval
;
4652 /* What follows is a simple remove and re-insert operation that is common
4653 * to both ZADD and ZINCRBY... */
4654 if (dictAdd(zs
->dict
,ele
,score
) == DICT_OK
) {
4655 /* case 1: New element */
4656 incrRefCount(ele
); /* added to hash */
4657 zslInsert(zs
->zsl
,*score
,ele
);
4658 incrRefCount(ele
); /* added to skiplist */
4661 addReplyDouble(c
,*score
);
4663 addReply(c
,shared
.cone
);
4668 /* case 2: Score update operation */
4669 de
= dictFind(zs
->dict
,ele
);
4670 redisAssert(de
!= NULL
);
4671 oldscore
= dictGetEntryVal(de
);
4672 if (*score
!= *oldscore
) {
4675 /* Remove and insert the element in the skip list with new score */
4676 deleted
= zslDelete(zs
->zsl
,*oldscore
,ele
);
4677 redisAssert(deleted
!= 0);
4678 zslInsert(zs
->zsl
,*score
,ele
);
4680 /* Update the score in the hash table */
4681 dictReplace(zs
->dict
,ele
,score
);
4687 addReplyDouble(c
,*score
);
4689 addReply(c
,shared
.czero
);
4693 static void zaddCommand(redisClient
*c
) {
4696 scoreval
= strtod(c
->argv
[2]->ptr
,NULL
);
4697 zaddGenericCommand(c
,c
->argv
[1],c
->argv
[3],scoreval
,0);
4700 static void zincrbyCommand(redisClient
*c
) {
4703 scoreval
= strtod(c
->argv
[2]->ptr
,NULL
);
4704 zaddGenericCommand(c
,c
->argv
[1],c
->argv
[3],scoreval
,1);
4707 static void zremCommand(redisClient
*c
) {
4711 zsetobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4712 if (zsetobj
== NULL
) {
4713 addReply(c
,shared
.czero
);
4719 if (zsetobj
->type
!= REDIS_ZSET
) {
4720 addReply(c
,shared
.wrongtypeerr
);
4724 de
= dictFind(zs
->dict
,c
->argv
[2]);
4726 addReply(c
,shared
.czero
);
4729 /* Delete from the skiplist */
4730 oldscore
= dictGetEntryVal(de
);
4731 deleted
= zslDelete(zs
->zsl
,*oldscore
,c
->argv
[2]);
4732 redisAssert(deleted
!= 0);
4734 /* Delete from the hash table */
4735 dictDelete(zs
->dict
,c
->argv
[2]);
4736 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
4738 addReply(c
,shared
.cone
);
4742 static void zremrangebyscoreCommand(redisClient
*c
) {
4743 double min
= strtod(c
->argv
[2]->ptr
,NULL
);
4744 double max
= strtod(c
->argv
[3]->ptr
,NULL
);
4748 zsetobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4749 if (zsetobj
== NULL
) {
4750 addReply(c
,shared
.czero
);
4754 if (zsetobj
->type
!= REDIS_ZSET
) {
4755 addReply(c
,shared
.wrongtypeerr
);
4759 deleted
= zslDeleteRange(zs
->zsl
,min
,max
,zs
->dict
);
4760 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
4761 server
.dirty
+= deleted
;
4762 addReplySds(c
,sdscatprintf(sdsempty(),":%lu\r\n",deleted
));
4766 static void zrangeGenericCommand(redisClient
*c
, int reverse
) {
4768 int start
= atoi(c
->argv
[2]->ptr
);
4769 int end
= atoi(c
->argv
[3]->ptr
);
4772 if (c
->argc
== 5 && !strcasecmp(c
->argv
[4]->ptr
,"withscores")) {
4774 } else if (c
->argc
>= 5) {
4775 addReply(c
,shared
.syntaxerr
);
4779 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4781 addReply(c
,shared
.nullmultibulk
);
4783 if (o
->type
!= REDIS_ZSET
) {
4784 addReply(c
,shared
.wrongtypeerr
);
4786 zset
*zsetobj
= o
->ptr
;
4787 zskiplist
*zsl
= zsetobj
->zsl
;
4790 int llen
= zsl
->length
;
4794 /* convert negative indexes */
4795 if (start
< 0) start
= llen
+start
;
4796 if (end
< 0) end
= llen
+end
;
4797 if (start
< 0) start
= 0;
4798 if (end
< 0) end
= 0;
4800 /* indexes sanity checks */
4801 if (start
> end
|| start
>= llen
) {
4802 /* Out of range start or start > end result in empty list */
4803 addReply(c
,shared
.emptymultibulk
);
4806 if (end
>= llen
) end
= llen
-1;
4807 rangelen
= (end
-start
)+1;
4809 /* Return the result in form of a multi-bulk reply */
4815 ln
= zsl
->header
->forward
[0];
4817 ln
= ln
->forward
[0];
4820 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",
4821 withscores
? (rangelen
*2) : rangelen
));
4822 for (j
= 0; j
< rangelen
; j
++) {
4824 addReplyBulkLen(c
,ele
);
4826 addReply(c
,shared
.crlf
);
4828 addReplyDouble(c
,ln
->score
);
4829 ln
= reverse
? ln
->backward
: ln
->forward
[0];
4835 static void zrangeCommand(redisClient
*c
) {
4836 zrangeGenericCommand(c
,0);
4839 static void zrevrangeCommand(redisClient
*c
) {
4840 zrangeGenericCommand(c
,1);
4843 static void zrangebyscoreCommand(redisClient
*c
) {
4845 double min
= strtod(c
->argv
[2]->ptr
,NULL
);
4846 double max
= strtod(c
->argv
[3]->ptr
,NULL
);
4847 int offset
= 0, limit
= -1;
4849 if (c
->argc
!= 4 && c
->argc
!= 7) {
4851 sdsnew("-ERR wrong number of arguments for ZRANGEBYSCORE\r\n"));
4853 } else if (c
->argc
== 7 && strcasecmp(c
->argv
[4]->ptr
,"limit")) {
4854 addReply(c
,shared
.syntaxerr
);
4856 } else if (c
->argc
== 7) {
4857 offset
= atoi(c
->argv
[5]->ptr
);
4858 limit
= atoi(c
->argv
[6]->ptr
);
4859 if (offset
< 0) offset
= 0;
4862 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4864 addReply(c
,shared
.nullmultibulk
);
4866 if (o
->type
!= REDIS_ZSET
) {
4867 addReply(c
,shared
.wrongtypeerr
);
4869 zset
*zsetobj
= o
->ptr
;
4870 zskiplist
*zsl
= zsetobj
->zsl
;
4873 unsigned int rangelen
= 0;
4875 /* Get the first node with the score >= min */
4876 ln
= zslFirstWithScore(zsl
,min
);
4878 /* No element matching the speciifed interval */
4879 addReply(c
,shared
.emptymultibulk
);
4883 /* We don't know in advance how many matching elements there
4884 * are in the list, so we push this object that will represent
4885 * the multi-bulk length in the output buffer, and will "fix"
4887 lenobj
= createObject(REDIS_STRING
,NULL
);
4889 decrRefCount(lenobj
);
4891 while(ln
&& ln
->score
<= max
) {
4894 ln
= ln
->forward
[0];
4897 if (limit
== 0) break;
4899 addReplyBulkLen(c
,ele
);
4901 addReply(c
,shared
.crlf
);
4902 ln
= ln
->forward
[0];
4904 if (limit
> 0) limit
--;
4906 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%d\r\n",rangelen
);
4911 static void zcardCommand(redisClient
*c
) {
4915 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4917 addReply(c
,shared
.czero
);
4920 if (o
->type
!= REDIS_ZSET
) {
4921 addReply(c
,shared
.wrongtypeerr
);
4924 addReplySds(c
,sdscatprintf(sdsempty(),":%lu\r\n",zs
->zsl
->length
));
4929 static void zscoreCommand(redisClient
*c
) {
4933 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4935 addReply(c
,shared
.nullbulk
);
4938 if (o
->type
!= REDIS_ZSET
) {
4939 addReply(c
,shared
.wrongtypeerr
);
4944 de
= dictFind(zs
->dict
,c
->argv
[2]);
4946 addReply(c
,shared
.nullbulk
);
4948 double *score
= dictGetEntryVal(de
);
4950 addReplyDouble(c
,*score
);
4956 /* ========================= Non type-specific commands ==================== */
4958 static void flushdbCommand(redisClient
*c
) {
4959 server
.dirty
+= dictSize(c
->db
->dict
);
4960 dictEmpty(c
->db
->dict
);
4961 dictEmpty(c
->db
->expires
);
4962 addReply(c
,shared
.ok
);
4965 static void flushallCommand(redisClient
*c
) {
4966 server
.dirty
+= emptyDb();
4967 addReply(c
,shared
.ok
);
4968 rdbSave(server
.dbfilename
);
4972 static redisSortOperation
*createSortOperation(int type
, robj
*pattern
) {
4973 redisSortOperation
*so
= zmalloc(sizeof(*so
));
4975 so
->pattern
= pattern
;
4979 /* Return the value associated to the key with a name obtained
4980 * substituting the first occurence of '*' in 'pattern' with 'subst' */
4981 static robj
*lookupKeyByPattern(redisDb
*db
, robj
*pattern
, robj
*subst
) {
4985 int prefixlen
, sublen
, postfixlen
;
4986 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
4990 char buf
[REDIS_SORTKEY_MAX
+1];
4993 /* If the pattern is "#" return the substitution object itself in order
4994 * to implement the "SORT ... GET #" feature. */
4995 spat
= pattern
->ptr
;
4996 if (spat
[0] == '#' && spat
[1] == '\0') {
5000 /* The substitution object may be specially encoded. If so we create
5001 * a decoded object on the fly. Otherwise getDecodedObject will just
5002 * increment the ref count, that we'll decrement later. */
5003 subst
= getDecodedObject(subst
);
5006 if (sdslen(spat
)+sdslen(ssub
)-1 > REDIS_SORTKEY_MAX
) return NULL
;
5007 p
= strchr(spat
,'*');
5009 decrRefCount(subst
);
5014 sublen
= sdslen(ssub
);
5015 postfixlen
= sdslen(spat
)-(prefixlen
+1);
5016 memcpy(keyname
.buf
,spat
,prefixlen
);
5017 memcpy(keyname
.buf
+prefixlen
,ssub
,sublen
);
5018 memcpy(keyname
.buf
+prefixlen
+sublen
,p
+1,postfixlen
);
5019 keyname
.buf
[prefixlen
+sublen
+postfixlen
] = '\0';
5020 keyname
.len
= prefixlen
+sublen
+postfixlen
;
5022 initStaticStringObject(keyobj
,((char*)&keyname
)+(sizeof(long)*2))
5023 decrRefCount(subst
);
5025 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
5026 return lookupKeyRead(db
,&keyobj
);
5029 /* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
5030 * the additional parameter is not standard but a BSD-specific we have to
5031 * pass sorting parameters via the global 'server' structure */
5032 static int sortCompare(const void *s1
, const void *s2
) {
5033 const redisSortObject
*so1
= s1
, *so2
= s2
;
5036 if (!server
.sort_alpha
) {
5037 /* Numeric sorting. Here it's trivial as we precomputed scores */
5038 if (so1
->u
.score
> so2
->u
.score
) {
5040 } else if (so1
->u
.score
< so2
->u
.score
) {
5046 /* Alphanumeric sorting */
5047 if (server
.sort_bypattern
) {
5048 if (!so1
->u
.cmpobj
|| !so2
->u
.cmpobj
) {
5049 /* At least one compare object is NULL */
5050 if (so1
->u
.cmpobj
== so2
->u
.cmpobj
)
5052 else if (so1
->u
.cmpobj
== NULL
)
5057 /* We have both the objects, use strcoll */
5058 cmp
= strcoll(so1
->u
.cmpobj
->ptr
,so2
->u
.cmpobj
->ptr
);
5061 /* Compare elements directly */
5064 dec1
= getDecodedObject(so1
->obj
);
5065 dec2
= getDecodedObject(so2
->obj
);
5066 cmp
= strcoll(dec1
->ptr
,dec2
->ptr
);
5071 return server
.sort_desc
? -cmp
: cmp
;
5074 /* The SORT command is the most complex command in Redis. Warning: this code
5075 * is optimized for speed and a bit less for readability */
5076 static void sortCommand(redisClient
*c
) {
5079 int desc
= 0, alpha
= 0;
5080 int limit_start
= 0, limit_count
= -1, start
, end
;
5081 int j
, dontsort
= 0, vectorlen
;
5082 int getop
= 0; /* GET operation counter */
5083 robj
*sortval
, *sortby
= NULL
, *storekey
= NULL
;
5084 redisSortObject
*vector
; /* Resulting vector to sort */
5086 /* Lookup the key to sort. It must be of the right types */
5087 sortval
= lookupKeyRead(c
->db
,c
->argv
[1]);
5088 if (sortval
== NULL
) {
5089 addReply(c
,shared
.nullmultibulk
);
5092 if (sortval
->type
!= REDIS_SET
&& sortval
->type
!= REDIS_LIST
&&
5093 sortval
->type
!= REDIS_ZSET
)
5095 addReply(c
,shared
.wrongtypeerr
);
5099 /* Create a list of operations to perform for every sorted element.
5100 * Operations can be GET/DEL/INCR/DECR */
5101 operations
= listCreate();
5102 listSetFreeMethod(operations
,zfree
);
5105 /* Now we need to protect sortval incrementing its count, in the future
5106 * SORT may have options able to overwrite/delete keys during the sorting
5107 * and the sorted key itself may get destroied */
5108 incrRefCount(sortval
);
5110 /* The SORT command has an SQL-alike syntax, parse it */
5111 while(j
< c
->argc
) {
5112 int leftargs
= c
->argc
-j
-1;
5113 if (!strcasecmp(c
->argv
[j
]->ptr
,"asc")) {
5115 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"desc")) {
5117 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"alpha")) {
5119 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"limit") && leftargs
>= 2) {
5120 limit_start
= atoi(c
->argv
[j
+1]->ptr
);
5121 limit_count
= atoi(c
->argv
[j
+2]->ptr
);
5123 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"store") && leftargs
>= 1) {
5124 storekey
= c
->argv
[j
+1];
5126 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"by") && leftargs
>= 1) {
5127 sortby
= c
->argv
[j
+1];
5128 /* If the BY pattern does not contain '*', i.e. it is constant,
5129 * we don't need to sort nor to lookup the weight keys. */
5130 if (strchr(c
->argv
[j
+1]->ptr
,'*') == NULL
) dontsort
= 1;
5132 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
5133 listAddNodeTail(operations
,createSortOperation(
5134 REDIS_SORT_GET
,c
->argv
[j
+1]));
5138 decrRefCount(sortval
);
5139 listRelease(operations
);
5140 addReply(c
,shared
.syntaxerr
);
5146 /* Load the sorting vector with all the objects to sort */
5147 switch(sortval
->type
) {
5148 case REDIS_LIST
: vectorlen
= listLength((list
*)sortval
->ptr
); break;
5149 case REDIS_SET
: vectorlen
= dictSize((dict
*)sortval
->ptr
); break;
5150 case REDIS_ZSET
: vectorlen
= dictSize(((zset
*)sortval
->ptr
)->dict
); break;
5151 default: vectorlen
= 0; redisAssert(0); /* Avoid GCC warning */
5153 vector
= zmalloc(sizeof(redisSortObject
)*vectorlen
);
5156 if (sortval
->type
== REDIS_LIST
) {
5157 list
*list
= sortval
->ptr
;
5161 while((ln
= listYield(list
))) {
5162 robj
*ele
= ln
->value
;
5163 vector
[j
].obj
= ele
;
5164 vector
[j
].u
.score
= 0;
5165 vector
[j
].u
.cmpobj
= NULL
;
5173 if (sortval
->type
== REDIS_SET
) {
5176 zset
*zs
= sortval
->ptr
;
5180 di
= dictGetIterator(set
);
5181 while((setele
= dictNext(di
)) != NULL
) {
5182 vector
[j
].obj
= dictGetEntryKey(setele
);
5183 vector
[j
].u
.score
= 0;
5184 vector
[j
].u
.cmpobj
= NULL
;
5187 dictReleaseIterator(di
);
5189 redisAssert(j
== vectorlen
);
5191 /* Now it's time to load the right scores in the sorting vector */
5192 if (dontsort
== 0) {
5193 for (j
= 0; j
< vectorlen
; j
++) {
5197 byval
= lookupKeyByPattern(c
->db
,sortby
,vector
[j
].obj
);
5198 if (!byval
|| byval
->type
!= REDIS_STRING
) continue;
5200 vector
[j
].u
.cmpobj
= getDecodedObject(byval
);
5202 if (byval
->encoding
== REDIS_ENCODING_RAW
) {
5203 vector
[j
].u
.score
= strtod(byval
->ptr
,NULL
);
5205 /* Don't need to decode the object if it's
5206 * integer-encoded (the only encoding supported) so
5207 * far. We can just cast it */
5208 if (byval
->encoding
== REDIS_ENCODING_INT
) {
5209 vector
[j
].u
.score
= (long)byval
->ptr
;
5211 redisAssert(1 != 1);
5216 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_RAW
)
5217 vector
[j
].u
.score
= strtod(vector
[j
].obj
->ptr
,NULL
);
5219 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_INT
)
5220 vector
[j
].u
.score
= (long) vector
[j
].obj
->ptr
;
5222 redisAssert(1 != 1);
5229 /* We are ready to sort the vector... perform a bit of sanity check
5230 * on the LIMIT option too. We'll use a partial version of quicksort. */
5231 start
= (limit_start
< 0) ? 0 : limit_start
;
5232 end
= (limit_count
< 0) ? vectorlen
-1 : start
+limit_count
-1;
5233 if (start
>= vectorlen
) {
5234 start
= vectorlen
-1;
5237 if (end
>= vectorlen
) end
= vectorlen
-1;
5239 if (dontsort
== 0) {
5240 server
.sort_desc
= desc
;
5241 server
.sort_alpha
= alpha
;
5242 server
.sort_bypattern
= sortby
? 1 : 0;
5243 if (sortby
&& (start
!= 0 || end
!= vectorlen
-1))
5244 pqsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
, start
,end
);
5246 qsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
);
5249 /* Send command output to the output buffer, performing the specified
5250 * GET/DEL/INCR/DECR operations if any. */
5251 outputlen
= getop
? getop
*(end
-start
+1) : end
-start
+1;
5252 if (storekey
== NULL
) {
5253 /* STORE option not specified, sent the sorting result to client */
5254 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",outputlen
));
5255 for (j
= start
; j
<= end
; j
++) {
5258 addReplyBulkLen(c
,vector
[j
].obj
);
5259 addReply(c
,vector
[j
].obj
);
5260 addReply(c
,shared
.crlf
);
5262 listRewind(operations
);
5263 while((ln
= listYield(operations
))) {
5264 redisSortOperation
*sop
= ln
->value
;
5265 robj
*val
= lookupKeyByPattern(c
->db
,sop
->pattern
,
5268 if (sop
->type
== REDIS_SORT_GET
) {
5269 if (!val
|| val
->type
!= REDIS_STRING
) {
5270 addReply(c
,shared
.nullbulk
);
5272 addReplyBulkLen(c
,val
);
5274 addReply(c
,shared
.crlf
);
5277 redisAssert(sop
->type
== REDIS_SORT_GET
); /* always fails */
5282 robj
*listObject
= createListObject();
5283 list
*listPtr
= (list
*) listObject
->ptr
;
5285 /* STORE option specified, set the sorting result as a List object */
5286 for (j
= start
; j
<= end
; j
++) {
5289 listAddNodeTail(listPtr
,vector
[j
].obj
);
5290 incrRefCount(vector
[j
].obj
);
5292 listRewind(operations
);
5293 while((ln
= listYield(operations
))) {
5294 redisSortOperation
*sop
= ln
->value
;
5295 robj
*val
= lookupKeyByPattern(c
->db
,sop
->pattern
,
5298 if (sop
->type
== REDIS_SORT_GET
) {
5299 if (!val
|| val
->type
!= REDIS_STRING
) {
5300 listAddNodeTail(listPtr
,createStringObject("",0));
5302 listAddNodeTail(listPtr
,val
);
5306 redisAssert(sop
->type
== REDIS_SORT_GET
); /* always fails */
5310 if (dictReplace(c
->db
->dict
,storekey
,listObject
)) {
5311 incrRefCount(storekey
);
5313 /* Note: we add 1 because the DB is dirty anyway since even if the
5314 * SORT result is empty a new key is set and maybe the old content
5316 server
.dirty
+= 1+outputlen
;
5317 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",outputlen
));
5321 decrRefCount(sortval
);
5322 listRelease(operations
);
5323 for (j
= 0; j
< vectorlen
; j
++) {
5324 if (sortby
&& alpha
&& vector
[j
].u
.cmpobj
)
5325 decrRefCount(vector
[j
].u
.cmpobj
);
5330 /* Create the string returned by the INFO command. This is decoupled
5331 * by the INFO command itself as we need to report the same information
5332 * on memory corruption problems. */
5333 static sds
genRedisInfoString(void) {
5335 time_t uptime
= time(NULL
)-server
.stat_starttime
;
5338 info
= sdscatprintf(sdsempty(),
5339 "redis_version:%s\r\n"
5341 "multiplexing_api:%s\r\n"
5342 "uptime_in_seconds:%ld\r\n"
5343 "uptime_in_days:%ld\r\n"
5344 "connected_clients:%d\r\n"
5345 "connected_slaves:%d\r\n"
5346 "blocked_clients:%d\r\n"
5347 "used_memory:%zu\r\n"
5348 "changes_since_last_save:%lld\r\n"
5349 "bgsave_in_progress:%d\r\n"
5350 "last_save_time:%ld\r\n"
5351 "bgrewriteaof_in_progress:%d\r\n"
5352 "total_connections_received:%lld\r\n"
5353 "total_commands_processed:%lld\r\n"
5356 (sizeof(long) == 8) ? "64" : "32",
5360 listLength(server
.clients
)-listLength(server
.slaves
),
5361 listLength(server
.slaves
),
5362 server
.blockedclients
,
5365 server
.bgsavechildpid
!= -1,
5367 server
.bgrewritechildpid
!= -1,
5368 server
.stat_numconnections
,
5369 server
.stat_numcommands
,
5370 server
.masterhost
== NULL
? "master" : "slave"
5372 if (server
.masterhost
) {
5373 info
= sdscatprintf(info
,
5374 "master_host:%s\r\n"
5375 "master_port:%d\r\n"
5376 "master_link_status:%s\r\n"
5377 "master_last_io_seconds_ago:%d\r\n"
5380 (server
.replstate
== REDIS_REPL_CONNECTED
) ?
5382 server
.master
? ((int)(time(NULL
)-server
.master
->lastinteraction
)) : -1
5385 for (j
= 0; j
< server
.dbnum
; j
++) {
5386 long long keys
, vkeys
;
5388 keys
= dictSize(server
.db
[j
].dict
);
5389 vkeys
= dictSize(server
.db
[j
].expires
);
5390 if (keys
|| vkeys
) {
5391 info
= sdscatprintf(info
, "db%d:keys=%lld,expires=%lld\r\n",
5398 static void infoCommand(redisClient
*c
) {
5399 sds info
= genRedisInfoString();
5400 addReplySds(c
,sdscatprintf(sdsempty(),"$%lu\r\n",
5401 (unsigned long)sdslen(info
)));
5402 addReplySds(c
,info
);
5403 addReply(c
,shared
.crlf
);
5406 static void monitorCommand(redisClient
*c
) {
5407 /* ignore MONITOR if aleady slave or in monitor mode */
5408 if (c
->flags
& REDIS_SLAVE
) return;
5410 c
->flags
|= (REDIS_SLAVE
|REDIS_MONITOR
);
5412 listAddNodeTail(server
.monitors
,c
);
5413 addReply(c
,shared
.ok
);
5416 /* ================================= Expire ================================= */
5417 static int removeExpire(redisDb
*db
, robj
*key
) {
5418 if (dictDelete(db
->expires
,key
) == DICT_OK
) {
5425 static int setExpire(redisDb
*db
, robj
*key
, time_t when
) {
5426 if (dictAdd(db
->expires
,key
,(void*)when
) == DICT_ERR
) {
5434 /* Return the expire time of the specified key, or -1 if no expire
5435 * is associated with this key (i.e. the key is non volatile) */
5436 static time_t getExpire(redisDb
*db
, robj
*key
) {
5439 /* No expire? return ASAP */
5440 if (dictSize(db
->expires
) == 0 ||
5441 (de
= dictFind(db
->expires
,key
)) == NULL
) return -1;
5443 return (time_t) dictGetEntryVal(de
);
5446 static int expireIfNeeded(redisDb
*db
, robj
*key
) {
5450 /* No expire? return ASAP */
5451 if (dictSize(db
->expires
) == 0 ||
5452 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
5454 /* Lookup the expire */
5455 when
= (time_t) dictGetEntryVal(de
);
5456 if (time(NULL
) <= when
) return 0;
5458 /* Delete the key */
5459 dictDelete(db
->expires
,key
);
5460 return dictDelete(db
->dict
,key
) == DICT_OK
;
5463 static int deleteIfVolatile(redisDb
*db
, robj
*key
) {
5466 /* No expire? return ASAP */
5467 if (dictSize(db
->expires
) == 0 ||
5468 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
5470 /* Delete the key */
5472 dictDelete(db
->expires
,key
);
5473 return dictDelete(db
->dict
,key
) == DICT_OK
;
5476 static void expireGenericCommand(redisClient
*c
, robj
*key
, time_t seconds
) {
5479 de
= dictFind(c
->db
->dict
,key
);
5481 addReply(c
,shared
.czero
);
5485 if (deleteKey(c
->db
,key
)) server
.dirty
++;
5486 addReply(c
, shared
.cone
);
5489 time_t when
= time(NULL
)+seconds
;
5490 if (setExpire(c
->db
,key
,when
)) {
5491 addReply(c
,shared
.cone
);
5494 addReply(c
,shared
.czero
);
5500 static void expireCommand(redisClient
*c
) {
5501 expireGenericCommand(c
,c
->argv
[1],strtol(c
->argv
[2]->ptr
,NULL
,10));
5504 static void expireatCommand(redisClient
*c
) {
5505 expireGenericCommand(c
,c
->argv
[1],strtol(c
->argv
[2]->ptr
,NULL
,10)-time(NULL
));
5508 static void ttlCommand(redisClient
*c
) {
5512 expire
= getExpire(c
->db
,c
->argv
[1]);
5514 ttl
= (int) (expire
-time(NULL
));
5515 if (ttl
< 0) ttl
= -1;
5517 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",ttl
));
5520 /* ================================ MULTI/EXEC ============================== */
5522 /* Client state initialization for MULTI/EXEC */
5523 static void initClientMultiState(redisClient
*c
) {
5524 c
->mstate
.commands
= NULL
;
5525 c
->mstate
.count
= 0;
5528 /* Release all the resources associated with MULTI/EXEC state */
5529 static void freeClientMultiState(redisClient
*c
) {
5532 for (j
= 0; j
< c
->mstate
.count
; j
++) {
5534 multiCmd
*mc
= c
->mstate
.commands
+j
;
5536 for (i
= 0; i
< mc
->argc
; i
++)
5537 decrRefCount(mc
->argv
[i
]);
5540 zfree(c
->mstate
.commands
);
5543 /* Add a new command into the MULTI commands queue */
5544 static void queueMultiCommand(redisClient
*c
, struct redisCommand
*cmd
) {
5548 c
->mstate
.commands
= zrealloc(c
->mstate
.commands
,
5549 sizeof(multiCmd
)*(c
->mstate
.count
+1));
5550 mc
= c
->mstate
.commands
+c
->mstate
.count
;
5553 mc
->argv
= zmalloc(sizeof(robj
*)*c
->argc
);
5554 memcpy(mc
->argv
,c
->argv
,sizeof(robj
*)*c
->argc
);
5555 for (j
= 0; j
< c
->argc
; j
++)
5556 incrRefCount(mc
->argv
[j
]);
5560 static void multiCommand(redisClient
*c
) {
5561 c
->flags
|= REDIS_MULTI
;
5562 addReply(c
,shared
.ok
);
5565 static void execCommand(redisClient
*c
) {
5570 if (!(c
->flags
& REDIS_MULTI
)) {
5571 addReplySds(c
,sdsnew("-ERR EXEC without MULTI\r\n"));
5575 orig_argv
= c
->argv
;
5576 orig_argc
= c
->argc
;
5577 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",c
->mstate
.count
));
5578 for (j
= 0; j
< c
->mstate
.count
; j
++) {
5579 c
->argc
= c
->mstate
.commands
[j
].argc
;
5580 c
->argv
= c
->mstate
.commands
[j
].argv
;
5581 call(c
,c
->mstate
.commands
[j
].cmd
);
5583 c
->argv
= orig_argv
;
5584 c
->argc
= orig_argc
;
5585 freeClientMultiState(c
);
5586 initClientMultiState(c
);
5587 c
->flags
&= (~REDIS_MULTI
);
5590 /* =========================== Blocking Operations ========================= */
5592 /* Currently Redis blocking operations support is limited to list POP ops,
5593 * so the current implementation is not fully generic, but it is also not
5594 * completely specific so it will not require a rewrite to support new
5595 * kind of blocking operations in the future.
5597 * Still it's important to note that list blocking operations can be already
5598 * used as a notification mechanism in order to implement other blocking
5599 * operations at application level, so there must be a very strong evidence
5600 * of usefulness and generality before new blocking operations are implemented.
5602 * This is how the current blocking POP works, we use BLPOP as example:
5603 * - If the user calls BLPOP and the key exists and contains a non empty list
5604 * then LPOP is called instead. So BLPOP is semantically the same as LPOP
5605 * if there is not to block.
5606 * - If instead BLPOP is called and the key does not exists or the list is
5607 * empty we need to block. In order to do so we remove the notification for
5608 * new data to read in the client socket (so that we'll not serve new
5609 * requests if the blocking request is not served). Also we put the client
5610 * in a dictionary (db->blockingkeys) mapping keys to a list of clients
5611 * blocking for this keys.
5612 * - If a PUSH operation against a key with blocked clients waiting is
5613 * performed, we serve the first in the list: basically instead to push
5614 * the new element inside the list we return it to the (first / oldest)
5615 * blocking client, unblock the client, and remove it form the list.
5617 * The above comment and the source code should be enough in order to understand
5618 * the implementation and modify / fix it later.
5621 /* Set a client in blocking mode for the specified key, with the specified
5623 static void blockForKeys(redisClient
*c
, robj
**keys
, int numkeys
, time_t timeout
) {
5628 c
->blockingkeys
= zmalloc(sizeof(robj
*)*numkeys
);
5629 c
->blockingkeysnum
= numkeys
;
5630 c
->blockingto
= timeout
;
5631 for (j
= 0; j
< numkeys
; j
++) {
5632 /* Add the key in the client structure, to map clients -> keys */
5633 c
->blockingkeys
[j
] = keys
[j
];
5634 incrRefCount(keys
[j
]);
5636 /* And in the other "side", to map keys -> clients */
5637 de
= dictFind(c
->db
->blockingkeys
,keys
[j
]);
5641 /* For every key we take a list of clients blocked for it */
5643 retval
= dictAdd(c
->db
->blockingkeys
,keys
[j
],l
);
5644 incrRefCount(keys
[j
]);
5645 assert(retval
== DICT_OK
);
5647 l
= dictGetEntryVal(de
);
5649 listAddNodeTail(l
,c
);
5651 /* Mark the client as a blocked client */
5652 c
->flags
|= REDIS_BLOCKED
;
5653 aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
);
5654 server
.blockedclients
++;
5657 /* Unblock a client that's waiting in a blocking operation such as BLPOP */
5658 static void unblockClient(redisClient
*c
) {
5663 assert(c
->blockingkeys
!= NULL
);
5664 /* The client may wait for multiple keys, so unblock it for every key. */
5665 for (j
= 0; j
< c
->blockingkeysnum
; j
++) {
5666 /* Remove this client from the list of clients waiting for this key. */
5667 de
= dictFind(c
->db
->blockingkeys
,c
->blockingkeys
[j
]);
5669 l
= dictGetEntryVal(de
);
5670 listDelNode(l
,listSearchKey(l
,c
));
5671 /* If the list is empty we need to remove it to avoid wasting memory */
5672 if (listLength(l
) == 0)
5673 dictDelete(c
->db
->blockingkeys
,c
->blockingkeys
[j
]);
5674 decrRefCount(c
->blockingkeys
[j
]);
5676 /* Cleanup the client structure */
5677 zfree(c
->blockingkeys
);
5678 c
->blockingkeys
= NULL
;
5679 c
->flags
&= (~REDIS_BLOCKED
);
5680 server
.blockedclients
--;
5681 /* Ok now we are ready to get read events from socket, note that we
5682 * can't trap errors here as it's possible that unblockClients() is
5683 * called from freeClient() itself, and the only thing we can do
5684 * if we failed to register the READABLE event is to kill the client.
5685 * Still the following function should never fail in the real world as
5686 * we are sure the file descriptor is sane, and we exit on out of mem. */
5687 aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
, readQueryFromClient
, c
);
5688 /* As a final step we want to process data if there is some command waiting
5689 * in the input buffer. Note that this is safe even if unblockClient()
5690 * gets called from freeClient() because freeClient() will be smart
5691 * enough to call this function *after* c->querybuf was set to NULL. */
5692 if (c
->querybuf
&& sdslen(c
->querybuf
) > 0) processInputBuffer(c
);
5695 /* This should be called from any function PUSHing into lists.
5696 * 'c' is the "pushing client", 'key' is the key it is pushing data against,
5697 * 'ele' is the element pushed.
5699 * If the function returns 0 there was no client waiting for a list push
5702 * If the function returns 1 there was a client waiting for a list push
5703 * against this key, the element was passed to this client thus it's not
5704 * needed to actually add it to the list and the caller should return asap. */
5705 static int handleClientsWaitingListPush(redisClient
*c
, robj
*key
, robj
*ele
) {
5706 struct dictEntry
*de
;
5707 redisClient
*receiver
;
5711 de
= dictFind(c
->db
->blockingkeys
,key
);
5712 if (de
== NULL
) return 0;
5713 l
= dictGetEntryVal(de
);
5716 receiver
= ln
->value
;
5718 addReplySds(receiver
,sdsnew("*2\r\n"));
5719 addReplyBulkLen(receiver
,key
);
5720 addReply(receiver
,key
);
5721 addReply(receiver
,shared
.crlf
);
5722 addReplyBulkLen(receiver
,ele
);
5723 addReply(receiver
,ele
);
5724 addReply(receiver
,shared
.crlf
);
5725 unblockClient(receiver
);
5729 /* Blocking RPOP/LPOP */
5730 static void blockingPopGenericCommand(redisClient
*c
, int where
) {
5735 for (j
= 1; j
< c
->argc
-1; j
++) {
5736 o
= lookupKeyWrite(c
->db
,c
->argv
[j
]);
5738 if (o
->type
!= REDIS_LIST
) {
5739 addReply(c
,shared
.wrongtypeerr
);
5742 list
*list
= o
->ptr
;
5743 if (listLength(list
) != 0) {
5744 /* If the list contains elements fall back to the usual
5745 * non-blocking POP operation */
5746 robj
*argv
[2], **orig_argv
;
5749 /* We need to alter the command arguments before to call
5750 * popGenericCommand() as the command takes a single key. */
5751 orig_argv
= c
->argv
;
5752 orig_argc
= c
->argc
;
5753 argv
[1] = c
->argv
[j
];
5757 /* Also the return value is different, we need to output
5758 * the multi bulk reply header and the key name. The
5759 * "real" command will add the last element (the value)
5760 * for us. If this souds like an hack to you it's just
5761 * because it is... */
5762 addReplySds(c
,sdsnew("*2\r\n"));
5763 addReplyBulkLen(c
,argv
[1]);
5764 addReply(c
,argv
[1]);
5765 addReply(c
,shared
.crlf
);
5766 popGenericCommand(c
,where
);
5768 /* Fix the client structure with the original stuff */
5769 c
->argv
= orig_argv
;
5770 c
->argc
= orig_argc
;
5776 /* If the list is empty or the key does not exists we must block */
5777 timeout
= strtol(c
->argv
[c
->argc
-1]->ptr
,NULL
,10);
5778 if (timeout
> 0) timeout
+= time(NULL
);
5779 blockForKeys(c
,c
->argv
+1,c
->argc
-2,timeout
);
5782 static void blpopCommand(redisClient
*c
) {
5783 blockingPopGenericCommand(c
,REDIS_HEAD
);
5786 static void brpopCommand(redisClient
*c
) {
5787 blockingPopGenericCommand(c
,REDIS_TAIL
);
5790 /* =============================== Replication ============================= */
5792 static int syncWrite(int fd
, char *ptr
, ssize_t size
, int timeout
) {
5793 ssize_t nwritten
, ret
= size
;
5794 time_t start
= time(NULL
);
5798 if (aeWait(fd
,AE_WRITABLE
,1000) & AE_WRITABLE
) {
5799 nwritten
= write(fd
,ptr
,size
);
5800 if (nwritten
== -1) return -1;
5804 if ((time(NULL
)-start
) > timeout
) {
5812 static int syncRead(int fd
, char *ptr
, ssize_t size
, int timeout
) {
5813 ssize_t nread
, totread
= 0;
5814 time_t start
= time(NULL
);
5818 if (aeWait(fd
,AE_READABLE
,1000) & AE_READABLE
) {
5819 nread
= read(fd
,ptr
,size
);
5820 if (nread
== -1) return -1;
5825 if ((time(NULL
)-start
) > timeout
) {
5833 static int syncReadLine(int fd
, char *ptr
, ssize_t size
, int timeout
) {
5840 if (syncRead(fd
,&c
,1,timeout
) == -1) return -1;
5843 if (nread
&& *(ptr
-1) == '\r') *(ptr
-1) = '\0';
5854 static void syncCommand(redisClient
*c
) {
5855 /* ignore SYNC if aleady slave or in monitor mode */
5856 if (c
->flags
& REDIS_SLAVE
) return;
5858 /* SYNC can't be issued when the server has pending data to send to
5859 * the client about already issued commands. We need a fresh reply
5860 * buffer registering the differences between the BGSAVE and the current
5861 * dataset, so that we can copy to other slaves if needed. */
5862 if (listLength(c
->reply
) != 0) {
5863 addReplySds(c
,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
5867 redisLog(REDIS_NOTICE
,"Slave ask for synchronization");
5868 /* Here we need to check if there is a background saving operation
5869 * in progress, or if it is required to start one */
5870 if (server
.bgsavechildpid
!= -1) {
5871 /* Ok a background save is in progress. Let's check if it is a good
5872 * one for replication, i.e. if there is another slave that is
5873 * registering differences since the server forked to save */
5877 listRewind(server
.slaves
);
5878 while((ln
= listYield(server
.slaves
))) {
5880 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) break;
5883 /* Perfect, the server is already registering differences for
5884 * another slave. Set the right state, and copy the buffer. */
5885 listRelease(c
->reply
);
5886 c
->reply
= listDup(slave
->reply
);
5887 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
5888 redisLog(REDIS_NOTICE
,"Waiting for end of BGSAVE for SYNC");
5890 /* No way, we need to wait for the next BGSAVE in order to
5891 * register differences */
5892 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
5893 redisLog(REDIS_NOTICE
,"Waiting for next BGSAVE for SYNC");
5896 /* Ok we don't have a BGSAVE in progress, let's start one */
5897 redisLog(REDIS_NOTICE
,"Starting BGSAVE for SYNC");
5898 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
5899 redisLog(REDIS_NOTICE
,"Replication failed, can't BGSAVE");
5900 addReplySds(c
,sdsnew("-ERR Unalbe to perform background save\r\n"));
5903 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
5906 c
->flags
|= REDIS_SLAVE
;
5908 listAddNodeTail(server
.slaves
,c
);
5912 static void sendBulkToSlave(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
5913 redisClient
*slave
= privdata
;
5915 REDIS_NOTUSED(mask
);
5916 char buf
[REDIS_IOBUF_LEN
];
5917 ssize_t nwritten
, buflen
;
5919 if (slave
->repldboff
== 0) {
5920 /* Write the bulk write count before to transfer the DB. In theory here
5921 * we don't know how much room there is in the output buffer of the
5922 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
5923 * operations) will never be smaller than the few bytes we need. */
5926 bulkcount
= sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
5928 if (write(fd
,bulkcount
,sdslen(bulkcount
)) != (signed)sdslen(bulkcount
))
5936 lseek(slave
->repldbfd
,slave
->repldboff
,SEEK_SET
);
5937 buflen
= read(slave
->repldbfd
,buf
,REDIS_IOBUF_LEN
);
5939 redisLog(REDIS_WARNING
,"Read error sending DB to slave: %s",
5940 (buflen
== 0) ? "premature EOF" : strerror(errno
));
5944 if ((nwritten
= write(fd
,buf
,buflen
)) == -1) {
5945 redisLog(REDIS_DEBUG
,"Write error sending DB to slave: %s",
5950 slave
->repldboff
+= nwritten
;
5951 if (slave
->repldboff
== slave
->repldbsize
) {
5952 close(slave
->repldbfd
);
5953 slave
->repldbfd
= -1;
5954 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
5955 slave
->replstate
= REDIS_REPL_ONLINE
;
5956 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
,
5957 sendReplyToClient
, slave
) == AE_ERR
) {
5961 addReplySds(slave
,sdsempty());
5962 redisLog(REDIS_NOTICE
,"Synchronization with slave succeeded");
5966 /* This function is called at the end of every backgrond saving.
5967 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
5968 * otherwise REDIS_ERR is passed to the function.
5970 * The goal of this function is to handle slaves waiting for a successful
5971 * background saving in order to perform non-blocking synchronization. */
5972 static void updateSlavesWaitingBgsave(int bgsaveerr
) {
5974 int startbgsave
= 0;
5976 listRewind(server
.slaves
);
5977 while((ln
= listYield(server
.slaves
))) {
5978 redisClient
*slave
= ln
->value
;
5980 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) {
5982 slave
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
5983 } else if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) {
5984 struct redis_stat buf
;
5986 if (bgsaveerr
!= REDIS_OK
) {
5988 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE child returned an error");
5991 if ((slave
->repldbfd
= open(server
.dbfilename
,O_RDONLY
)) == -1 ||
5992 redis_fstat(slave
->repldbfd
,&buf
) == -1) {
5994 redisLog(REDIS_WARNING
,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno
));
5997 slave
->repldboff
= 0;
5998 slave
->repldbsize
= buf
.st_size
;
5999 slave
->replstate
= REDIS_REPL_SEND_BULK
;
6000 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
6001 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
, sendBulkToSlave
, slave
) == AE_ERR
) {
6008 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
6009 listRewind(server
.slaves
);
6010 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE failed");
6011 while((ln
= listYield(server
.slaves
))) {
6012 redisClient
*slave
= ln
->value
;
6014 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
)
6021 static int syncWithMaster(void) {
6022 char buf
[1024], tmpfile
[256], authcmd
[1024];
6024 int fd
= anetTcpConnect(NULL
,server
.masterhost
,server
.masterport
);
6028 redisLog(REDIS_WARNING
,"Unable to connect to MASTER: %s",
6033 /* AUTH with the master if required. */
6034 if(server
.masterauth
) {
6035 snprintf(authcmd
, 1024, "AUTH %s\r\n", server
.masterauth
);
6036 if (syncWrite(fd
, authcmd
, strlen(server
.masterauth
)+7, 5) == -1) {
6038 redisLog(REDIS_WARNING
,"Unable to AUTH to MASTER: %s",
6042 /* Read the AUTH result. */
6043 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
6045 redisLog(REDIS_WARNING
,"I/O error reading auth result from MASTER: %s",
6049 if (buf
[0] != '+') {
6051 redisLog(REDIS_WARNING
,"Cannot AUTH to MASTER, is the masterauth password correct?");
6056 /* Issue the SYNC command */
6057 if (syncWrite(fd
,"SYNC \r\n",7,5) == -1) {
6059 redisLog(REDIS_WARNING
,"I/O error writing to MASTER: %s",
6063 /* Read the bulk write count */
6064 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
6066 redisLog(REDIS_WARNING
,"I/O error reading bulk count from MASTER: %s",
6070 if (buf
[0] != '$') {
6072 redisLog(REDIS_WARNING
,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
6075 dumpsize
= atoi(buf
+1);
6076 redisLog(REDIS_NOTICE
,"Receiving %d bytes data dump from MASTER",dumpsize
);
6077 /* Read the bulk write data on a temp file */
6078 snprintf(tmpfile
,256,"temp-%d.%ld.rdb",(int)time(NULL
),(long int)random());
6079 dfd
= open(tmpfile
,O_CREAT
|O_WRONLY
,0644);
6082 redisLog(REDIS_WARNING
,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno
));
6086 int nread
, nwritten
;
6088 nread
= read(fd
,buf
,(dumpsize
< 1024)?dumpsize
:1024);
6090 redisLog(REDIS_WARNING
,"I/O error trying to sync with MASTER: %s",
6096 nwritten
= write(dfd
,buf
,nread
);
6097 if (nwritten
== -1) {
6098 redisLog(REDIS_WARNING
,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno
));
6106 if (rename(tmpfile
,server
.dbfilename
) == -1) {
6107 redisLog(REDIS_WARNING
,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno
));
6113 if (rdbLoad(server
.dbfilename
) != REDIS_OK
) {
6114 redisLog(REDIS_WARNING
,"Failed trying to load the MASTER synchronization DB from disk");
6118 server
.master
= createClient(fd
);
6119 server
.master
->flags
|= REDIS_MASTER
;
6120 server
.master
->authenticated
= 1;
6121 server
.replstate
= REDIS_REPL_CONNECTED
;
6125 static void slaveofCommand(redisClient
*c
) {
6126 if (!strcasecmp(c
->argv
[1]->ptr
,"no") &&
6127 !strcasecmp(c
->argv
[2]->ptr
,"one")) {
6128 if (server
.masterhost
) {
6129 sdsfree(server
.masterhost
);
6130 server
.masterhost
= NULL
;
6131 if (server
.master
) freeClient(server
.master
);
6132 server
.replstate
= REDIS_REPL_NONE
;
6133 redisLog(REDIS_NOTICE
,"MASTER MODE enabled (user request)");
6136 sdsfree(server
.masterhost
);
6137 server
.masterhost
= sdsdup(c
->argv
[1]->ptr
);
6138 server
.masterport
= atoi(c
->argv
[2]->ptr
);
6139 if (server
.master
) freeClient(server
.master
);
6140 server
.replstate
= REDIS_REPL_CONNECT
;
6141 redisLog(REDIS_NOTICE
,"SLAVE OF %s:%d enabled (user request)",
6142 server
.masterhost
, server
.masterport
);
6144 addReply(c
,shared
.ok
);
6147 /* ============================ Maxmemory directive ======================== */
6149 /* This function gets called when 'maxmemory' is set on the config file to limit
6150 * the max memory used by the server, and we are out of memory.
6151 * This function will try to, in order:
6153 * - Free objects from the free list
6154 * - Try to remove keys with an EXPIRE set
6156 * It is not possible to free enough memory to reach used-memory < maxmemory
6157 * the server will start refusing commands that will enlarge even more the
6160 static void freeMemoryIfNeeded(void) {
6161 while (server
.maxmemory
&& zmalloc_used_memory() > server
.maxmemory
) {
6162 if (listLength(server
.objfreelist
)) {
6165 listNode
*head
= listFirst(server
.objfreelist
);
6166 o
= listNodeValue(head
);
6167 listDelNode(server
.objfreelist
,head
);
6170 int j
, k
, freed
= 0;
6172 for (j
= 0; j
< server
.dbnum
; j
++) {
6174 robj
*minkey
= NULL
;
6175 struct dictEntry
*de
;
6177 if (dictSize(server
.db
[j
].expires
)) {
6179 /* From a sample of three keys drop the one nearest to
6180 * the natural expire */
6181 for (k
= 0; k
< 3; k
++) {
6184 de
= dictGetRandomKey(server
.db
[j
].expires
);
6185 t
= (time_t) dictGetEntryVal(de
);
6186 if (minttl
== -1 || t
< minttl
) {
6187 minkey
= dictGetEntryKey(de
);
6191 deleteKey(server
.db
+j
,minkey
);
6194 if (!freed
) return; /* nothing to free... */
6199 /* ============================== Append Only file ========================== */
6201 static void feedAppendOnlyFile(struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
) {
6202 sds buf
= sdsempty();
6208 /* The DB this command was targetting is not the same as the last command
6209 * we appendend. To issue a SELECT command is needed. */
6210 if (dictid
!= server
.appendseldb
) {
6213 snprintf(seldb
,sizeof(seldb
),"%d",dictid
);
6214 buf
= sdscatprintf(buf
,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
6215 (unsigned long)strlen(seldb
),seldb
);
6216 server
.appendseldb
= dictid
;
6219 /* "Fix" the argv vector if the command is EXPIRE. We want to translate
6220 * EXPIREs into EXPIREATs calls */
6221 if (cmd
->proc
== expireCommand
) {
6224 tmpargv
[0] = createStringObject("EXPIREAT",8);
6225 tmpargv
[1] = argv
[1];
6226 incrRefCount(argv
[1]);
6227 when
= time(NULL
)+strtol(argv
[2]->ptr
,NULL
,10);
6228 tmpargv
[2] = createObject(REDIS_STRING
,
6229 sdscatprintf(sdsempty(),"%ld",when
));
6233 /* Append the actual command */
6234 buf
= sdscatprintf(buf
,"*%d\r\n",argc
);
6235 for (j
= 0; j
< argc
; j
++) {
6238 o
= getDecodedObject(o
);
6239 buf
= sdscatprintf(buf
,"$%lu\r\n",(unsigned long)sdslen(o
->ptr
));
6240 buf
= sdscatlen(buf
,o
->ptr
,sdslen(o
->ptr
));
6241 buf
= sdscatlen(buf
,"\r\n",2);
6245 /* Free the objects from the modified argv for EXPIREAT */
6246 if (cmd
->proc
== expireCommand
) {
6247 for (j
= 0; j
< 3; j
++)
6248 decrRefCount(argv
[j
]);
6251 /* We want to perform a single write. This should be guaranteed atomic
6252 * at least if the filesystem we are writing is a real physical one.
6253 * While this will save us against the server being killed I don't think
6254 * there is much to do about the whole server stopping for power problems
6256 nwritten
= write(server
.appendfd
,buf
,sdslen(buf
));
6257 if (nwritten
!= (signed)sdslen(buf
)) {
6258 /* Ooops, we are in troubles. The best thing to do for now is
6259 * to simply exit instead to give the illusion that everything is
6260 * working as expected. */
6261 if (nwritten
== -1) {
6262 redisLog(REDIS_WARNING
,"Exiting on error writing to the append-only file: %s",strerror(errno
));
6264 redisLog(REDIS_WARNING
,"Exiting on short write while writing to the append-only file: %s",strerror(errno
));
6268 /* If a background append only file rewriting is in progress we want to
6269 * accumulate the differences between the child DB and the current one
6270 * in a buffer, so that when the child process will do its work we
6271 * can append the differences to the new append only file. */
6272 if (server
.bgrewritechildpid
!= -1)
6273 server
.bgrewritebuf
= sdscatlen(server
.bgrewritebuf
,buf
,sdslen(buf
));
6277 if (server
.appendfsync
== APPENDFSYNC_ALWAYS
||
6278 (server
.appendfsync
== APPENDFSYNC_EVERYSEC
&&
6279 now
-server
.lastfsync
> 1))
6281 fsync(server
.appendfd
); /* Let's try to get this data on the disk */
6282 server
.lastfsync
= now
;
6286 /* In Redis commands are always executed in the context of a client, so in
6287 * order to load the append only file we need to create a fake client. */
6288 static struct redisClient
*createFakeClient(void) {
6289 struct redisClient
*c
= zmalloc(sizeof(*c
));
6293 c
->querybuf
= sdsempty();
6297 /* We set the fake client as a slave waiting for the synchronization
6298 * so that Redis will not try to send replies to this client. */
6299 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
6300 c
->reply
= listCreate();
6301 listSetFreeMethod(c
->reply
,decrRefCount
);
6302 listSetDupMethod(c
->reply
,dupClientReplyValue
);
6306 static void freeFakeClient(struct redisClient
*c
) {
6307 sdsfree(c
->querybuf
);
6308 listRelease(c
->reply
);
6312 /* Replay the append log file. On error REDIS_OK is returned. On non fatal
6313 * error (the append only file is zero-length) REDIS_ERR is returned. On
6314 * fatal error an error message is logged and the program exists. */
6315 int loadAppendOnlyFile(char *filename
) {
6316 struct redisClient
*fakeClient
;
6317 FILE *fp
= fopen(filename
,"r");
6318 struct redis_stat sb
;
6320 if (redis_fstat(fileno(fp
),&sb
) != -1 && sb
.st_size
== 0)
6324 redisLog(REDIS_WARNING
,"Fatal error: can't open the append log file for reading: %s",strerror(errno
));
6328 fakeClient
= createFakeClient();
6335 struct redisCommand
*cmd
;
6337 if (fgets(buf
,sizeof(buf
),fp
) == NULL
) {
6343 if (buf
[0] != '*') goto fmterr
;
6345 argv
= zmalloc(sizeof(robj
*)*argc
);
6346 for (j
= 0; j
< argc
; j
++) {
6347 if (fgets(buf
,sizeof(buf
),fp
) == NULL
) goto readerr
;
6348 if (buf
[0] != '$') goto fmterr
;
6349 len
= strtol(buf
+1,NULL
,10);
6350 argsds
= sdsnewlen(NULL
,len
);
6351 if (len
&& fread(argsds
,len
,1,fp
) == 0) goto fmterr
;
6352 argv
[j
] = createObject(REDIS_STRING
,argsds
);
6353 if (fread(buf
,2,1,fp
) == 0) goto fmterr
; /* discard CRLF */
6356 /* Command lookup */
6357 cmd
= lookupCommand(argv
[0]->ptr
);
6359 redisLog(REDIS_WARNING
,"Unknown command '%s' reading the append only file", argv
[0]->ptr
);
6362 /* Try object sharing and encoding */
6363 if (server
.shareobjects
) {
6365 for(j
= 1; j
< argc
; j
++)
6366 argv
[j
] = tryObjectSharing(argv
[j
]);
6368 if (cmd
->flags
& REDIS_CMD_BULK
)
6369 tryObjectEncoding(argv
[argc
-1]);
6370 /* Run the command in the context of a fake client */
6371 fakeClient
->argc
= argc
;
6372 fakeClient
->argv
= argv
;
6373 cmd
->proc(fakeClient
);
6374 /* Discard the reply objects list from the fake client */
6375 while(listLength(fakeClient
->reply
))
6376 listDelNode(fakeClient
->reply
,listFirst(fakeClient
->reply
));
6377 /* Clean up, ready for the next command */
6378 for (j
= 0; j
< argc
; j
++) decrRefCount(argv
[j
]);
6382 freeFakeClient(fakeClient
);
6387 redisLog(REDIS_WARNING
,"Unexpected end of file reading the append only file");
6389 redisLog(REDIS_WARNING
,"Unrecoverable error reading the append only file: %s", strerror(errno
));
6393 redisLog(REDIS_WARNING
,"Bad file format reading the append only file");
6397 /* Write an object into a file in the bulk format $<count>\r\n<payload>\r\n */
6398 static int fwriteBulk(FILE *fp
, robj
*obj
) {
6400 obj
= getDecodedObject(obj
);
6401 snprintf(buf
,sizeof(buf
),"$%ld\r\n",(long)sdslen(obj
->ptr
));
6402 if (fwrite(buf
,strlen(buf
),1,fp
) == 0) goto err
;
6403 if (sdslen(obj
->ptr
) && fwrite(obj
->ptr
,sdslen(obj
->ptr
),1,fp
) == 0)
6405 if (fwrite("\r\n",2,1,fp
) == 0) goto err
;
6413 /* Write a double value in bulk format $<count>\r\n<payload>\r\n */
6414 static int fwriteBulkDouble(FILE *fp
, double d
) {
6415 char buf
[128], dbuf
[128];
6417 snprintf(dbuf
,sizeof(dbuf
),"%.17g\r\n",d
);
6418 snprintf(buf
,sizeof(buf
),"$%lu\r\n",(unsigned long)strlen(dbuf
)-2);
6419 if (fwrite(buf
,strlen(buf
),1,fp
) == 0) return 0;
6420 if (fwrite(dbuf
,strlen(dbuf
),1,fp
) == 0) return 0;
6424 /* Write a long value in bulk format $<count>\r\n<payload>\r\n */
6425 static int fwriteBulkLong(FILE *fp
, long l
) {
6426 char buf
[128], lbuf
[128];
6428 snprintf(lbuf
,sizeof(lbuf
),"%ld\r\n",l
);
6429 snprintf(buf
,sizeof(buf
),"$%lu\r\n",(unsigned long)strlen(lbuf
)-2);
6430 if (fwrite(buf
,strlen(buf
),1,fp
) == 0) return 0;
6431 if (fwrite(lbuf
,strlen(lbuf
),1,fp
) == 0) return 0;
6435 /* Write a sequence of commands able to fully rebuild the dataset into
6436 * "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
6437 static int rewriteAppendOnlyFile(char *filename
) {
6438 dictIterator
*di
= NULL
;
6443 time_t now
= time(NULL
);
6445 /* Note that we have to use a different temp name here compared to the
6446 * one used by rewriteAppendOnlyFileBackground() function. */
6447 snprintf(tmpfile
,256,"temp-rewriteaof-%d.aof", (int) getpid());
6448 fp
= fopen(tmpfile
,"w");
6450 redisLog(REDIS_WARNING
, "Failed rewriting the append only file: %s", strerror(errno
));
6453 for (j
= 0; j
< server
.dbnum
; j
++) {
6454 char selectcmd
[] = "*2\r\n$6\r\nSELECT\r\n";
6455 redisDb
*db
= server
.db
+j
;
6457 if (dictSize(d
) == 0) continue;
6458 di
= dictGetIterator(d
);
6464 /* SELECT the new DB */
6465 if (fwrite(selectcmd
,sizeof(selectcmd
)-1,1,fp
) == 0) goto werr
;
6466 if (fwriteBulkLong(fp
,j
) == 0) goto werr
;
6468 /* Iterate this DB writing every entry */
6469 while((de
= dictNext(di
)) != NULL
) {
6470 robj
*key
= dictGetEntryKey(de
);
6471 robj
*o
= dictGetEntryVal(de
);
6472 time_t expiretime
= getExpire(db
,key
);
6474 /* Save the key and associated value */
6475 if (o
->type
== REDIS_STRING
) {
6476 /* Emit a SET command */
6477 char cmd
[]="*3\r\n$3\r\nSET\r\n";
6478 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
6480 if (fwriteBulk(fp
,key
) == 0) goto werr
;
6481 if (fwriteBulk(fp
,o
) == 0) goto werr
;
6482 } else if (o
->type
== REDIS_LIST
) {
6483 /* Emit the RPUSHes needed to rebuild the list */
6484 list
*list
= o
->ptr
;
6488 while((ln
= listYield(list
))) {
6489 char cmd
[]="*3\r\n$5\r\nRPUSH\r\n";
6490 robj
*eleobj
= listNodeValue(ln
);
6492 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
6493 if (fwriteBulk(fp
,key
) == 0) goto werr
;
6494 if (fwriteBulk(fp
,eleobj
) == 0) goto werr
;
6496 } else if (o
->type
== REDIS_SET
) {
6497 /* Emit the SADDs needed to rebuild the set */
6499 dictIterator
*di
= dictGetIterator(set
);
6502 while((de
= dictNext(di
)) != NULL
) {
6503 char cmd
[]="*3\r\n$4\r\nSADD\r\n";
6504 robj
*eleobj
= dictGetEntryKey(de
);
6506 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
6507 if (fwriteBulk(fp
,key
) == 0) goto werr
;
6508 if (fwriteBulk(fp
,eleobj
) == 0) goto werr
;
6510 dictReleaseIterator(di
);
6511 } else if (o
->type
== REDIS_ZSET
) {
6512 /* Emit the ZADDs needed to rebuild the sorted set */
6514 dictIterator
*di
= dictGetIterator(zs
->dict
);
6517 while((de
= dictNext(di
)) != NULL
) {
6518 char cmd
[]="*4\r\n$4\r\nZADD\r\n";
6519 robj
*eleobj
= dictGetEntryKey(de
);
6520 double *score
= dictGetEntryVal(de
);
6522 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
6523 if (fwriteBulk(fp
,key
) == 0) goto werr
;
6524 if (fwriteBulkDouble(fp
,*score
) == 0) goto werr
;
6525 if (fwriteBulk(fp
,eleobj
) == 0) goto werr
;
6527 dictReleaseIterator(di
);
6529 redisAssert(0 != 0);
6531 /* Save the expire time */
6532 if (expiretime
!= -1) {
6533 char cmd
[]="*3\r\n$8\r\nEXPIREAT\r\n";
6534 /* If this key is already expired skip it */
6535 if (expiretime
< now
) continue;
6536 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
6537 if (fwriteBulk(fp
,key
) == 0) goto werr
;
6538 if (fwriteBulkLong(fp
,expiretime
) == 0) goto werr
;
6541 dictReleaseIterator(di
);
6544 /* Make sure data will not remain on the OS's output buffers */
6549 /* Use RENAME to make sure the DB file is changed atomically only
6550 * if the generate DB file is ok. */
6551 if (rename(tmpfile
,filename
) == -1) {
6552 redisLog(REDIS_WARNING
,"Error moving temp append only file on the final destination: %s", strerror(errno
));
6556 redisLog(REDIS_NOTICE
,"SYNC append only file rewrite performed");
6562 redisLog(REDIS_WARNING
,"Write error writing append only file on disk: %s", strerror(errno
));
6563 if (di
) dictReleaseIterator(di
);
6567 /* This is how rewriting of the append only file in background works:
6569 * 1) The user calls BGREWRITEAOF
6570 * 2) Redis calls this function, that forks():
6571 * 2a) the child rewrite the append only file in a temp file.
6572 * 2b) the parent accumulates differences in server.bgrewritebuf.
6573 * 3) When the child finished '2a' exists.
6574 * 4) The parent will trap the exit code, if it's OK, will append the
6575 * data accumulated into server.bgrewritebuf into the temp file, and
6576 * finally will rename(2) the temp file in the actual file name.
6577 * The the new file is reopened as the new append only file. Profit!
6579 static int rewriteAppendOnlyFileBackground(void) {
6582 if (server
.bgrewritechildpid
!= -1) return REDIS_ERR
;
6583 if ((childpid
= fork()) == 0) {
6588 snprintf(tmpfile
,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
6589 if (rewriteAppendOnlyFile(tmpfile
) == REDIS_OK
) {
6596 if (childpid
== -1) {
6597 redisLog(REDIS_WARNING
,
6598 "Can't rewrite append only file in background: fork: %s",
6602 redisLog(REDIS_NOTICE
,
6603 "Background append only file rewriting started by pid %d",childpid
);
6604 server
.bgrewritechildpid
= childpid
;
6605 /* We set appendseldb to -1 in order to force the next call to the
6606 * feedAppendOnlyFile() to issue a SELECT command, so the differences
6607 * accumulated by the parent into server.bgrewritebuf will start
6608 * with a SELECT statement and it will be safe to merge. */
6609 server
.appendseldb
= -1;
6612 return REDIS_OK
; /* unreached */
6615 static void bgrewriteaofCommand(redisClient
*c
) {
6616 if (server
.bgrewritechildpid
!= -1) {
6617 addReplySds(c
,sdsnew("-ERR background append only file rewriting already in progress\r\n"));
6620 if (rewriteAppendOnlyFileBackground() == REDIS_OK
) {
6621 char *status
= "+Background append only file rewriting started\r\n";
6622 addReplySds(c
,sdsnew(status
));
6624 addReply(c
,shared
.err
);
6628 static void aofRemoveTempFile(pid_t childpid
) {
6631 snprintf(tmpfile
,256,"temp-rewriteaof-bg-%d.aof", (int) childpid
);
6635 /* =============================== Virtual Memory =========================== */
6636 static void vmInit(void) {
6639 server
.vm_fp
= fopen("/tmp/redisvm","w+b");
6640 if (server
.vm_fp
== NULL
) {
6641 redisLog(REDIS_WARNING
,"Impossible to open the swap file. Exiting.");
6644 server
.vm_fd
= fileno(server
.vm_fp
);
6645 server
.vm_next_page
= 0;
6646 server
.vm_near_pages
= 0;
6647 totsize
= server
.vm_pages
*server
.vm_page_size
;
6648 redisLog(REDIS_NOTICE
,"Allocating %lld bytes of swap file",totsize
);
6649 if (ftruncate(server
.vm_fd
,totsize
) == -1) {
6650 redisLog(REDIS_WARNING
,"Can't ftruncate swap file: %s. Exiting.",
6654 redisLog(REDIS_NOTICE
,"Swap file allocated with success");
6656 server
.vm_bitmap
= zmalloc((server
.vm_pages
+7)/8);
6657 memset(server
.vm_bitmap
,0,(server
.vm_pages
+7)/8);
6658 /* Try to remove the swap file, so the OS will really delete it from the
6659 * file system when Redis exists. */
6660 unlink("/tmp/redisvm");
6663 /* Mark the page as used */
6664 static void vmMarkPageUsed(off_t page
) {
6665 off_t byte
= page
/8;
6667 server
.vm_bitmap
[byte
] |= 1<<bit
;
6668 printf("Mark used: %lld (byte:%d bit:%d)\n", (long long)page
, byte
, bit
);
6671 /* Mark N contiguous pages as used, with 'page' being the first. */
6672 static void vmMarkPagesUsed(off_t page
, off_t count
) {
6675 for (j
= 0; j
< count
; j
++)
6676 vmMarkPageUsed(page
+j
);
6679 /* Mark the page as free */
6680 static void vmMarkPageFree(off_t page
) {
6681 off_t byte
= page
/8;
6683 server
.vm_bitmap
[byte
] &= ~(1<<bit
);
6686 /* Mark N contiguous pages as free, with 'page' being the first. */
6687 static void vmMarkPagesFree(off_t page
, off_t count
) {
6690 for (j
= 0; j
< count
; j
++)
6691 vmMarkPageFree(page
+j
);
6694 /* Test if the page is free */
6695 static int vmFreePage(off_t page
) {
6696 off_t byte
= page
/8;
6698 return (server
.vm_bitmap
[byte
] & (1<<bit
)) == 0;
6701 /* Find N contiguous free pages storing the first page of the cluster in *first.
6702 * Returns REDIS_OK if it was able to find N contiguous pages, otherwise
6703 * REDIS_ERR is returned.
6705 * This function uses a simple algorithm: we try to allocate
6706 * REDIS_VM_MAX_NEAR_PAGES sequentially, when we reach this limit we start
6707 * again from the start of the swap file searching for free spaces.
6709 * If it looks pretty clear that there are no free pages near our offset
6710 * we try to find less populated places doing a forward jump of
6711 * REDIS_VM_MAX_RANDOM_JUMP, then we start scanning again a few pages
6712 * without hurry, and then we jump again and so forth...
6714 * This function can be improved using a free list to avoid to guess
6715 * too much, since we could collect data about freed pages.
6717 * note: I implemented this function just after watching an episode of
6718 * Battlestar Galactica, where the hybrid was continuing to say "JUMP!"
6720 static int vmFindContiguousPages(off_t
*first
, int n
) {
6721 off_t base
, offset
= 0, since_jump
= 0, numfree
= 0;
6723 if (server
.vm_near_pages
== REDIS_VM_MAX_NEAR_PAGES
) {
6724 server
.vm_near_pages
= 0;
6725 server
.vm_next_page
= 0;
6727 server
.vm_near_pages
++; /* Yet another try for pages near to the old ones */
6728 base
= server
.vm_next_page
;
6730 while(offset
< server
.vm_pages
) {
6731 off_t
this = base
+offset
;
6733 printf("THIS: %lld (%c)\n", (long long) this, vmFreePage(this) ? 'F' : 'X');
6734 /* If we overflow, restart from page zero */
6735 if (this >= server
.vm_pages
) {
6736 this -= server
.vm_pages
;
6738 /* Just overflowed, what we found on tail is no longer
6739 * interesting, as it's no longer contiguous. */
6743 if (vmFreePage(this)) {
6744 /* This is a free page */
6746 /* Already got N free pages? Return to the caller, with success */
6748 *first
= this-(n
-1);
6749 server
.vm_next_page
= this+1;
6753 /* The current one is not a free page */
6757 /* Fast-forward if the current page is not free and we already
6758 * searched enough near this place. */
6760 if (!numfree
&& since_jump
>= REDIS_VM_MAX_RANDOM_JUMP
/4) {
6761 offset
+= random() % REDIS_VM_MAX_RANDOM_JUMP
;
6763 /* Note that even if we rewind after the jump, we are don't need
6764 * to make sure numfree is set to zero as we only jump *if* it
6765 * is set to zero. */
6767 /* Otherwise just check the next page */
6774 /* Swap the 'val' object relative to 'key' into disk. Store all the information
6775 * needed to later retrieve the object into the key object.
6776 * If we can't find enough contiguous empty pages to swap the object on disk
6777 * REDIS_ERR is returned. */
6778 static int vmSwapObject(robj
*key
, robj
*val
) {
6779 off_t pages
= rdbSavedObjectPages(val
);
6782 assert(key
->storage
== REDIS_VM_MEMORY
);
6783 if (vmFindContiguousPages(&page
,pages
) == REDIS_ERR
) return REDIS_ERR
;
6784 if (fseeko(server
.vm_fp
,page
*server
.vm_page_size
,SEEK_SET
) == -1) {
6785 redisLog(REDIS_WARNING
,
6786 "Critical VM problem in vmSwapObject(): can't seek: %s",
6790 rdbSaveObject(server
.vm_fp
,val
);
6791 key
->vm
.page
= page
;
6792 key
->vm
.usedpages
= pages
;
6793 key
->storage
= REDIS_VM_SWAPPED
;
6794 decrRefCount(val
); /* Deallocate the object from memory. */
6795 vmMarkPagesUsed(page
,pages
);
6796 redisLog(REDIS_DEBUG
,"VM: object %s swapped out at %lld (%lld pages)",
6797 (unsigned char*) key
->ptr
,
6798 (unsigned long long) page
, (unsigned long long) pages
);
6802 /* Load the value object relative to the 'key' object from swap to memory.
6803 * The newly allocated object is returned. */
6804 static robj
*vmLoadObject(robj
*key
) {
6807 assert(key
->storage
== REDIS_VM_SWAPPED
);
6808 if (fseeko(server
.vm_fp
,key
->vm
.page
*server
.vm_page_size
,SEEK_SET
) == -1) {
6809 redisLog(REDIS_WARNING
,
6810 "Unrecoverable VM problem in vmLoadObject(): can't seek: %s",
6814 val
= rdbLoadObject(key
->type
,server
.vm_fp
);
6816 redisLog(REDIS_WARNING
, "Unrecoverable VM problem in vmLoadObject(): can't load object from swap file: %s", strerror(errno
));
6819 key
->storage
= REDIS_VM_MEMORY
;
6820 key
->vm
.atime
= server
.unixtime
;
6821 vmMarkPagesFree(key
->vm
.page
,key
->vm
.usedpages
);
6822 redisLog(REDIS_DEBUG
, "VM: object %s loaded from disk",
6823 (unsigned char*) key
->ptr
);
6827 /* ================================= Debugging ============================== */
6829 static void debugCommand(redisClient
*c
) {
6830 if (!strcasecmp(c
->argv
[1]->ptr
,"segfault")) {
6832 } else if (!strcasecmp(c
->argv
[1]->ptr
,"reload")) {
6833 if (rdbSave(server
.dbfilename
) != REDIS_OK
) {
6834 addReply(c
,shared
.err
);
6838 if (rdbLoad(server
.dbfilename
) != REDIS_OK
) {
6839 addReply(c
,shared
.err
);
6842 redisLog(REDIS_WARNING
,"DB reloaded by DEBUG RELOAD");
6843 addReply(c
,shared
.ok
);
6844 } else if (!strcasecmp(c
->argv
[1]->ptr
,"loadaof")) {
6846 if (loadAppendOnlyFile(server
.appendfilename
) != REDIS_OK
) {
6847 addReply(c
,shared
.err
);
6850 redisLog(REDIS_WARNING
,"Append Only File loaded by DEBUG LOADAOF");
6851 addReply(c
,shared
.ok
);
6852 } else if (!strcasecmp(c
->argv
[1]->ptr
,"object") && c
->argc
== 3) {
6853 dictEntry
*de
= dictFind(c
->db
->dict
,c
->argv
[2]);
6857 addReply(c
,shared
.nokeyerr
);
6860 key
= dictGetEntryKey(de
);
6861 val
= dictGetEntryVal(de
);
6862 addReplySds(c
,sdscatprintf(sdsempty(),
6863 "+Key at:%p refcount:%d, value at:%p refcount:%d encoding:%d serializedlength:%lld\r\n",
6864 (void*)key
, key
->refcount
, (void*)val
, val
->refcount
,
6865 val
->encoding
, rdbSavedObjectLen(val
)));
6866 } else if (!strcasecmp(c
->argv
[1]->ptr
,"swapout") && c
->argc
== 3) {
6867 dictEntry
*de
= dictFind(c
->db
->dict
,c
->argv
[2]);
6870 if (!server
.vm_enabled
) {
6871 addReplySds(c
,sdsnew("-ERR Virtual Memory is disabled\r\n"));
6875 addReply(c
,shared
.nokeyerr
);
6878 key
= dictGetEntryKey(de
);
6879 val
= dictGetEntryVal(de
);
6880 if (key
->storage
!= REDIS_VM_MEMORY
) {
6881 addReplySds(c
,sdsnew("-ERR This key is not in memory\r\n"));
6882 } else if (vmSwapObject(key
,val
) == REDIS_OK
) {
6883 dictGetEntryVal(de
) = NULL
;
6884 addReply(c
,shared
.ok
);
6886 addReply(c
,shared
.err
);
6889 addReplySds(c
,sdsnew(
6890 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPOUT <key>|RELOAD]\r\n"));
6894 static void _redisAssert(char *estr
) {
6895 redisLog(REDIS_WARNING
,"=== ASSERTION FAILED ===");
6896 redisLog(REDIS_WARNING
,"==> %s\n",estr
);
6897 #ifdef HAVE_BACKTRACE
6898 redisLog(REDIS_WARNING
,"(forcing SIGSEGV in order to print the stack trace)");
6903 /* =================================== Main! ================================ */
6906 int linuxOvercommitMemoryValue(void) {
6907 FILE *fp
= fopen("/proc/sys/vm/overcommit_memory","r");
6911 if (fgets(buf
,64,fp
) == NULL
) {
6920 void linuxOvercommitMemoryWarning(void) {
6921 if (linuxOvercommitMemoryValue() == 0) {
6922 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.");
6925 #endif /* __linux__ */
6927 static void daemonize(void) {
6931 if (fork() != 0) exit(0); /* parent exits */
6932 printf("New pid: %d\n", getpid());
6933 setsid(); /* create a new session */
6935 /* Every output goes to /dev/null. If Redis is daemonized but
6936 * the 'logfile' is set to 'stdout' in the configuration file
6937 * it will not log at all. */
6938 if ((fd
= open("/dev/null", O_RDWR
, 0)) != -1) {
6939 dup2(fd
, STDIN_FILENO
);
6940 dup2(fd
, STDOUT_FILENO
);
6941 dup2(fd
, STDERR_FILENO
);
6942 if (fd
> STDERR_FILENO
) close(fd
);
6944 /* Try to write the pid file */
6945 fp
= fopen(server
.pidfile
,"w");
6947 fprintf(fp
,"%d\n",getpid());
6952 int main(int argc
, char **argv
) {
6955 resetServerSaveParams();
6956 loadServerConfig(argv
[1]);
6957 } else if (argc
> 2) {
6958 fprintf(stderr
,"Usage: ./redis-server [/path/to/redis.conf]\n");
6961 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'");
6963 if (server
.daemonize
) daemonize();
6965 redisLog(REDIS_NOTICE
,"Server started, Redis version " REDIS_VERSION
);
6967 linuxOvercommitMemoryWarning();
6969 if (server
.appendonly
) {
6970 if (loadAppendOnlyFile(server
.appendfilename
) == REDIS_OK
)
6971 redisLog(REDIS_NOTICE
,"DB loaded from append only file");
6973 if (rdbLoad(server
.dbfilename
) == REDIS_OK
)
6974 redisLog(REDIS_NOTICE
,"DB loaded from disk");
6976 if (aeCreateFileEvent(server
.el
, server
.fd
, AE_READABLE
,
6977 acceptHandler
, NULL
) == AE_ERR
) oom("creating file event");
6978 redisLog(REDIS_NOTICE
,"The server is now ready to accept connections on port %d", server
.port
);
6980 aeDeleteEventLoop(server
.el
);
6984 /* ============================= Backtrace support ========================= */
6986 #ifdef HAVE_BACKTRACE
6987 static char *findFuncName(void *pointer
, unsigned long *offset
);
6989 static void *getMcontextEip(ucontext_t
*uc
) {
6990 #if defined(__FreeBSD__)
6991 return (void*) uc
->uc_mcontext
.mc_eip
;
6992 #elif defined(__dietlibc__)
6993 return (void*) uc
->uc_mcontext
.eip
;
6994 #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
6996 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
6998 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
7000 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
7001 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
7002 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
7004 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
7006 #elif defined(__i386__) || defined(__X86_64__) || defined(__x86_64__)
7007 return (void*) uc
->uc_mcontext
.gregs
[REG_EIP
]; /* Linux 32/64 bit */
7008 #elif defined(__ia64__) /* Linux IA64 */
7009 return (void*) uc
->uc_mcontext
.sc_ip
;
7015 static void segvHandler(int sig
, siginfo_t
*info
, void *secret
) {
7017 char **messages
= NULL
;
7018 int i
, trace_size
= 0;
7019 unsigned long offset
=0;
7020 ucontext_t
*uc
= (ucontext_t
*) secret
;
7022 REDIS_NOTUSED(info
);
7024 redisLog(REDIS_WARNING
,
7025 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION
, sig
);
7026 infostring
= genRedisInfoString();
7027 redisLog(REDIS_WARNING
, "%s",infostring
);
7028 /* It's not safe to sdsfree() the returned string under memory
7029 * corruption conditions. Let it leak as we are going to abort */
7031 trace_size
= backtrace(trace
, 100);
7032 /* overwrite sigaction with caller's address */
7033 if (getMcontextEip(uc
) != NULL
) {
7034 trace
[1] = getMcontextEip(uc
);
7036 messages
= backtrace_symbols(trace
, trace_size
);
7038 for (i
=1; i
<trace_size
; ++i
) {
7039 char *fn
= findFuncName(trace
[i
], &offset
), *p
;
7041 p
= strchr(messages
[i
],'+');
7042 if (!fn
|| (p
&& ((unsigned long)strtol(p
+1,NULL
,10)) < offset
)) {
7043 redisLog(REDIS_WARNING
,"%s", messages
[i
]);
7045 redisLog(REDIS_WARNING
,"%d redis-server %p %s + %d", i
, trace
[i
], fn
, (unsigned int)offset
);
7048 /* free(messages); Don't call free() with possibly corrupted memory. */
7052 static void setupSigSegvAction(void) {
7053 struct sigaction act
;
7055 sigemptyset (&act
.sa_mask
);
7056 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
7057 * is used. Otherwise, sa_handler is used */
7058 act
.sa_flags
= SA_NODEFER
| SA_ONSTACK
| SA_RESETHAND
| SA_SIGINFO
;
7059 act
.sa_sigaction
= segvHandler
;
7060 sigaction (SIGSEGV
, &act
, NULL
);
7061 sigaction (SIGBUS
, &act
, NULL
);
7062 sigaction (SIGFPE
, &act
, NULL
);
7063 sigaction (SIGILL
, &act
, NULL
);
7064 sigaction (SIGBUS
, &act
, NULL
);
7068 #include "staticsymbols.h"
7069 /* This function try to convert a pointer into a function name. It's used in
7070 * oreder to provide a backtrace under segmentation fault that's able to
7071 * display functions declared as static (otherwise the backtrace is useless). */
7072 static char *findFuncName(void *pointer
, unsigned long *offset
){
7074 unsigned long off
, minoff
= 0;
7076 /* Try to match against the Symbol with the smallest offset */
7077 for (i
=0; symsTable
[i
].pointer
; i
++) {
7078 unsigned long lp
= (unsigned long) pointer
;
7080 if (lp
!= (unsigned long)-1 && lp
>= symsTable
[i
].pointer
) {
7081 off
=lp
-symsTable
[i
].pointer
;
7082 if (ret
< 0 || off
< minoff
) {
7088 if (ret
== -1) return NULL
;
7090 return symsTable
[ret
].name
;
7092 #else /* HAVE_BACKTRACE */
7093 static void setupSigSegvAction(void) {
7095 #endif /* HAVE_BACKTRACE */