2 * Copyright (c) 2009-2010, 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.8"
40 #define __USE_POSIX199309
47 #endif /* HAVE_BACKTRACE */
55 #include <arpa/inet.h>
59 #include <sys/resource.h>
66 #include "solarisfixes.h"
70 #include "ae.h" /* Event driven programming library */
71 #include "sds.h" /* Dynamic safe strings */
72 #include "anet.h" /* Networking the easy way */
73 #include "dict.h" /* Hash tables */
74 #include "adlist.h" /* Linked lists */
75 #include "zmalloc.h" /* total memory usage aware version of malloc/free */
76 #include "lzf.h" /* LZF compression library */
77 #include "pqsort.h" /* Partial qsort for SORT+LIMIT */
84 /* Static server configuration */
85 #define REDIS_SERVERPORT 6379 /* TCP port */
86 #define REDIS_MAXIDLETIME (60*5) /* default client timeout */
87 #define REDIS_IOBUF_LEN 1024
88 #define REDIS_LOADBUF_LEN 1024
89 #define REDIS_STATIC_ARGS 8
90 #define REDIS_DEFAULT_DBNUM 16
91 #define REDIS_CONFIGLINE_MAX 1024
92 #define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
93 #define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
94 #define REDIS_EXPIRELOOKUPS_PER_CRON 10 /* try to expire 10 keys/loop */
95 #define REDIS_MAX_WRITE_PER_EVENT (1024*64)
96 #define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
98 /* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
99 #define REDIS_WRITEV_THRESHOLD 3
100 /* Max number of iovecs used for each writev call */
101 #define REDIS_WRITEV_IOVEC_COUNT 256
103 /* Hash table parameters */
104 #define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
107 #define REDIS_CMD_BULK 1 /* Bulk write command */
108 #define REDIS_CMD_INLINE 2 /* Inline command */
109 /* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
110 this flags will return an error when the 'maxmemory' option is set in the
111 config file and the server is using more than maxmemory bytes of memory.
112 In short this commands are denied on low memory conditions. */
113 #define REDIS_CMD_DENYOOM 4
114 #define REDIS_CMD_FORCE_REPLICATION 8 /* Force replication even if dirty is 0 */
117 #define REDIS_STRING 0
123 /* Objects encoding. Some kind of objects like Strings and Hashes can be
124 * internally represented in multiple ways. The 'encoding' field of the object
125 * is set to one of this fields for this object. */
126 #define REDIS_ENCODING_RAW 0 /* Raw representation */
127 #define REDIS_ENCODING_INT 1 /* Encoded as integer */
128 #define REDIS_ENCODING_ZIPMAP 2 /* Encoded as zipmap */
129 #define REDIS_ENCODING_HT 3 /* Encoded as an hash table */
131 static char* strencoding
[] = {
132 "raw", "int", "zipmap", "hashtable"
135 /* Object types only used for dumping to disk */
136 #define REDIS_EXPIRETIME 253
137 #define REDIS_SELECTDB 254
138 #define REDIS_EOF 255
140 /* Defines related to the dump file format. To store 32 bits lengths for short
141 * keys requires a lot of space, so we check the most significant 2 bits of
142 * the first byte to interpreter the length:
144 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
145 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
146 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
147 * 11|000000 this means: specially encoded object will follow. The six bits
148 * number specify the kind of object that follows.
149 * See the REDIS_RDB_ENC_* defines.
151 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
152 * values, will fit inside. */
153 #define REDIS_RDB_6BITLEN 0
154 #define REDIS_RDB_14BITLEN 1
155 #define REDIS_RDB_32BITLEN 2
156 #define REDIS_RDB_ENCVAL 3
157 #define REDIS_RDB_LENERR UINT_MAX
159 /* When a length of a string object stored on disk has the first two bits
160 * set, the remaining two bits specify a special encoding for the object
161 * accordingly to the following defines: */
162 #define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
163 #define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
164 #define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
165 #define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
167 /* Virtual memory object->where field. */
168 #define REDIS_VM_MEMORY 0 /* The object is on memory */
169 #define REDIS_VM_SWAPPED 1 /* The object is on disk */
170 #define REDIS_VM_SWAPPING 2 /* Redis is swapping this object on disk */
171 #define REDIS_VM_LOADING 3 /* Redis is loading this object from disk */
173 /* Virtual memory static configuration stuff.
174 * Check vmFindContiguousPages() to know more about this magic numbers. */
175 #define REDIS_VM_MAX_NEAR_PAGES 65536
176 #define REDIS_VM_MAX_RANDOM_JUMP 4096
177 #define REDIS_VM_MAX_THREADS 32
178 #define REDIS_THREAD_STACK_SIZE (1024*1024*4)
179 /* The following is the *percentage* of completed I/O jobs to process when the
180 * handelr is called. While Virtual Memory I/O operations are performed by
181 * threads, this operations must be processed by the main thread when completed
182 * in order to take effect. */
183 #define REDIS_MAX_COMPLETED_JOBS_PROCESSED 1
186 #define REDIS_SLAVE 1 /* This client is a slave server */
187 #define REDIS_MASTER 2 /* This client is a master server */
188 #define REDIS_MONITOR 4 /* This client is a slave monitor, see MONITOR */
189 #define REDIS_MULTI 8 /* This client is in a MULTI context */
190 #define REDIS_BLOCKED 16 /* The client is waiting in a blocking operation */
191 #define REDIS_IO_WAIT 32 /* The client is waiting for Virtual Memory I/O */
193 /* Slave replication state - slave side */
194 #define REDIS_REPL_NONE 0 /* No active replication */
195 #define REDIS_REPL_CONNECT 1 /* Must connect to master */
196 #define REDIS_REPL_CONNECTED 2 /* Connected to master */
198 /* Slave replication state - from the point of view of master
199 * Note that in SEND_BULK and ONLINE state the slave receives new updates
200 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
201 * to start the next background saving in order to send updates to it. */
202 #define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
203 #define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
204 #define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
205 #define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
207 /* List related stuff */
211 /* Sort operations */
212 #define REDIS_SORT_GET 0
213 #define REDIS_SORT_ASC 1
214 #define REDIS_SORT_DESC 2
215 #define REDIS_SORTKEY_MAX 1024
218 #define REDIS_DEBUG 0
219 #define REDIS_VERBOSE 1
220 #define REDIS_NOTICE 2
221 #define REDIS_WARNING 3
223 /* Anti-warning macro... */
224 #define REDIS_NOTUSED(V) ((void) V)
226 #define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
227 #define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
229 /* Append only defines */
230 #define APPENDFSYNC_NO 0
231 #define APPENDFSYNC_ALWAYS 1
232 #define APPENDFSYNC_EVERYSEC 2
234 /* Hashes related defaults */
235 #define REDIS_HASH_MAX_ZIPMAP_ENTRIES 64
236 #define REDIS_HASH_MAX_ZIPMAP_VALUE 512
238 /* We can print the stacktrace, so our assert is defined this way: */
239 #define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),_exit(1)))
240 static void _redisAssert(char *estr
, char *file
, int line
);
242 /*================================= Data types ============================== */
244 /* A redis object, that is a type able to hold a string / list / set */
246 /* The VM object structure */
247 struct redisObjectVM
{
248 off_t page
; /* the page at witch the object is stored on disk */
249 off_t usedpages
; /* number of pages used on disk */
250 time_t atime
; /* Last access time */
253 /* The actual Redis Object */
254 typedef struct redisObject
{
257 unsigned char encoding
;
258 unsigned char storage
; /* If this object is a key, where is the value?
259 * REDIS_VM_MEMORY, REDIS_VM_SWAPPED, ... */
260 unsigned char vtype
; /* If this object is a key, and value is swapped out,
261 * this is the type of the swapped out object. */
263 /* VM fields, this are only allocated if VM is active, otherwise the
264 * object allocation function will just allocate
265 * sizeof(redisObjct) minus sizeof(redisObjectVM), so using
266 * Redis without VM active will not have any overhead. */
267 struct redisObjectVM vm
;
270 /* Macro used to initalize a Redis object allocated on the stack.
271 * Note that this macro is taken near the structure definition to make sure
272 * we'll update it when the structure is changed, to avoid bugs like
273 * bug #85 introduced exactly in this way. */
274 #define initStaticStringObject(_var,_ptr) do { \
276 _var.type = REDIS_STRING; \
277 _var.encoding = REDIS_ENCODING_RAW; \
279 if (server.vm_enabled) _var.storage = REDIS_VM_MEMORY; \
282 typedef struct redisDb
{
283 dict
*dict
; /* The keyspace for this DB */
284 dict
*expires
; /* Timeout of keys with a timeout set */
285 dict
*blockingkeys
; /* Keys with clients waiting for data (BLPOP) */
286 dict
*io_keys
; /* Keys with clients waiting for VM I/O */
290 /* Client MULTI/EXEC state */
291 typedef struct multiCmd
{
294 struct redisCommand
*cmd
;
297 typedef struct multiState
{
298 multiCmd
*commands
; /* Array of MULTI commands */
299 int count
; /* Total number of MULTI commands */
302 /* With multiplexing we need to take per-clinet state.
303 * Clients are taken in a liked list. */
304 typedef struct redisClient
{
309 robj
**argv
, **mbargv
;
311 int bulklen
; /* bulk read len. -1 if not in bulk read mode */
312 int multibulk
; /* multi bulk command format active */
315 time_t lastinteraction
; /* time of the last interaction, used for timeout */
316 int flags
; /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
317 int slaveseldb
; /* slave selected db, if this client is a slave */
318 int authenticated
; /* when requirepass is non-NULL */
319 int replstate
; /* replication state if this is a slave */
320 int repldbfd
; /* replication DB file descriptor */
321 long repldboff
; /* replication DB file offset */
322 off_t repldbsize
; /* replication DB file size */
323 multiState mstate
; /* MULTI/EXEC state */
324 robj
**blockingkeys
; /* The key we are waiting to terminate a blocking
325 * operation such as BLPOP. Otherwise NULL. */
326 int blockingkeysnum
; /* Number of blocking keys */
327 time_t blockingto
; /* Blocking operation timeout. If UNIX current time
328 * is >= blockingto then the operation timed out. */
329 list
*io_keys
; /* Keys this client is waiting to be loaded from the
330 * swap file in order to continue. */
331 dict
*pubsub_channels
; /* channels a client is interested in (SUBSCRIBE) */
332 list
*pubsub_patterns
; /* patterns a client is interested in (SUBSCRIBE) */
340 /* Global server state structure */
345 dict
*sharingpool
; /* Poll used for object sharing */
346 unsigned int sharingpoolsize
;
347 long long dirty
; /* changes to DB from the last save */
349 list
*slaves
, *monitors
;
350 char neterr
[ANET_ERR_LEN
];
352 int cronloops
; /* number of times the cron function run */
353 list
*objfreelist
; /* A list of freed objects to avoid malloc() */
354 time_t lastsave
; /* Unix time of last save succeeede */
355 /* Fields used only for stats */
356 time_t stat_starttime
; /* server start time */
357 long long stat_numcommands
; /* number of processed commands */
358 long long stat_numconnections
; /* number of connections received */
359 long long stat_expiredkeys
; /* number of expired keys */
372 pid_t bgsavechildpid
;
373 pid_t bgrewritechildpid
;
374 sds bgrewritebuf
; /* buffer taken by parent during oppend only rewrite */
375 struct saveparam
*saveparams
;
380 char *appendfilename
;
384 /* Replication related */
389 redisClient
*master
; /* client that is master for this slave */
391 unsigned int maxclients
;
392 unsigned long long maxmemory
;
393 unsigned int blpop_blocked_clients
;
394 unsigned int vm_blocked_clients
;
395 /* Sort parameters - qsort_r() is only available under BSD so we
396 * have to take this state global, in order to pass it to sortCompare() */
400 /* Virtual memory configuration */
405 unsigned long long vm_max_memory
;
407 size_t hash_max_zipmap_entries
;
408 size_t hash_max_zipmap_value
;
409 /* Virtual memory state */
412 off_t vm_next_page
; /* Next probably empty page */
413 off_t vm_near_pages
; /* Number of pages allocated sequentially */
414 unsigned char *vm_bitmap
; /* Bitmap of free/used pages */
415 time_t unixtime
; /* Unix time sampled every second. */
416 /* Virtual memory I/O threads stuff */
417 /* An I/O thread process an element taken from the io_jobs queue and
418 * put the result of the operation in the io_done list. While the
419 * job is being processed, it's put on io_processing queue. */
420 list
*io_newjobs
; /* List of VM I/O jobs yet to be processed */
421 list
*io_processing
; /* List of VM I/O jobs being processed */
422 list
*io_processed
; /* List of VM I/O jobs already processed */
423 list
*io_ready_clients
; /* Clients ready to be unblocked. All keys loaded */
424 pthread_mutex_t io_mutex
; /* lock to access io_jobs/io_done/io_thread_job */
425 pthread_mutex_t obj_freelist_mutex
; /* safe redis objects creation/free */
426 pthread_mutex_t io_swapfile_mutex
; /* So we can lseek + write */
427 pthread_attr_t io_threads_attr
; /* attributes for threads creation */
428 int io_active_threads
; /* Number of running I/O threads */
429 int vm_max_threads
; /* Max number of I/O threads running at the same time */
430 /* Our main thread is blocked on the event loop, locking for sockets ready
431 * to be read or written, so when a threaded I/O operation is ready to be
432 * processed by the main thread, the I/O thread will use a unix pipe to
433 * awake the main thread. The followings are the two pipe FDs. */
434 int io_ready_pipe_read
;
435 int io_ready_pipe_write
;
436 /* Virtual memory stats */
437 unsigned long long vm_stats_used_pages
;
438 unsigned long long vm_stats_swapped_objects
;
439 unsigned long long vm_stats_swapouts
;
440 unsigned long long vm_stats_swapins
;
442 dict
*pubsub_channels
; /* Map channels to list of subscribed clients */
443 list
*pubsub_patterns
; /* A list of pubsub_patterns */
448 typedef struct pubsubPattern
{
453 typedef void redisCommandProc(redisClient
*c
);
454 struct redisCommand
{
456 redisCommandProc
*proc
;
459 /* Use a function to determine which keys need to be loaded
460 * in the background prior to executing this command. Takes precedence
461 * over vm_firstkey and others, ignored when NULL */
462 redisCommandProc
*vm_preload_proc
;
463 /* What keys should be loaded in background when calling this command? */
464 int vm_firstkey
; /* The first argument that's a key (0 = no keys) */
465 int vm_lastkey
; /* THe last argument that's a key */
466 int vm_keystep
; /* The step between first and last key */
469 struct redisFunctionSym
{
471 unsigned long pointer
;
474 typedef struct _redisSortObject
{
482 typedef struct _redisSortOperation
{
485 } redisSortOperation
;
487 /* ZSETs use a specialized version of Skiplists */
489 typedef struct zskiplistNode
{
490 struct zskiplistNode
**forward
;
491 struct zskiplistNode
*backward
;
497 typedef struct zskiplist
{
498 struct zskiplistNode
*header
, *tail
;
499 unsigned long length
;
503 typedef struct zset
{
508 /* Our shared "common" objects */
510 struct sharedObjectsStruct
{
511 robj
*crlf
, *ok
, *err
, *emptybulk
, *czero
, *cone
, *pong
, *space
,
512 *colon
, *nullbulk
, *nullmultibulk
, *queued
,
513 *emptymultibulk
, *wrongtypeerr
, *nokeyerr
, *syntaxerr
, *sameobjecterr
,
514 *outofrangeerr
, *plus
,
515 *select0
, *select1
, *select2
, *select3
, *select4
,
516 *select5
, *select6
, *select7
, *select8
, *select9
,
517 *messagebulk
, *subscribebulk
, *unsubscribebulk
, *mbulk3
,
518 *psubscribebulk
, *punsubscribebulk
;
521 /* Global vars that are actally used as constants. The following double
522 * values are used for double on-disk serialization, and are initialized
523 * at runtime to avoid strange compiler optimizations. */
525 static double R_Zero
, R_PosInf
, R_NegInf
, R_Nan
;
527 /* VM threaded I/O request message */
528 #define REDIS_IOJOB_LOAD 0 /* Load from disk to memory */
529 #define REDIS_IOJOB_PREPARE_SWAP 1 /* Compute needed pages */
530 #define REDIS_IOJOB_DO_SWAP 2 /* Swap from memory to disk */
531 typedef struct iojob
{
532 int type
; /* Request type, REDIS_IOJOB_* */
533 redisDb
*db
;/* Redis database */
534 robj
*key
; /* This I/O request is about swapping this key */
535 robj
*val
; /* the value to swap for REDIS_IOREQ_*_SWAP, otherwise this
536 * field is populated by the I/O thread for REDIS_IOREQ_LOAD. */
537 off_t page
; /* Swap page where to read/write the object */
538 off_t pages
; /* Swap pages needed to save object. PREPARE_SWAP return val */
539 int canceled
; /* True if this command was canceled by blocking side of VM */
540 pthread_t thread
; /* ID of the thread processing this entry */
543 /*================================ Prototypes =============================== */
545 static void freeStringObject(robj
*o
);
546 static void freeListObject(robj
*o
);
547 static void freeSetObject(robj
*o
);
548 static void decrRefCount(void *o
);
549 static robj
*createObject(int type
, void *ptr
);
550 static void freeClient(redisClient
*c
);
551 static int rdbLoad(char *filename
);
552 static void addReply(redisClient
*c
, robj
*obj
);
553 static void addReplySds(redisClient
*c
, sds s
);
554 static void incrRefCount(robj
*o
);
555 static int rdbSaveBackground(char *filename
);
556 static robj
*createStringObject(char *ptr
, size_t len
);
557 static robj
*dupStringObject(robj
*o
);
558 static void replicationFeedSlaves(list
*slaves
, int dictid
, robj
**argv
, int argc
);
559 static void feedAppendOnlyFile(struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
);
560 static int syncWithMaster(void);
561 static robj
*tryObjectSharing(robj
*o
);
562 static int tryObjectEncoding(robj
*o
);
563 static robj
*getDecodedObject(robj
*o
);
564 static int removeExpire(redisDb
*db
, robj
*key
);
565 static int expireIfNeeded(redisDb
*db
, robj
*key
);
566 static int deleteIfVolatile(redisDb
*db
, robj
*key
);
567 static int deleteIfSwapped(redisDb
*db
, robj
*key
);
568 static int deleteKey(redisDb
*db
, robj
*key
);
569 static time_t getExpire(redisDb
*db
, robj
*key
);
570 static int setExpire(redisDb
*db
, robj
*key
, time_t when
);
571 static void updateSlavesWaitingBgsave(int bgsaveerr
);
572 static void freeMemoryIfNeeded(void);
573 static int processCommand(redisClient
*c
);
574 static void setupSigSegvAction(void);
575 static void rdbRemoveTempFile(pid_t childpid
);
576 static void aofRemoveTempFile(pid_t childpid
);
577 static size_t stringObjectLen(robj
*o
);
578 static void processInputBuffer(redisClient
*c
);
579 static zskiplist
*zslCreate(void);
580 static void zslFree(zskiplist
*zsl
);
581 static void zslInsert(zskiplist
*zsl
, double score
, robj
*obj
);
582 static void sendReplyToClientWritev(aeEventLoop
*el
, int fd
, void *privdata
, int mask
);
583 static void initClientMultiState(redisClient
*c
);
584 static void freeClientMultiState(redisClient
*c
);
585 static void queueMultiCommand(redisClient
*c
, struct redisCommand
*cmd
);
586 static void unblockClientWaitingData(redisClient
*c
);
587 static int handleClientsWaitingListPush(redisClient
*c
, robj
*key
, robj
*ele
);
588 static void vmInit(void);
589 static void vmMarkPagesFree(off_t page
, off_t count
);
590 static robj
*vmLoadObject(robj
*key
);
591 static robj
*vmPreviewObject(robj
*key
);
592 static int vmSwapOneObjectBlocking(void);
593 static int vmSwapOneObjectThreaded(void);
594 static int vmCanSwapOut(void);
595 static int tryFreeOneObjectFromFreelist(void);
596 static void acceptHandler(aeEventLoop
*el
, int fd
, void *privdata
, int mask
);
597 static void vmThreadedIOCompletedJob(aeEventLoop
*el
, int fd
, void *privdata
, int mask
);
598 static void vmCancelThreadedIOJob(robj
*o
);
599 static void lockThreadedIO(void);
600 static void unlockThreadedIO(void);
601 static int vmSwapObjectThreaded(robj
*key
, robj
*val
, redisDb
*db
);
602 static void freeIOJob(iojob
*j
);
603 static void queueIOJob(iojob
*j
);
604 static int vmWriteObjectOnSwap(robj
*o
, off_t page
);
605 static robj
*vmReadObjectFromSwap(off_t page
, int type
);
606 static void waitEmptyIOJobsQueue(void);
607 static void vmReopenSwapFile(void);
608 static int vmFreePage(off_t page
);
609 static void zunionInterBlockClientOnSwappedKeys(redisClient
*c
);
610 static int blockClientOnSwappedKeys(struct redisCommand
*cmd
, redisClient
*c
);
611 static int dontWaitForSwappedKey(redisClient
*c
, robj
*key
);
612 static void handleClientsBlockedOnSwappedKey(redisDb
*db
, robj
*key
);
613 static void readQueryFromClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
);
614 static struct redisCommand
*lookupCommand(char *name
);
615 static void call(redisClient
*c
, struct redisCommand
*cmd
);
616 static void resetClient(redisClient
*c
);
617 static void convertToRealHash(robj
*o
);
618 static int pubsubUnsubscribeAllChannels(redisClient
*c
, int notify
);
619 static int pubsubUnsubscribeAllPatterns(redisClient
*c
, int notify
);
620 static void freePubsubPattern(void *p
);
621 static int listMatchPubsubPattern(void *a
, void *b
);
622 static int compareStringObjects(robj
*a
, robj
*b
);
625 static void authCommand(redisClient
*c
);
626 static void pingCommand(redisClient
*c
);
627 static void echoCommand(redisClient
*c
);
628 static void setCommand(redisClient
*c
);
629 static void setnxCommand(redisClient
*c
);
630 static void getCommand(redisClient
*c
);
631 static void delCommand(redisClient
*c
);
632 static void existsCommand(redisClient
*c
);
633 static void incrCommand(redisClient
*c
);
634 static void decrCommand(redisClient
*c
);
635 static void incrbyCommand(redisClient
*c
);
636 static void decrbyCommand(redisClient
*c
);
637 static void selectCommand(redisClient
*c
);
638 static void randomkeyCommand(redisClient
*c
);
639 static void keysCommand(redisClient
*c
);
640 static void dbsizeCommand(redisClient
*c
);
641 static void lastsaveCommand(redisClient
*c
);
642 static void saveCommand(redisClient
*c
);
643 static void bgsaveCommand(redisClient
*c
);
644 static void bgrewriteaofCommand(redisClient
*c
);
645 static void shutdownCommand(redisClient
*c
);
646 static void moveCommand(redisClient
*c
);
647 static void renameCommand(redisClient
*c
);
648 static void renamenxCommand(redisClient
*c
);
649 static void lpushCommand(redisClient
*c
);
650 static void rpushCommand(redisClient
*c
);
651 static void lpopCommand(redisClient
*c
);
652 static void rpopCommand(redisClient
*c
);
653 static void llenCommand(redisClient
*c
);
654 static void lindexCommand(redisClient
*c
);
655 static void lrangeCommand(redisClient
*c
);
656 static void ltrimCommand(redisClient
*c
);
657 static void typeCommand(redisClient
*c
);
658 static void lsetCommand(redisClient
*c
);
659 static void saddCommand(redisClient
*c
);
660 static void sremCommand(redisClient
*c
);
661 static void smoveCommand(redisClient
*c
);
662 static void sismemberCommand(redisClient
*c
);
663 static void scardCommand(redisClient
*c
);
664 static void spopCommand(redisClient
*c
);
665 static void srandmemberCommand(redisClient
*c
);
666 static void sinterCommand(redisClient
*c
);
667 static void sinterstoreCommand(redisClient
*c
);
668 static void sunionCommand(redisClient
*c
);
669 static void sunionstoreCommand(redisClient
*c
);
670 static void sdiffCommand(redisClient
*c
);
671 static void sdiffstoreCommand(redisClient
*c
);
672 static void syncCommand(redisClient
*c
);
673 static void flushdbCommand(redisClient
*c
);
674 static void flushallCommand(redisClient
*c
);
675 static void sortCommand(redisClient
*c
);
676 static void lremCommand(redisClient
*c
);
677 static void rpoplpushcommand(redisClient
*c
);
678 static void infoCommand(redisClient
*c
);
679 static void mgetCommand(redisClient
*c
);
680 static void monitorCommand(redisClient
*c
);
681 static void expireCommand(redisClient
*c
);
682 static void expireatCommand(redisClient
*c
);
683 static void getsetCommand(redisClient
*c
);
684 static void ttlCommand(redisClient
*c
);
685 static void slaveofCommand(redisClient
*c
);
686 static void debugCommand(redisClient
*c
);
687 static void msetCommand(redisClient
*c
);
688 static void msetnxCommand(redisClient
*c
);
689 static void zaddCommand(redisClient
*c
);
690 static void zincrbyCommand(redisClient
*c
);
691 static void zrangeCommand(redisClient
*c
);
692 static void zrangebyscoreCommand(redisClient
*c
);
693 static void zcountCommand(redisClient
*c
);
694 static void zrevrangeCommand(redisClient
*c
);
695 static void zcardCommand(redisClient
*c
);
696 static void zremCommand(redisClient
*c
);
697 static void zscoreCommand(redisClient
*c
);
698 static void zremrangebyscoreCommand(redisClient
*c
);
699 static void multiCommand(redisClient
*c
);
700 static void execCommand(redisClient
*c
);
701 static void discardCommand(redisClient
*c
);
702 static void blpopCommand(redisClient
*c
);
703 static void brpopCommand(redisClient
*c
);
704 static void appendCommand(redisClient
*c
);
705 static void substrCommand(redisClient
*c
);
706 static void zrankCommand(redisClient
*c
);
707 static void zrevrankCommand(redisClient
*c
);
708 static void hsetCommand(redisClient
*c
);
709 static void hgetCommand(redisClient
*c
);
710 static void hdelCommand(redisClient
*c
);
711 static void hlenCommand(redisClient
*c
);
712 static void zremrangebyrankCommand(redisClient
*c
);
713 static void zunionCommand(redisClient
*c
);
714 static void zinterCommand(redisClient
*c
);
715 static void hkeysCommand(redisClient
*c
);
716 static void hvalsCommand(redisClient
*c
);
717 static void hgetallCommand(redisClient
*c
);
718 static void hexistsCommand(redisClient
*c
);
719 static void configCommand(redisClient
*c
);
720 static void hincrbyCommand(redisClient
*c
);
721 static void subscribeCommand(redisClient
*c
);
722 static void unsubscribeCommand(redisClient
*c
);
723 static void psubscribeCommand(redisClient
*c
);
724 static void punsubscribeCommand(redisClient
*c
);
725 static void publishCommand(redisClient
*c
);
727 /*================================= Globals ================================= */
730 static struct redisServer server
; /* server global state */
731 static struct redisCommand cmdTable
[] = {
732 {"get",getCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
733 {"set",setCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,0,0,0},
734 {"setnx",setnxCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,0,0,0},
735 {"append",appendCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
736 {"substr",substrCommand
,4,REDIS_CMD_INLINE
,NULL
,1,1,1},
737 {"del",delCommand
,-2,REDIS_CMD_INLINE
,NULL
,0,0,0},
738 {"exists",existsCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
739 {"incr",incrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
740 {"decr",decrCommand
,2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
741 {"mget",mgetCommand
,-2,REDIS_CMD_INLINE
,NULL
,1,-1,1},
742 {"rpush",rpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
743 {"lpush",lpushCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
744 {"rpop",rpopCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
745 {"lpop",lpopCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
746 {"brpop",brpopCommand
,-3,REDIS_CMD_INLINE
,NULL
,1,1,1},
747 {"blpop",blpopCommand
,-3,REDIS_CMD_INLINE
,NULL
,1,1,1},
748 {"llen",llenCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
749 {"lindex",lindexCommand
,3,REDIS_CMD_INLINE
,NULL
,1,1,1},
750 {"lset",lsetCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
751 {"lrange",lrangeCommand
,4,REDIS_CMD_INLINE
,NULL
,1,1,1},
752 {"ltrim",ltrimCommand
,4,REDIS_CMD_INLINE
,NULL
,1,1,1},
753 {"lrem",lremCommand
,4,REDIS_CMD_BULK
,NULL
,1,1,1},
754 {"rpoplpush",rpoplpushcommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,1,2,1},
755 {"sadd",saddCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
756 {"srem",sremCommand
,3,REDIS_CMD_BULK
,NULL
,1,1,1},
757 {"smove",smoveCommand
,4,REDIS_CMD_BULK
,NULL
,1,2,1},
758 {"sismember",sismemberCommand
,3,REDIS_CMD_BULK
,NULL
,1,1,1},
759 {"scard",scardCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
760 {"spop",spopCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
761 {"srandmember",srandmemberCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
762 {"sinter",sinterCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,1,-1,1},
763 {"sinterstore",sinterstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,2,-1,1},
764 {"sunion",sunionCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,1,-1,1},
765 {"sunionstore",sunionstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,2,-1,1},
766 {"sdiff",sdiffCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,1,-1,1},
767 {"sdiffstore",sdiffstoreCommand
,-3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,2,-1,1},
768 {"smembers",sinterCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
769 {"zadd",zaddCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
770 {"zincrby",zincrbyCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
771 {"zrem",zremCommand
,3,REDIS_CMD_BULK
,NULL
,1,1,1},
772 {"zremrangebyscore",zremrangebyscoreCommand
,4,REDIS_CMD_INLINE
,NULL
,1,1,1},
773 {"zremrangebyrank",zremrangebyrankCommand
,4,REDIS_CMD_INLINE
,NULL
,1,1,1},
774 {"zunion",zunionCommand
,-4,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,zunionInterBlockClientOnSwappedKeys
,0,0,0},
775 {"zinter",zinterCommand
,-4,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,zunionInterBlockClientOnSwappedKeys
,0,0,0},
776 {"zrange",zrangeCommand
,-4,REDIS_CMD_INLINE
,NULL
,1,1,1},
777 {"zrangebyscore",zrangebyscoreCommand
,-4,REDIS_CMD_INLINE
,NULL
,1,1,1},
778 {"zcount",zcountCommand
,4,REDIS_CMD_INLINE
,NULL
,1,1,1},
779 {"zrevrange",zrevrangeCommand
,-4,REDIS_CMD_INLINE
,NULL
,1,1,1},
780 {"zcard",zcardCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
781 {"zscore",zscoreCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
782 {"zrank",zrankCommand
,3,REDIS_CMD_BULK
,NULL
,1,1,1},
783 {"zrevrank",zrevrankCommand
,3,REDIS_CMD_BULK
,NULL
,1,1,1},
784 {"hset",hsetCommand
,4,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
785 {"hincrby",hincrbyCommand
,4,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
786 {"hget",hgetCommand
,3,REDIS_CMD_BULK
,NULL
,1,1,1},
787 {"hdel",hdelCommand
,3,REDIS_CMD_BULK
,NULL
,1,1,1},
788 {"hlen",hlenCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
789 {"hkeys",hkeysCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
790 {"hvals",hvalsCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
791 {"hgetall",hgetallCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
792 {"hexists",hexistsCommand
,3,REDIS_CMD_BULK
,NULL
,1,1,1},
793 {"incrby",incrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
794 {"decrby",decrbyCommand
,3,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
795 {"getset",getsetCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
796 {"mset",msetCommand
,-3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,-1,2},
797 {"msetnx",msetnxCommand
,-3,REDIS_CMD_BULK
|REDIS_CMD_DENYOOM
,NULL
,1,-1,2},
798 {"randomkey",randomkeyCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
799 {"select",selectCommand
,2,REDIS_CMD_INLINE
,NULL
,0,0,0},
800 {"move",moveCommand
,3,REDIS_CMD_INLINE
,NULL
,1,1,1},
801 {"rename",renameCommand
,3,REDIS_CMD_INLINE
,NULL
,1,1,1},
802 {"renamenx",renamenxCommand
,3,REDIS_CMD_INLINE
,NULL
,1,1,1},
803 {"expire",expireCommand
,3,REDIS_CMD_INLINE
,NULL
,0,0,0},
804 {"expireat",expireatCommand
,3,REDIS_CMD_INLINE
,NULL
,0,0,0},
805 {"keys",keysCommand
,2,REDIS_CMD_INLINE
,NULL
,0,0,0},
806 {"dbsize",dbsizeCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
807 {"auth",authCommand
,2,REDIS_CMD_INLINE
,NULL
,0,0,0},
808 {"ping",pingCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
809 {"echo",echoCommand
,2,REDIS_CMD_BULK
,NULL
,0,0,0},
810 {"save",saveCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
811 {"bgsave",bgsaveCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
812 {"bgrewriteaof",bgrewriteaofCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
813 {"shutdown",shutdownCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
814 {"lastsave",lastsaveCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
815 {"type",typeCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
816 {"multi",multiCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
817 {"exec",execCommand
,1,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,0,0,0},
818 {"discard",discardCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
819 {"sync",syncCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
820 {"flushdb",flushdbCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
821 {"flushall",flushallCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
822 {"sort",sortCommand
,-2,REDIS_CMD_INLINE
|REDIS_CMD_DENYOOM
,NULL
,1,1,1},
823 {"info",infoCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
824 {"monitor",monitorCommand
,1,REDIS_CMD_INLINE
,NULL
,0,0,0},
825 {"ttl",ttlCommand
,2,REDIS_CMD_INLINE
,NULL
,1,1,1},
826 {"slaveof",slaveofCommand
,3,REDIS_CMD_INLINE
,NULL
,0,0,0},
827 {"debug",debugCommand
,-2,REDIS_CMD_INLINE
,NULL
,0,0,0},
828 {"config",configCommand
,-2,REDIS_CMD_BULK
,NULL
,0,0,0},
829 {"subscribe",subscribeCommand
,-2,REDIS_CMD_INLINE
,NULL
,0,0,0},
830 {"unsubscribe",unsubscribeCommand
,-1,REDIS_CMD_INLINE
,NULL
,0,0,0},
831 {"psubscribe",psubscribeCommand
,-2,REDIS_CMD_INLINE
,NULL
,0,0,0},
832 {"punsubscribe",punsubscribeCommand
,-1,REDIS_CMD_INLINE
,NULL
,0,0,0},
833 {"publish",publishCommand
,3,REDIS_CMD_BULK
|REDIS_CMD_FORCE_REPLICATION
,NULL
,0,0,0},
834 {NULL
,NULL
,0,0,NULL
,0,0,0}
837 /*============================ Utility functions ============================ */
839 /* Glob-style pattern matching. */
840 static int stringmatchlen(const char *pattern
, int patternLen
,
841 const char *string
, int stringLen
, int nocase
)
846 while (pattern
[1] == '*') {
851 return 1; /* match */
853 if (stringmatchlen(pattern
+1, patternLen
-1,
854 string
, stringLen
, nocase
))
855 return 1; /* match */
859 return 0; /* no match */
863 return 0; /* no match */
873 not = pattern
[0] == '^';
880 if (pattern
[0] == '\\') {
883 if (pattern
[0] == string
[0])
885 } else if (pattern
[0] == ']') {
887 } else if (patternLen
== 0) {
891 } else if (pattern
[1] == '-' && patternLen
>= 3) {
892 int start
= pattern
[0];
893 int end
= pattern
[2];
901 start
= tolower(start
);
907 if (c
>= start
&& c
<= end
)
911 if (pattern
[0] == string
[0])
914 if (tolower((int)pattern
[0]) == tolower((int)string
[0]))
924 return 0; /* no match */
930 if (patternLen
>= 2) {
937 if (pattern
[0] != string
[0])
938 return 0; /* no match */
940 if (tolower((int)pattern
[0]) != tolower((int)string
[0]))
941 return 0; /* no match */
949 if (stringLen
== 0) {
950 while(*pattern
== '*') {
957 if (patternLen
== 0 && stringLen
== 0)
962 static int stringmatch(const char *pattern
, const char *string
, int nocase
) {
963 return stringmatchlen(pattern
,strlen(pattern
),string
,strlen(string
),nocase
);
966 static void redisLog(int level
, const char *fmt
, ...) {
970 fp
= (server
.logfile
== NULL
) ? stdout
: fopen(server
.logfile
,"a");
974 if (level
>= server
.verbosity
) {
980 strftime(buf
,64,"%d %b %H:%M:%S",localtime(&now
));
981 fprintf(fp
,"[%d] %s %c ",(int)getpid(),buf
,c
[level
]);
982 vfprintf(fp
, fmt
, ap
);
988 if (server
.logfile
) fclose(fp
);
991 /*====================== Hash table type implementation ==================== */
993 /* This is an hash table type that uses the SDS dynamic strings libary as
994 * keys and radis objects as values (objects can hold SDS strings,
997 static void dictVanillaFree(void *privdata
, void *val
)
999 DICT_NOTUSED(privdata
);
1003 static void dictListDestructor(void *privdata
, void *val
)
1005 DICT_NOTUSED(privdata
);
1006 listRelease((list
*)val
);
1009 static int sdsDictKeyCompare(void *privdata
, const void *key1
,
1013 DICT_NOTUSED(privdata
);
1015 l1
= sdslen((sds
)key1
);
1016 l2
= sdslen((sds
)key2
);
1017 if (l1
!= l2
) return 0;
1018 return memcmp(key1
, key2
, l1
) == 0;
1021 static void dictRedisObjectDestructor(void *privdata
, void *val
)
1023 DICT_NOTUSED(privdata
);
1025 if (val
== NULL
) return; /* Values of swapped out keys as set to NULL */
1029 static int dictObjKeyCompare(void *privdata
, const void *key1
,
1032 const robj
*o1
= key1
, *o2
= key2
;
1033 return sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
1036 static unsigned int dictObjHash(const void *key
) {
1037 const robj
*o
= key
;
1038 return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
1041 static int dictEncObjKeyCompare(void *privdata
, const void *key1
,
1044 robj
*o1
= (robj
*) key1
, *o2
= (robj
*) key2
;
1047 if (o1
->encoding
== REDIS_ENCODING_INT
&&
1048 o2
->encoding
== REDIS_ENCODING_INT
&&
1049 o1
->ptr
== o2
->ptr
) return 1;
1051 o1
= getDecodedObject(o1
);
1052 o2
= getDecodedObject(o2
);
1053 cmp
= sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
);
1059 static unsigned int dictEncObjHash(const void *key
) {
1060 robj
*o
= (robj
*) key
;
1062 if (o
->encoding
== REDIS_ENCODING_RAW
) {
1063 return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
1065 if (o
->encoding
== REDIS_ENCODING_INT
) {
1069 len
= snprintf(buf
,32,"%ld",(long)o
->ptr
);
1070 return dictGenHashFunction((unsigned char*)buf
, len
);
1074 o
= getDecodedObject(o
);
1075 hash
= dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
));
1082 /* Sets type and expires */
1083 static dictType setDictType
= {
1084 dictEncObjHash
, /* hash function */
1087 dictEncObjKeyCompare
, /* key compare */
1088 dictRedisObjectDestructor
, /* key destructor */
1089 NULL
/* val destructor */
1092 /* Sorted sets hash (note: a skiplist is used in addition to the hash table) */
1093 static dictType zsetDictType
= {
1094 dictEncObjHash
, /* hash function */
1097 dictEncObjKeyCompare
, /* key compare */
1098 dictRedisObjectDestructor
, /* key destructor */
1099 dictVanillaFree
/* val destructor of malloc(sizeof(double)) */
1103 static dictType dbDictType
= {
1104 dictObjHash
, /* hash function */
1107 dictObjKeyCompare
, /* key compare */
1108 dictRedisObjectDestructor
, /* key destructor */
1109 dictRedisObjectDestructor
/* val destructor */
1113 static dictType keyptrDictType
= {
1114 dictObjHash
, /* hash function */
1117 dictObjKeyCompare
, /* key compare */
1118 dictRedisObjectDestructor
, /* key destructor */
1119 NULL
/* val destructor */
1122 /* Hash type hash table (note that small hashes are represented with zimpaps) */
1123 static dictType hashDictType
= {
1124 dictEncObjHash
, /* hash function */
1127 dictEncObjKeyCompare
, /* key compare */
1128 dictRedisObjectDestructor
, /* key destructor */
1129 dictRedisObjectDestructor
/* val destructor */
1132 /* Keylist hash table type has unencoded redis objects as keys and
1133 * lists as values. It's used for blocking operations (BLPOP) and to
1134 * map swapped keys to a list of clients waiting for this keys to be loaded. */
1135 static dictType keylistDictType
= {
1136 dictObjHash
, /* hash function */
1139 dictObjKeyCompare
, /* key compare */
1140 dictRedisObjectDestructor
, /* key destructor */
1141 dictListDestructor
/* val destructor */
1144 static void version();
1146 /* ========================= Random utility functions ======================= */
1148 /* Redis generally does not try to recover from out of memory conditions
1149 * when allocating objects or strings, it is not clear if it will be possible
1150 * to report this condition to the client since the networking layer itself
1151 * is based on heap allocation for send buffers, so we simply abort.
1152 * At least the code will be simpler to read... */
1153 static void oom(const char *msg
) {
1154 redisLog(REDIS_WARNING
, "%s: Out of memory\n",msg
);
1159 /* ====================== Redis server networking stuff ===================== */
1160 static void closeTimedoutClients(void) {
1163 time_t now
= time(NULL
);
1166 listRewind(server
.clients
,&li
);
1167 while ((ln
= listNext(&li
)) != NULL
) {
1168 c
= listNodeValue(ln
);
1169 if (server
.maxidletime
&&
1170 !(c
->flags
& REDIS_SLAVE
) && /* no timeout for slaves */
1171 !(c
->flags
& REDIS_MASTER
) && /* no timeout for masters */
1172 dictSize(c
->pubsub_channels
) == 0 && /* no timeout for pubsub */
1173 listLength(c
->pubsub_patterns
) == 0 &&
1174 (now
- c
->lastinteraction
> server
.maxidletime
))
1176 redisLog(REDIS_VERBOSE
,"Closing idle client");
1178 } else if (c
->flags
& REDIS_BLOCKED
) {
1179 if (c
->blockingto
!= 0 && c
->blockingto
< now
) {
1180 addReply(c
,shared
.nullmultibulk
);
1181 unblockClientWaitingData(c
);
1187 static int htNeedsResize(dict
*dict
) {
1188 long long size
, used
;
1190 size
= dictSlots(dict
);
1191 used
= dictSize(dict
);
1192 return (size
&& used
&& size
> DICT_HT_INITIAL_SIZE
&&
1193 (used
*100/size
< REDIS_HT_MINFILL
));
1196 /* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
1197 * we resize the hash table to save memory */
1198 static void tryResizeHashTables(void) {
1201 for (j
= 0; j
< server
.dbnum
; j
++) {
1202 if (htNeedsResize(server
.db
[j
].dict
)) {
1203 redisLog(REDIS_VERBOSE
,"The hash table %d is too sparse, resize it...",j
);
1204 dictResize(server
.db
[j
].dict
);
1205 redisLog(REDIS_VERBOSE
,"Hash table %d resized.",j
);
1207 if (htNeedsResize(server
.db
[j
].expires
))
1208 dictResize(server
.db
[j
].expires
);
1212 /* A background saving child (BGSAVE) terminated its work. Handle this. */
1213 void backgroundSaveDoneHandler(int statloc
) {
1214 int exitcode
= WEXITSTATUS(statloc
);
1215 int bysignal
= WIFSIGNALED(statloc
);
1217 if (!bysignal
&& exitcode
== 0) {
1218 redisLog(REDIS_NOTICE
,
1219 "Background saving terminated with success");
1221 server
.lastsave
= time(NULL
);
1222 } else if (!bysignal
&& exitcode
!= 0) {
1223 redisLog(REDIS_WARNING
, "Background saving error");
1225 redisLog(REDIS_WARNING
,
1226 "Background saving terminated by signal %d", WTERMSIG(statloc
));
1227 rdbRemoveTempFile(server
.bgsavechildpid
);
1229 server
.bgsavechildpid
= -1;
1230 /* Possibly there are slaves waiting for a BGSAVE in order to be served
1231 * (the first stage of SYNC is a bulk transfer of dump.rdb) */
1232 updateSlavesWaitingBgsave(exitcode
== 0 ? REDIS_OK
: REDIS_ERR
);
1235 /* A background append only file rewriting (BGREWRITEAOF) terminated its work.
1237 void backgroundRewriteDoneHandler(int statloc
) {
1238 int exitcode
= WEXITSTATUS(statloc
);
1239 int bysignal
= WIFSIGNALED(statloc
);
1241 if (!bysignal
&& exitcode
== 0) {
1245 redisLog(REDIS_NOTICE
,
1246 "Background append only file rewriting terminated with success");
1247 /* Now it's time to flush the differences accumulated by the parent */
1248 snprintf(tmpfile
,256,"temp-rewriteaof-bg-%d.aof", (int) server
.bgrewritechildpid
);
1249 fd
= open(tmpfile
,O_WRONLY
|O_APPEND
);
1251 redisLog(REDIS_WARNING
, "Not able to open the temp append only file produced by the child: %s", strerror(errno
));
1254 /* Flush our data... */
1255 if (write(fd
,server
.bgrewritebuf
,sdslen(server
.bgrewritebuf
)) !=
1256 (signed) sdslen(server
.bgrewritebuf
)) {
1257 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
));
1261 redisLog(REDIS_NOTICE
,"Parent diff flushed into the new append log file with success (%lu bytes)",sdslen(server
.bgrewritebuf
));
1262 /* Now our work is to rename the temp file into the stable file. And
1263 * switch the file descriptor used by the server for append only. */
1264 if (rename(tmpfile
,server
.appendfilename
) == -1) {
1265 redisLog(REDIS_WARNING
,"Can't rename the temp append only file into the stable one: %s", strerror(errno
));
1269 /* Mission completed... almost */
1270 redisLog(REDIS_NOTICE
,"Append only file successfully rewritten.");
1271 if (server
.appendfd
!= -1) {
1272 /* If append only is actually enabled... */
1273 close(server
.appendfd
);
1274 server
.appendfd
= fd
;
1276 server
.appendseldb
= -1; /* Make sure it will issue SELECT */
1277 redisLog(REDIS_NOTICE
,"The new append only file was selected for future appends.");
1279 /* If append only is disabled we just generate a dump in this
1280 * format. Why not? */
1283 } else if (!bysignal
&& exitcode
!= 0) {
1284 redisLog(REDIS_WARNING
, "Background append only file rewriting error");
1286 redisLog(REDIS_WARNING
,
1287 "Background append only file rewriting terminated by signal %d",
1291 sdsfree(server
.bgrewritebuf
);
1292 server
.bgrewritebuf
= sdsempty();
1293 aofRemoveTempFile(server
.bgrewritechildpid
);
1294 server
.bgrewritechildpid
= -1;
1297 /* This function is called once a background process of some kind terminates,
1298 * as we want to avoid resizing the hash tables when there is a child in order
1299 * to play well with copy-on-write (otherwise when a resize happens lots of
1300 * memory pages are copied). The goal of this function is to update the ability
1301 * for dict.c to resize the hash tables accordingly to the fact we have o not
1302 * running childs. */
1303 static void updateDictResizePolicy(void) {
1304 if (server
.bgsavechildpid
== -1 && server
.bgrewritechildpid
== -1)
1307 dictDisableResize();
1310 static int serverCron(struct aeEventLoop
*eventLoop
, long long id
, void *clientData
) {
1311 int j
, loops
= server
.cronloops
++;
1312 REDIS_NOTUSED(eventLoop
);
1314 REDIS_NOTUSED(clientData
);
1316 /* We take a cached value of the unix time in the global state because
1317 * with virtual memory and aging there is to store the current time
1318 * in objects at every object access, and accuracy is not needed.
1319 * To access a global var is faster than calling time(NULL) */
1320 server
.unixtime
= time(NULL
);
1322 /* Show some info about non-empty databases */
1323 for (j
= 0; j
< server
.dbnum
; j
++) {
1324 long long size
, used
, vkeys
;
1326 size
= dictSlots(server
.db
[j
].dict
);
1327 used
= dictSize(server
.db
[j
].dict
);
1328 vkeys
= dictSize(server
.db
[j
].expires
);
1329 if (!(loops
% 50) && (used
|| vkeys
)) {
1330 redisLog(REDIS_VERBOSE
,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j
,used
,vkeys
,size
);
1331 /* dictPrintStats(server.dict); */
1335 /* We don't want to resize the hash tables while a bacground saving
1336 * is in progress: the saving child is created using fork() that is
1337 * implemented with a copy-on-write semantic in most modern systems, so
1338 * if we resize the HT while there is the saving child at work actually
1339 * a lot of memory movements in the parent will cause a lot of pages
1341 if (server
.bgsavechildpid
== -1 && server
.bgrewritechildpid
== -1 &&
1344 tryResizeHashTables();
1347 /* Show information about connected clients */
1348 if (!(loops
% 50)) {
1349 redisLog(REDIS_VERBOSE
,"%d clients connected (%d slaves), %zu bytes in use, %d shared objects",
1350 listLength(server
.clients
)-listLength(server
.slaves
),
1351 listLength(server
.slaves
),
1352 zmalloc_used_memory(),
1353 dictSize(server
.sharingpool
));
1356 /* Close connections of timedout clients */
1357 if ((server
.maxidletime
&& !(loops
% 100)) || server
.blpop_blocked_clients
)
1358 closeTimedoutClients();
1360 /* Check if a background saving or AOF rewrite in progress terminated */
1361 if (server
.bgsavechildpid
!= -1 || server
.bgrewritechildpid
!= -1) {
1365 if ((pid
= wait3(&statloc
,WNOHANG
,NULL
)) != 0) {
1366 if (pid
== server
.bgsavechildpid
) {
1367 backgroundSaveDoneHandler(statloc
);
1369 backgroundRewriteDoneHandler(statloc
);
1371 updateDictResizePolicy();
1374 /* If there is not a background saving in progress check if
1375 * we have to save now */
1376 time_t now
= time(NULL
);
1377 for (j
= 0; j
< server
.saveparamslen
; j
++) {
1378 struct saveparam
*sp
= server
.saveparams
+j
;
1380 if (server
.dirty
>= sp
->changes
&&
1381 now
-server
.lastsave
> sp
->seconds
) {
1382 redisLog(REDIS_NOTICE
,"%d changes in %d seconds. Saving...",
1383 sp
->changes
, sp
->seconds
);
1384 rdbSaveBackground(server
.dbfilename
);
1390 /* Try to expire a few timed out keys. The algorithm used is adaptive and
1391 * will use few CPU cycles if there are few expiring keys, otherwise
1392 * it will get more aggressive to avoid that too much memory is used by
1393 * keys that can be removed from the keyspace. */
1394 for (j
= 0; j
< server
.dbnum
; j
++) {
1396 redisDb
*db
= server
.db
+j
;
1398 /* Continue to expire if at the end of the cycle more than 25%
1399 * of the keys were expired. */
1401 long num
= dictSize(db
->expires
);
1402 time_t now
= time(NULL
);
1405 if (num
> REDIS_EXPIRELOOKUPS_PER_CRON
)
1406 num
= REDIS_EXPIRELOOKUPS_PER_CRON
;
1411 if ((de
= dictGetRandomKey(db
->expires
)) == NULL
) break;
1412 t
= (time_t) dictGetEntryVal(de
);
1414 deleteKey(db
,dictGetEntryKey(de
));
1416 server
.stat_expiredkeys
++;
1419 } while (expired
> REDIS_EXPIRELOOKUPS_PER_CRON
/4);
1422 /* Swap a few keys on disk if we are over the memory limit and VM
1423 * is enbled. Try to free objects from the free list first. */
1424 if (vmCanSwapOut()) {
1425 while (server
.vm_enabled
&& zmalloc_used_memory() >
1426 server
.vm_max_memory
)
1430 if (tryFreeOneObjectFromFreelist() == REDIS_OK
) continue;
1431 retval
= (server
.vm_max_threads
== 0) ?
1432 vmSwapOneObjectBlocking() :
1433 vmSwapOneObjectThreaded();
1434 if (retval
== REDIS_ERR
&& !(loops
% 300) &&
1435 zmalloc_used_memory() >
1436 (server
.vm_max_memory
+server
.vm_max_memory
/10))
1438 redisLog(REDIS_WARNING
,"WARNING: vm-max-memory limit exceeded by more than 10%% but unable to swap more objects out!");
1440 /* Note that when using threade I/O we free just one object,
1441 * because anyway when the I/O thread in charge to swap this
1442 * object out will finish, the handler of completed jobs
1443 * will try to swap more objects if we are still out of memory. */
1444 if (retval
== REDIS_ERR
|| server
.vm_max_threads
> 0) break;
1448 /* Check if we should connect to a MASTER */
1449 if (server
.replstate
== REDIS_REPL_CONNECT
&& !(loops
% 10)) {
1450 redisLog(REDIS_NOTICE
,"Connecting to MASTER...");
1451 if (syncWithMaster() == REDIS_OK
) {
1452 redisLog(REDIS_NOTICE
,"MASTER <-> SLAVE sync succeeded");
1458 /* This function gets called every time Redis is entering the
1459 * main loop of the event driven library, that is, before to sleep
1460 * for ready file descriptors. */
1461 static void beforeSleep(struct aeEventLoop
*eventLoop
) {
1462 REDIS_NOTUSED(eventLoop
);
1464 if (server
.vm_enabled
&& listLength(server
.io_ready_clients
)) {
1468 listRewind(server
.io_ready_clients
,&li
);
1469 while((ln
= listNext(&li
))) {
1470 redisClient
*c
= ln
->value
;
1471 struct redisCommand
*cmd
;
1473 /* Resume the client. */
1474 listDelNode(server
.io_ready_clients
,ln
);
1475 c
->flags
&= (~REDIS_IO_WAIT
);
1476 server
.vm_blocked_clients
--;
1477 aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
,
1478 readQueryFromClient
, c
);
1479 cmd
= lookupCommand(c
->argv
[0]->ptr
);
1480 assert(cmd
!= NULL
);
1483 /* There may be more data to process in the input buffer. */
1484 if (c
->querybuf
&& sdslen(c
->querybuf
) > 0)
1485 processInputBuffer(c
);
1490 static void createSharedObjects(void) {
1491 shared
.crlf
= createObject(REDIS_STRING
,sdsnew("\r\n"));
1492 shared
.ok
= createObject(REDIS_STRING
,sdsnew("+OK\r\n"));
1493 shared
.err
= createObject(REDIS_STRING
,sdsnew("-ERR\r\n"));
1494 shared
.emptybulk
= createObject(REDIS_STRING
,sdsnew("$0\r\n\r\n"));
1495 shared
.czero
= createObject(REDIS_STRING
,sdsnew(":0\r\n"));
1496 shared
.cone
= createObject(REDIS_STRING
,sdsnew(":1\r\n"));
1497 shared
.nullbulk
= createObject(REDIS_STRING
,sdsnew("$-1\r\n"));
1498 shared
.nullmultibulk
= createObject(REDIS_STRING
,sdsnew("*-1\r\n"));
1499 shared
.emptymultibulk
= createObject(REDIS_STRING
,sdsnew("*0\r\n"));
1500 shared
.pong
= createObject(REDIS_STRING
,sdsnew("+PONG\r\n"));
1501 shared
.queued
= createObject(REDIS_STRING
,sdsnew("+QUEUED\r\n"));
1502 shared
.wrongtypeerr
= createObject(REDIS_STRING
,sdsnew(
1503 "-ERR Operation against a key holding the wrong kind of value\r\n"));
1504 shared
.nokeyerr
= createObject(REDIS_STRING
,sdsnew(
1505 "-ERR no such key\r\n"));
1506 shared
.syntaxerr
= createObject(REDIS_STRING
,sdsnew(
1507 "-ERR syntax error\r\n"));
1508 shared
.sameobjecterr
= createObject(REDIS_STRING
,sdsnew(
1509 "-ERR source and destination objects are the same\r\n"));
1510 shared
.outofrangeerr
= createObject(REDIS_STRING
,sdsnew(
1511 "-ERR index out of range\r\n"));
1512 shared
.space
= createObject(REDIS_STRING
,sdsnew(" "));
1513 shared
.colon
= createObject(REDIS_STRING
,sdsnew(":"));
1514 shared
.plus
= createObject(REDIS_STRING
,sdsnew("+"));
1515 shared
.select0
= createStringObject("select 0\r\n",10);
1516 shared
.select1
= createStringObject("select 1\r\n",10);
1517 shared
.select2
= createStringObject("select 2\r\n",10);
1518 shared
.select3
= createStringObject("select 3\r\n",10);
1519 shared
.select4
= createStringObject("select 4\r\n",10);
1520 shared
.select5
= createStringObject("select 5\r\n",10);
1521 shared
.select6
= createStringObject("select 6\r\n",10);
1522 shared
.select7
= createStringObject("select 7\r\n",10);
1523 shared
.select8
= createStringObject("select 8\r\n",10);
1524 shared
.select9
= createStringObject("select 9\r\n",10);
1525 shared
.messagebulk
= createStringObject("$7\r\nmessage\r\n",13);
1526 shared
.subscribebulk
= createStringObject("$9\r\nsubscribe\r\n",15);
1527 shared
.unsubscribebulk
= createStringObject("$11\r\nunsubscribe\r\n",18);
1528 shared
.psubscribebulk
= createStringObject("$10\r\npsubscribe\r\n",17);
1529 shared
.punsubscribebulk
= createStringObject("$12\r\npunsubscribe\r\n",19);
1530 shared
.mbulk3
= createStringObject("*3\r\n",4);
1533 static void appendServerSaveParams(time_t seconds
, int changes
) {
1534 server
.saveparams
= zrealloc(server
.saveparams
,sizeof(struct saveparam
)*(server
.saveparamslen
+1));
1535 server
.saveparams
[server
.saveparamslen
].seconds
= seconds
;
1536 server
.saveparams
[server
.saveparamslen
].changes
= changes
;
1537 server
.saveparamslen
++;
1540 static void resetServerSaveParams() {
1541 zfree(server
.saveparams
);
1542 server
.saveparams
= NULL
;
1543 server
.saveparamslen
= 0;
1546 static void initServerConfig() {
1547 server
.dbnum
= REDIS_DEFAULT_DBNUM
;
1548 server
.port
= REDIS_SERVERPORT
;
1549 server
.verbosity
= REDIS_VERBOSE
;
1550 server
.maxidletime
= REDIS_MAXIDLETIME
;
1551 server
.saveparams
= NULL
;
1552 server
.logfile
= NULL
; /* NULL = log on standard output */
1553 server
.bindaddr
= NULL
;
1554 server
.glueoutputbuf
= 1;
1555 server
.daemonize
= 0;
1556 server
.appendonly
= 0;
1557 server
.appendfsync
= APPENDFSYNC_ALWAYS
;
1558 server
.lastfsync
= time(NULL
);
1559 server
.appendfd
= -1;
1560 server
.appendseldb
= -1; /* Make sure the first time will not match */
1561 server
.pidfile
= zstrdup("/var/run/redis.pid");
1562 server
.dbfilename
= zstrdup("dump.rdb");
1563 server
.appendfilename
= zstrdup("appendonly.aof");
1564 server
.requirepass
= NULL
;
1565 server
.shareobjects
= 0;
1566 server
.rdbcompression
= 1;
1567 server
.sharingpoolsize
= 1024;
1568 server
.maxclients
= 0;
1569 server
.blpop_blocked_clients
= 0;
1570 server
.maxmemory
= 0;
1571 server
.vm_enabled
= 0;
1572 server
.vm_swap_file
= zstrdup("/tmp/redis-%p.vm");
1573 server
.vm_page_size
= 256; /* 256 bytes per page */
1574 server
.vm_pages
= 1024*1024*100; /* 104 millions of pages */
1575 server
.vm_max_memory
= 1024LL*1024*1024*1; /* 1 GB of RAM */
1576 server
.vm_max_threads
= 4;
1577 server
.vm_blocked_clients
= 0;
1578 server
.hash_max_zipmap_entries
= REDIS_HASH_MAX_ZIPMAP_ENTRIES
;
1579 server
.hash_max_zipmap_value
= REDIS_HASH_MAX_ZIPMAP_VALUE
;
1581 resetServerSaveParams();
1583 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
1584 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
1585 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1586 /* Replication related */
1588 server
.masterauth
= NULL
;
1589 server
.masterhost
= NULL
;
1590 server
.masterport
= 6379;
1591 server
.master
= NULL
;
1592 server
.replstate
= REDIS_REPL_NONE
;
1594 /* Double constants initialization */
1596 R_PosInf
= 1.0/R_Zero
;
1597 R_NegInf
= -1.0/R_Zero
;
1598 R_Nan
= R_Zero
/R_Zero
;
1601 static void initServer() {
1604 signal(SIGHUP
, SIG_IGN
);
1605 signal(SIGPIPE
, SIG_IGN
);
1606 setupSigSegvAction();
1608 server
.devnull
= fopen("/dev/null","w");
1609 if (server
.devnull
== NULL
) {
1610 redisLog(REDIS_WARNING
, "Can't open /dev/null: %s", server
.neterr
);
1613 server
.clients
= listCreate();
1614 server
.slaves
= listCreate();
1615 server
.monitors
= listCreate();
1616 server
.objfreelist
= listCreate();
1617 createSharedObjects();
1618 server
.el
= aeCreateEventLoop();
1619 server
.db
= zmalloc(sizeof(redisDb
)*server
.dbnum
);
1620 server
.sharingpool
= dictCreate(&setDictType
,NULL
);
1621 server
.fd
= anetTcpServer(server
.neterr
, server
.port
, server
.bindaddr
);
1622 if (server
.fd
== -1) {
1623 redisLog(REDIS_WARNING
, "Opening TCP port: %s", server
.neterr
);
1626 for (j
= 0; j
< server
.dbnum
; j
++) {
1627 server
.db
[j
].dict
= dictCreate(&dbDictType
,NULL
);
1628 server
.db
[j
].expires
= dictCreate(&keyptrDictType
,NULL
);
1629 server
.db
[j
].blockingkeys
= dictCreate(&keylistDictType
,NULL
);
1630 if (server
.vm_enabled
)
1631 server
.db
[j
].io_keys
= dictCreate(&keylistDictType
,NULL
);
1632 server
.db
[j
].id
= j
;
1634 server
.pubsub_channels
= dictCreate(&keylistDictType
,NULL
);
1635 server
.pubsub_patterns
= listCreate();
1636 listSetFreeMethod(server
.pubsub_patterns
,freePubsubPattern
);
1637 listSetMatchMethod(server
.pubsub_patterns
,listMatchPubsubPattern
);
1638 server
.cronloops
= 0;
1639 server
.bgsavechildpid
= -1;
1640 server
.bgrewritechildpid
= -1;
1641 server
.bgrewritebuf
= sdsempty();
1642 server
.lastsave
= time(NULL
);
1644 server
.stat_numcommands
= 0;
1645 server
.stat_numconnections
= 0;
1646 server
.stat_expiredkeys
= 0;
1647 server
.stat_starttime
= time(NULL
);
1648 server
.unixtime
= time(NULL
);
1649 aeCreateTimeEvent(server
.el
, 1, serverCron
, NULL
, NULL
);
1650 if (aeCreateFileEvent(server
.el
, server
.fd
, AE_READABLE
,
1651 acceptHandler
, NULL
) == AE_ERR
) oom("creating file event");
1653 if (server
.appendonly
) {
1654 server
.appendfd
= open(server
.appendfilename
,O_WRONLY
|O_APPEND
|O_CREAT
,0644);
1655 if (server
.appendfd
== -1) {
1656 redisLog(REDIS_WARNING
, "Can't open the append-only file: %s",
1662 if (server
.vm_enabled
) vmInit();
1665 /* Empty the whole database */
1666 static long long emptyDb() {
1668 long long removed
= 0;
1670 for (j
= 0; j
< server
.dbnum
; j
++) {
1671 removed
+= dictSize(server
.db
[j
].dict
);
1672 dictEmpty(server
.db
[j
].dict
);
1673 dictEmpty(server
.db
[j
].expires
);
1678 static int yesnotoi(char *s
) {
1679 if (!strcasecmp(s
,"yes")) return 1;
1680 else if (!strcasecmp(s
,"no")) return 0;
1684 /* I agree, this is a very rudimental way to load a configuration...
1685 will improve later if the config gets more complex */
1686 static void loadServerConfig(char *filename
) {
1688 char buf
[REDIS_CONFIGLINE_MAX
+1], *err
= NULL
;
1691 char *errormsg
= "Fatal error, can't open config file '%s'";
1692 char *errorbuf
= zmalloc(sizeof(char)*(strlen(errormsg
)+strlen(filename
)));
1693 sprintf(errorbuf
, errormsg
, filename
);
1695 if (filename
[0] == '-' && filename
[1] == '\0')
1698 if ((fp
= fopen(filename
,"r")) == NULL
) {
1699 redisLog(REDIS_WARNING
, errorbuf
);
1704 while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) {
1710 line
= sdstrim(line
," \t\r\n");
1712 /* Skip comments and blank lines*/
1713 if (line
[0] == '#' || line
[0] == '\0') {
1718 /* Split into arguments */
1719 argv
= sdssplitlen(line
,sdslen(line
)," ",1,&argc
);
1720 sdstolower(argv
[0]);
1722 /* Execute config directives */
1723 if (!strcasecmp(argv
[0],"timeout") && argc
== 2) {
1724 server
.maxidletime
= atoi(argv
[1]);
1725 if (server
.maxidletime
< 0) {
1726 err
= "Invalid timeout value"; goto loaderr
;
1728 } else if (!strcasecmp(argv
[0],"port") && argc
== 2) {
1729 server
.port
= atoi(argv
[1]);
1730 if (server
.port
< 1 || server
.port
> 65535) {
1731 err
= "Invalid port"; goto loaderr
;
1733 } else if (!strcasecmp(argv
[0],"bind") && argc
== 2) {
1734 server
.bindaddr
= zstrdup(argv
[1]);
1735 } else if (!strcasecmp(argv
[0],"save") && argc
== 3) {
1736 int seconds
= atoi(argv
[1]);
1737 int changes
= atoi(argv
[2]);
1738 if (seconds
< 1 || changes
< 0) {
1739 err
= "Invalid save parameters"; goto loaderr
;
1741 appendServerSaveParams(seconds
,changes
);
1742 } else if (!strcasecmp(argv
[0],"dir") && argc
== 2) {
1743 if (chdir(argv
[1]) == -1) {
1744 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s",
1745 argv
[1], strerror(errno
));
1748 } else if (!strcasecmp(argv
[0],"loglevel") && argc
== 2) {
1749 if (!strcasecmp(argv
[1],"debug")) server
.verbosity
= REDIS_DEBUG
;
1750 else if (!strcasecmp(argv
[1],"verbose")) server
.verbosity
= REDIS_VERBOSE
;
1751 else if (!strcasecmp(argv
[1],"notice")) server
.verbosity
= REDIS_NOTICE
;
1752 else if (!strcasecmp(argv
[1],"warning")) server
.verbosity
= REDIS_WARNING
;
1754 err
= "Invalid log level. Must be one of debug, notice, warning";
1757 } else if (!strcasecmp(argv
[0],"logfile") && argc
== 2) {
1760 server
.logfile
= zstrdup(argv
[1]);
1761 if (!strcasecmp(server
.logfile
,"stdout")) {
1762 zfree(server
.logfile
);
1763 server
.logfile
= NULL
;
1765 if (server
.logfile
) {
1766 /* Test if we are able to open the file. The server will not
1767 * be able to abort just for this problem later... */
1768 logfp
= fopen(server
.logfile
,"a");
1769 if (logfp
== NULL
) {
1770 err
= sdscatprintf(sdsempty(),
1771 "Can't open the log file: %s", strerror(errno
));
1776 } else if (!strcasecmp(argv
[0],"databases") && argc
== 2) {
1777 server
.dbnum
= atoi(argv
[1]);
1778 if (server
.dbnum
< 1) {
1779 err
= "Invalid number of databases"; goto loaderr
;
1781 } else if (!strcasecmp(argv
[0],"include") && argc
== 2) {
1782 loadServerConfig(argv
[1]);
1783 } else if (!strcasecmp(argv
[0],"maxclients") && argc
== 2) {
1784 server
.maxclients
= atoi(argv
[1]);
1785 } else if (!strcasecmp(argv
[0],"maxmemory") && argc
== 2) {
1786 server
.maxmemory
= strtoll(argv
[1], NULL
, 10);
1787 } else if (!strcasecmp(argv
[0],"slaveof") && argc
== 3) {
1788 server
.masterhost
= sdsnew(argv
[1]);
1789 server
.masterport
= atoi(argv
[2]);
1790 server
.replstate
= REDIS_REPL_CONNECT
;
1791 } else if (!strcasecmp(argv
[0],"masterauth") && argc
== 2) {
1792 server
.masterauth
= zstrdup(argv
[1]);
1793 } else if (!strcasecmp(argv
[0],"glueoutputbuf") && argc
== 2) {
1794 if ((server
.glueoutputbuf
= yesnotoi(argv
[1])) == -1) {
1795 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1797 } else if (!strcasecmp(argv
[0],"shareobjects") && argc
== 2) {
1798 if ((server
.shareobjects
= yesnotoi(argv
[1])) == -1) {
1799 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1801 } else if (!strcasecmp(argv
[0],"rdbcompression") && argc
== 2) {
1802 if ((server
.rdbcompression
= yesnotoi(argv
[1])) == -1) {
1803 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1805 } else if (!strcasecmp(argv
[0],"shareobjectspoolsize") && argc
== 2) {
1806 server
.sharingpoolsize
= atoi(argv
[1]);
1807 if (server
.sharingpoolsize
< 1) {
1808 err
= "invalid object sharing pool size"; goto loaderr
;
1810 } else if (!strcasecmp(argv
[0],"daemonize") && argc
== 2) {
1811 if ((server
.daemonize
= yesnotoi(argv
[1])) == -1) {
1812 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1814 } else if (!strcasecmp(argv
[0],"appendonly") && argc
== 2) {
1815 if ((server
.appendonly
= yesnotoi(argv
[1])) == -1) {
1816 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1818 } else if (!strcasecmp(argv
[0],"appendfsync") && argc
== 2) {
1819 if (!strcasecmp(argv
[1],"no")) {
1820 server
.appendfsync
= APPENDFSYNC_NO
;
1821 } else if (!strcasecmp(argv
[1],"always")) {
1822 server
.appendfsync
= APPENDFSYNC_ALWAYS
;
1823 } else if (!strcasecmp(argv
[1],"everysec")) {
1824 server
.appendfsync
= APPENDFSYNC_EVERYSEC
;
1826 err
= "argument must be 'no', 'always' or 'everysec'";
1829 } else if (!strcasecmp(argv
[0],"requirepass") && argc
== 2) {
1830 server
.requirepass
= zstrdup(argv
[1]);
1831 } else if (!strcasecmp(argv
[0],"pidfile") && argc
== 2) {
1832 zfree(server
.pidfile
);
1833 server
.pidfile
= zstrdup(argv
[1]);
1834 } else if (!strcasecmp(argv
[0],"dbfilename") && argc
== 2) {
1835 zfree(server
.dbfilename
);
1836 server
.dbfilename
= zstrdup(argv
[1]);
1837 } else if (!strcasecmp(argv
[0],"vm-enabled") && argc
== 2) {
1838 if ((server
.vm_enabled
= yesnotoi(argv
[1])) == -1) {
1839 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1841 } else if (!strcasecmp(argv
[0],"vm-swap-file") && argc
== 2) {
1842 zfree(server
.vm_swap_file
);
1843 server
.vm_swap_file
= zstrdup(argv
[1]);
1844 } else if (!strcasecmp(argv
[0],"vm-max-memory") && argc
== 2) {
1845 server
.vm_max_memory
= strtoll(argv
[1], NULL
, 10);
1846 } else if (!strcasecmp(argv
[0],"vm-page-size") && argc
== 2) {
1847 server
.vm_page_size
= strtoll(argv
[1], NULL
, 10);
1848 } else if (!strcasecmp(argv
[0],"vm-pages") && argc
== 2) {
1849 server
.vm_pages
= strtoll(argv
[1], NULL
, 10);
1850 } else if (!strcasecmp(argv
[0],"vm-max-threads") && argc
== 2) {
1851 server
.vm_max_threads
= strtoll(argv
[1], NULL
, 10);
1852 } else if (!strcasecmp(argv
[0],"hash-max-zipmap-entries") && argc
== 2){
1853 server
.hash_max_zipmap_entries
= strtol(argv
[1], NULL
, 10);
1854 } else if (!strcasecmp(argv
[0],"hash-max-zipmap-value") && argc
== 2){
1855 server
.hash_max_zipmap_value
= strtol(argv
[1], NULL
, 10);
1856 } else if (!strcasecmp(argv
[0],"vm-max-threads") && argc
== 2) {
1857 server
.vm_max_threads
= strtoll(argv
[1], NULL
, 10);
1859 err
= "Bad directive or wrong number of arguments"; goto loaderr
;
1861 for (j
= 0; j
< argc
; j
++)
1866 if (fp
!= stdin
) fclose(fp
);
1870 fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n");
1871 fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
);
1872 fprintf(stderr
, ">>> '%s'\n", line
);
1873 fprintf(stderr
, "%s\n", err
);
1877 static void freeClientArgv(redisClient
*c
) {
1880 for (j
= 0; j
< c
->argc
; j
++)
1881 decrRefCount(c
->argv
[j
]);
1882 for (j
= 0; j
< c
->mbargc
; j
++)
1883 decrRefCount(c
->mbargv
[j
]);
1888 static void freeClient(redisClient
*c
) {
1891 /* Note that if the client we are freeing is blocked into a blocking
1892 * call, we have to set querybuf to NULL *before* to call
1893 * unblockClientWaitingData() to avoid processInputBuffer() will get
1894 * called. Also it is important to remove the file events after
1895 * this, because this call adds the READABLE event. */
1896 sdsfree(c
->querybuf
);
1898 if (c
->flags
& REDIS_BLOCKED
)
1899 unblockClientWaitingData(c
);
1901 /* Unsubscribe from all the pubsub channels */
1902 pubsubUnsubscribeAllChannels(c
,0);
1903 pubsubUnsubscribeAllPatterns(c
,0);
1904 dictRelease(c
->pubsub_channels
);
1905 listRelease(c
->pubsub_patterns
);
1906 /* Obvious cleanup */
1907 aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
);
1908 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1909 listRelease(c
->reply
);
1912 /* Remove from the list of clients */
1913 ln
= listSearchKey(server
.clients
,c
);
1914 redisAssert(ln
!= NULL
);
1915 listDelNode(server
.clients
,ln
);
1916 /* Remove from the list of clients waiting for swapped keys */
1917 if (c
->flags
& REDIS_IO_WAIT
&& listLength(c
->io_keys
) == 0) {
1918 ln
= listSearchKey(server
.io_ready_clients
,c
);
1920 listDelNode(server
.io_ready_clients
,ln
);
1921 server
.vm_blocked_clients
--;
1924 while (server
.vm_enabled
&& listLength(c
->io_keys
)) {
1925 ln
= listFirst(c
->io_keys
);
1926 dontWaitForSwappedKey(c
,ln
->value
);
1928 listRelease(c
->io_keys
);
1929 /* Master/slave cleanup */
1930 if (c
->flags
& REDIS_SLAVE
) {
1931 if (c
->replstate
== REDIS_REPL_SEND_BULK
&& c
->repldbfd
!= -1)
1933 list
*l
= (c
->flags
& REDIS_MONITOR
) ? server
.monitors
: server
.slaves
;
1934 ln
= listSearchKey(l
,c
);
1935 redisAssert(ln
!= NULL
);
1938 if (c
->flags
& REDIS_MASTER
) {
1939 server
.master
= NULL
;
1940 server
.replstate
= REDIS_REPL_CONNECT
;
1942 /* Release memory */
1945 freeClientMultiState(c
);
1949 #define GLUEREPLY_UP_TO (1024)
1950 static void glueReplyBuffersIfNeeded(redisClient
*c
) {
1952 char buf
[GLUEREPLY_UP_TO
];
1957 listRewind(c
->reply
,&li
);
1958 while((ln
= listNext(&li
))) {
1962 objlen
= sdslen(o
->ptr
);
1963 if (copylen
+ objlen
<= GLUEREPLY_UP_TO
) {
1964 memcpy(buf
+copylen
,o
->ptr
,objlen
);
1966 listDelNode(c
->reply
,ln
);
1968 if (copylen
== 0) return;
1972 /* Now the output buffer is empty, add the new single element */
1973 o
= createObject(REDIS_STRING
,sdsnewlen(buf
,copylen
));
1974 listAddNodeHead(c
->reply
,o
);
1977 static void sendReplyToClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1978 redisClient
*c
= privdata
;
1979 int nwritten
= 0, totwritten
= 0, objlen
;
1982 REDIS_NOTUSED(mask
);
1984 /* Use writev() if we have enough buffers to send */
1985 if (!server
.glueoutputbuf
&&
1986 listLength(c
->reply
) > REDIS_WRITEV_THRESHOLD
&&
1987 !(c
->flags
& REDIS_MASTER
))
1989 sendReplyToClientWritev(el
, fd
, privdata
, mask
);
1993 while(listLength(c
->reply
)) {
1994 if (server
.glueoutputbuf
&& listLength(c
->reply
) > 1)
1995 glueReplyBuffersIfNeeded(c
);
1997 o
= listNodeValue(listFirst(c
->reply
));
1998 objlen
= sdslen(o
->ptr
);
2001 listDelNode(c
->reply
,listFirst(c
->reply
));
2005 if (c
->flags
& REDIS_MASTER
) {
2006 /* Don't reply to a master */
2007 nwritten
= objlen
- c
->sentlen
;
2009 nwritten
= write(fd
, ((char*)o
->ptr
)+c
->sentlen
, objlen
- c
->sentlen
);
2010 if (nwritten
<= 0) break;
2012 c
->sentlen
+= nwritten
;
2013 totwritten
+= nwritten
;
2014 /* If we fully sent the object on head go to the next one */
2015 if (c
->sentlen
== objlen
) {
2016 listDelNode(c
->reply
,listFirst(c
->reply
));
2019 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
2020 * bytes, in a single threaded server it's a good idea to serve
2021 * other clients as well, even if a very large request comes from
2022 * super fast link that is always able to accept data (in real world
2023 * scenario think about 'KEYS *' against the loopback interfae) */
2024 if (totwritten
> REDIS_MAX_WRITE_PER_EVENT
) break;
2026 if (nwritten
== -1) {
2027 if (errno
== EAGAIN
) {
2030 redisLog(REDIS_VERBOSE
,
2031 "Error writing to client: %s", strerror(errno
));
2036 if (totwritten
> 0) c
->lastinteraction
= time(NULL
);
2037 if (listLength(c
->reply
) == 0) {
2039 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
2043 static void sendReplyToClientWritev(aeEventLoop
*el
, int fd
, void *privdata
, int mask
)
2045 redisClient
*c
= privdata
;
2046 int nwritten
= 0, totwritten
= 0, objlen
, willwrite
;
2048 struct iovec iov
[REDIS_WRITEV_IOVEC_COUNT
];
2049 int offset
, ion
= 0;
2051 REDIS_NOTUSED(mask
);
2054 while (listLength(c
->reply
)) {
2055 offset
= c
->sentlen
;
2059 /* fill-in the iov[] array */
2060 for(node
= listFirst(c
->reply
); node
; node
= listNextNode(node
)) {
2061 o
= listNodeValue(node
);
2062 objlen
= sdslen(o
->ptr
);
2064 if (totwritten
+ objlen
- offset
> REDIS_MAX_WRITE_PER_EVENT
)
2067 if(ion
== REDIS_WRITEV_IOVEC_COUNT
)
2068 break; /* no more iovecs */
2070 iov
[ion
].iov_base
= ((char*)o
->ptr
) + offset
;
2071 iov
[ion
].iov_len
= objlen
- offset
;
2072 willwrite
+= objlen
- offset
;
2073 offset
= 0; /* just for the first item */
2080 /* write all collected blocks at once */
2081 if((nwritten
= writev(fd
, iov
, ion
)) < 0) {
2082 if (errno
!= EAGAIN
) {
2083 redisLog(REDIS_VERBOSE
,
2084 "Error writing to client: %s", strerror(errno
));
2091 totwritten
+= nwritten
;
2092 offset
= c
->sentlen
;
2094 /* remove written robjs from c->reply */
2095 while (nwritten
&& listLength(c
->reply
)) {
2096 o
= listNodeValue(listFirst(c
->reply
));
2097 objlen
= sdslen(o
->ptr
);
2099 if(nwritten
>= objlen
- offset
) {
2100 listDelNode(c
->reply
, listFirst(c
->reply
));
2101 nwritten
-= objlen
- offset
;
2105 c
->sentlen
+= nwritten
;
2113 c
->lastinteraction
= time(NULL
);
2115 if (listLength(c
->reply
) == 0) {
2117 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
2121 static struct redisCommand
*lookupCommand(char *name
) {
2123 while(cmdTable
[j
].name
!= NULL
) {
2124 if (!strcasecmp(name
,cmdTable
[j
].name
)) return &cmdTable
[j
];
2130 /* resetClient prepare the client to process the next command */
2131 static void resetClient(redisClient
*c
) {
2137 /* Call() is the core of Redis execution of a command */
2138 static void call(redisClient
*c
, struct redisCommand
*cmd
) {
2141 dirty
= server
.dirty
;
2143 dirty
= server
.dirty
-dirty
;
2145 if (server
.appendonly
&& dirty
)
2146 feedAppendOnlyFile(cmd
,c
->db
->id
,c
->argv
,c
->argc
);
2147 if ((dirty
|| cmd
->flags
& REDIS_CMD_FORCE_REPLICATION
) &&
2148 listLength(server
.slaves
))
2149 replicationFeedSlaves(server
.slaves
,c
->db
->id
,c
->argv
,c
->argc
);
2150 if (listLength(server
.monitors
))
2151 replicationFeedSlaves(server
.monitors
,c
->db
->id
,c
->argv
,c
->argc
);
2152 server
.stat_numcommands
++;
2155 /* If this function gets called we already read a whole
2156 * command, argments are in the client argv/argc fields.
2157 * processCommand() execute the command or prepare the
2158 * server for a bulk read from the client.
2160 * If 1 is returned the client is still alive and valid and
2161 * and other operations can be performed by the caller. Otherwise
2162 * if 0 is returned the client was destroied (i.e. after QUIT). */
2163 static int processCommand(redisClient
*c
) {
2164 struct redisCommand
*cmd
;
2166 /* Free some memory if needed (maxmemory setting) */
2167 if (server
.maxmemory
) freeMemoryIfNeeded();
2169 /* Handle the multi bulk command type. This is an alternative protocol
2170 * supported by Redis in order to receive commands that are composed of
2171 * multiple binary-safe "bulk" arguments. The latency of processing is
2172 * a bit higher but this allows things like multi-sets, so if this
2173 * protocol is used only for MSET and similar commands this is a big win. */
2174 if (c
->multibulk
== 0 && c
->argc
== 1 && ((char*)(c
->argv
[0]->ptr
))[0] == '*') {
2175 c
->multibulk
= atoi(((char*)c
->argv
[0]->ptr
)+1);
2176 if (c
->multibulk
<= 0) {
2180 decrRefCount(c
->argv
[c
->argc
-1]);
2184 } else if (c
->multibulk
) {
2185 if (c
->bulklen
== -1) {
2186 if (((char*)c
->argv
[0]->ptr
)[0] != '$') {
2187 addReplySds(c
,sdsnew("-ERR multi bulk protocol error\r\n"));
2191 int bulklen
= atoi(((char*)c
->argv
[0]->ptr
)+1);
2192 decrRefCount(c
->argv
[0]);
2193 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
2195 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
2200 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
2204 c
->mbargv
= zrealloc(c
->mbargv
,(sizeof(robj
*))*(c
->mbargc
+1));
2205 c
->mbargv
[c
->mbargc
] = c
->argv
[0];
2209 if (c
->multibulk
== 0) {
2213 /* Here we need to swap the multi-bulk argc/argv with the
2214 * normal argc/argv of the client structure. */
2216 c
->argv
= c
->mbargv
;
2217 c
->mbargv
= auxargv
;
2220 c
->argc
= c
->mbargc
;
2221 c
->mbargc
= auxargc
;
2223 /* We need to set bulklen to something different than -1
2224 * in order for the code below to process the command without
2225 * to try to read the last argument of a bulk command as
2226 * a special argument. */
2228 /* continue below and process the command */
2235 /* -- end of multi bulk commands processing -- */
2237 /* The QUIT command is handled as a special case. Normal command
2238 * procs are unable to close the client connection safely */
2239 if (!strcasecmp(c
->argv
[0]->ptr
,"quit")) {
2244 /* Now lookup the command and check ASAP about trivial error conditions
2245 * such wrong arity, bad command name and so forth. */
2246 cmd
= lookupCommand(c
->argv
[0]->ptr
);
2249 sdscatprintf(sdsempty(), "-ERR unknown command '%s'\r\n",
2250 (char*)c
->argv
[0]->ptr
));
2253 } else if ((cmd
->arity
> 0 && cmd
->arity
!= c
->argc
) ||
2254 (c
->argc
< -cmd
->arity
)) {
2256 sdscatprintf(sdsempty(),
2257 "-ERR wrong number of arguments for '%s' command\r\n",
2261 } else if (cmd
->flags
& REDIS_CMD_BULK
&& c
->bulklen
== -1) {
2262 /* This is a bulk command, we have to read the last argument yet. */
2263 int bulklen
= atoi(c
->argv
[c
->argc
-1]->ptr
);
2265 decrRefCount(c
->argv
[c
->argc
-1]);
2266 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
2268 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
2273 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
2274 /* It is possible that the bulk read is already in the
2275 * buffer. Check this condition and handle it accordingly.
2276 * This is just a fast path, alternative to call processInputBuffer().
2277 * It's a good idea since the code is small and this condition
2278 * happens most of the times. */
2279 if ((signed)sdslen(c
->querybuf
) >= c
->bulklen
) {
2280 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
2282 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
2284 /* Otherwise return... there is to read the last argument
2285 * from the socket. */
2289 /* Let's try to share objects on the command arguments vector */
2290 if (server
.shareobjects
) {
2292 for(j
= 1; j
< c
->argc
; j
++)
2293 c
->argv
[j
] = tryObjectSharing(c
->argv
[j
]);
2295 /* Let's try to encode the bulk object to save space. */
2296 if (cmd
->flags
& REDIS_CMD_BULK
)
2297 tryObjectEncoding(c
->argv
[c
->argc
-1]);
2299 /* Check if the user is authenticated */
2300 if (server
.requirepass
&& !c
->authenticated
&& cmd
->proc
!= authCommand
) {
2301 addReplySds(c
,sdsnew("-ERR operation not permitted\r\n"));
2306 /* Handle the maxmemory directive */
2307 if (server
.maxmemory
&& (cmd
->flags
& REDIS_CMD_DENYOOM
) &&
2308 zmalloc_used_memory() > server
.maxmemory
)
2310 addReplySds(c
,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
2315 /* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
2316 if (dictSize(c
->pubsub_channels
) > 0 &&
2317 cmd
->proc
!= subscribeCommand
&& cmd
->proc
!= unsubscribeCommand
&&
2318 cmd
->proc
!= psubscribeCommand
&& cmd
->proc
!= punsubscribeCommand
) {
2319 addReplySds(c
,sdsnew("-ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context\r\n"));
2324 /* Exec the command */
2325 if (c
->flags
& REDIS_MULTI
&& cmd
->proc
!= execCommand
&& cmd
->proc
!= discardCommand
) {
2326 queueMultiCommand(c
,cmd
);
2327 addReply(c
,shared
.queued
);
2329 if (server
.vm_enabled
&& server
.vm_max_threads
> 0 &&
2330 blockClientOnSwappedKeys(cmd
,c
)) return 1;
2334 /* Prepare the client for the next command */
2339 static void replicationFeedSlaves(list
*slaves
, int dictid
, robj
**argv
, int argc
) {
2344 /* We need 1+(ARGS*3) objects since commands are using the new protocol
2345 * and we one 1 object for the first "*<count>\r\n" multibulk count, then
2346 * for every additional object we have "$<count>\r\n" + object + "\r\n". */
2347 robj
*static_outv
[REDIS_STATIC_ARGS
*3+1];
2350 if (argc
<= REDIS_STATIC_ARGS
) {
2353 outv
= zmalloc(sizeof(robj
*)*(argc
*3+1));
2356 lenobj
= createObject(REDIS_STRING
,
2357 sdscatprintf(sdsempty(), "*%d\r\n", argc
));
2358 lenobj
->refcount
= 0;
2359 outv
[outc
++] = lenobj
;
2360 for (j
= 0; j
< argc
; j
++) {
2361 lenobj
= createObject(REDIS_STRING
,
2362 sdscatprintf(sdsempty(),"$%lu\r\n",
2363 (unsigned long) stringObjectLen(argv
[j
])));
2364 lenobj
->refcount
= 0;
2365 outv
[outc
++] = lenobj
;
2366 outv
[outc
++] = argv
[j
];
2367 outv
[outc
++] = shared
.crlf
;
2370 /* Increment all the refcounts at start and decrement at end in order to
2371 * be sure to free objects if there is no slave in a replication state
2372 * able to be feed with commands */
2373 for (j
= 0; j
< outc
; j
++) incrRefCount(outv
[j
]);
2374 listRewind(slaves
,&li
);
2375 while((ln
= listNext(&li
))) {
2376 redisClient
*slave
= ln
->value
;
2378 /* Don't feed slaves that are still waiting for BGSAVE to start */
2379 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) continue;
2381 /* Feed all the other slaves, MONITORs and so on */
2382 if (slave
->slaveseldb
!= dictid
) {
2386 case 0: selectcmd
= shared
.select0
; break;
2387 case 1: selectcmd
= shared
.select1
; break;
2388 case 2: selectcmd
= shared
.select2
; break;
2389 case 3: selectcmd
= shared
.select3
; break;
2390 case 4: selectcmd
= shared
.select4
; break;
2391 case 5: selectcmd
= shared
.select5
; break;
2392 case 6: selectcmd
= shared
.select6
; break;
2393 case 7: selectcmd
= shared
.select7
; break;
2394 case 8: selectcmd
= shared
.select8
; break;
2395 case 9: selectcmd
= shared
.select9
; break;
2397 selectcmd
= createObject(REDIS_STRING
,
2398 sdscatprintf(sdsempty(),"select %d\r\n",dictid
));
2399 selectcmd
->refcount
= 0;
2402 addReply(slave
,selectcmd
);
2403 slave
->slaveseldb
= dictid
;
2405 for (j
= 0; j
< outc
; j
++) addReply(slave
,outv
[j
]);
2407 for (j
= 0; j
< outc
; j
++) decrRefCount(outv
[j
]);
2408 if (outv
!= static_outv
) zfree(outv
);
2411 static void processInputBuffer(redisClient
*c
) {
2413 /* Before to process the input buffer, make sure the client is not
2414 * waitig for a blocking operation such as BLPOP. Note that the first
2415 * iteration the client is never blocked, otherwise the processInputBuffer
2416 * would not be called at all, but after the execution of the first commands
2417 * in the input buffer the client may be blocked, and the "goto again"
2418 * will try to reiterate. The following line will make it return asap. */
2419 if (c
->flags
& REDIS_BLOCKED
|| c
->flags
& REDIS_IO_WAIT
) return;
2420 if (c
->bulklen
== -1) {
2421 /* Read the first line of the query */
2422 char *p
= strchr(c
->querybuf
,'\n');
2429 query
= c
->querybuf
;
2430 c
->querybuf
= sdsempty();
2431 querylen
= 1+(p
-(query
));
2432 if (sdslen(query
) > querylen
) {
2433 /* leave data after the first line of the query in the buffer */
2434 c
->querybuf
= sdscatlen(c
->querybuf
,query
+querylen
,sdslen(query
)-querylen
);
2436 *p
= '\0'; /* remove "\n" */
2437 if (*(p
-1) == '\r') *(p
-1) = '\0'; /* and "\r" if any */
2438 sdsupdatelen(query
);
2440 /* Now we can split the query in arguments */
2441 argv
= sdssplitlen(query
,sdslen(query
)," ",1,&argc
);
2444 if (c
->argv
) zfree(c
->argv
);
2445 c
->argv
= zmalloc(sizeof(robj
*)*argc
);
2447 for (j
= 0; j
< argc
; j
++) {
2448 if (sdslen(argv
[j
])) {
2449 c
->argv
[c
->argc
] = createObject(REDIS_STRING
,argv
[j
]);
2457 /* Execute the command. If the client is still valid
2458 * after processCommand() return and there is something
2459 * on the query buffer try to process the next command. */
2460 if (processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
2462 /* Nothing to process, argc == 0. Just process the query
2463 * buffer if it's not empty or return to the caller */
2464 if (sdslen(c
->querybuf
)) goto again
;
2467 } else if (sdslen(c
->querybuf
) >= REDIS_REQUEST_MAX_SIZE
) {
2468 redisLog(REDIS_VERBOSE
, "Client protocol error");
2473 /* Bulk read handling. Note that if we are at this point
2474 the client already sent a command terminated with a newline,
2475 we are reading the bulk data that is actually the last
2476 argument of the command. */
2477 int qbl
= sdslen(c
->querybuf
);
2479 if (c
->bulklen
<= qbl
) {
2480 /* Copy everything but the final CRLF as final argument */
2481 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
2483 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
2484 /* Process the command. If the client is still valid after
2485 * the processing and there is more data in the buffer
2486 * try to parse it. */
2487 if (processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
2493 static void readQueryFromClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
2494 redisClient
*c
= (redisClient
*) privdata
;
2495 char buf
[REDIS_IOBUF_LEN
];
2498 REDIS_NOTUSED(mask
);
2500 nread
= read(fd
, buf
, REDIS_IOBUF_LEN
);
2502 if (errno
== EAGAIN
) {
2505 redisLog(REDIS_VERBOSE
, "Reading from client: %s",strerror(errno
));
2509 } else if (nread
== 0) {
2510 redisLog(REDIS_VERBOSE
, "Client closed connection");
2515 c
->querybuf
= sdscatlen(c
->querybuf
, buf
, nread
);
2516 c
->lastinteraction
= time(NULL
);
2520 processInputBuffer(c
);
2523 static int selectDb(redisClient
*c
, int id
) {
2524 if (id
< 0 || id
>= server
.dbnum
)
2526 c
->db
= &server
.db
[id
];
2530 static void *dupClientReplyValue(void *o
) {
2531 incrRefCount((robj
*)o
);
2535 static int listMatchObjects(void *a
, void *b
) {
2536 return compareStringObjects(a
,b
) == 0;
2539 static redisClient
*createClient(int fd
) {
2540 redisClient
*c
= zmalloc(sizeof(*c
));
2542 anetNonBlock(NULL
,fd
);
2543 anetTcpNoDelay(NULL
,fd
);
2544 if (!c
) return NULL
;
2547 c
->querybuf
= sdsempty();
2556 c
->lastinteraction
= time(NULL
);
2557 c
->authenticated
= 0;
2558 c
->replstate
= REDIS_REPL_NONE
;
2559 c
->reply
= listCreate();
2560 listSetFreeMethod(c
->reply
,decrRefCount
);
2561 listSetDupMethod(c
->reply
,dupClientReplyValue
);
2562 c
->blockingkeys
= NULL
;
2563 c
->blockingkeysnum
= 0;
2564 c
->io_keys
= listCreate();
2565 listSetFreeMethod(c
->io_keys
,decrRefCount
);
2566 c
->pubsub_channels
= dictCreate(&setDictType
,NULL
);
2567 c
->pubsub_patterns
= listCreate();
2568 listSetFreeMethod(c
->pubsub_patterns
,decrRefCount
);
2569 listSetMatchMethod(c
->pubsub_patterns
,listMatchObjects
);
2570 if (aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
,
2571 readQueryFromClient
, c
) == AE_ERR
) {
2575 listAddNodeTail(server
.clients
,c
);
2576 initClientMultiState(c
);
2580 static void addReply(redisClient
*c
, robj
*obj
) {
2581 if (listLength(c
->reply
) == 0 &&
2582 (c
->replstate
== REDIS_REPL_NONE
||
2583 c
->replstate
== REDIS_REPL_ONLINE
) &&
2584 aeCreateFileEvent(server
.el
, c
->fd
, AE_WRITABLE
,
2585 sendReplyToClient
, c
) == AE_ERR
) return;
2587 if (server
.vm_enabled
&& obj
->storage
!= REDIS_VM_MEMORY
) {
2588 obj
= dupStringObject(obj
);
2589 obj
->refcount
= 0; /* getDecodedObject() will increment the refcount */
2591 listAddNodeTail(c
->reply
,getDecodedObject(obj
));
2594 static void addReplySds(redisClient
*c
, sds s
) {
2595 robj
*o
= createObject(REDIS_STRING
,s
);
2600 static void addReplyDouble(redisClient
*c
, double d
) {
2603 snprintf(buf
,sizeof(buf
),"%.17g",d
);
2604 addReplySds(c
,sdscatprintf(sdsempty(),"$%lu\r\n%s\r\n",
2605 (unsigned long) strlen(buf
),buf
));
2608 static void addReplyLong(redisClient
*c
, long l
) {
2613 addReply(c
,shared
.czero
);
2615 } else if (l
== 1) {
2616 addReply(c
,shared
.cone
);
2619 len
= snprintf(buf
,sizeof(buf
),":%ld\r\n",l
);
2620 addReplySds(c
,sdsnewlen(buf
,len
));
2623 static void addReplyLongLong(redisClient
*c
, long long ll
) {
2628 addReply(c
,shared
.czero
);
2630 } else if (ll
== 1) {
2631 addReply(c
,shared
.cone
);
2634 len
= snprintf(buf
,sizeof(buf
),":%lld\r\n",ll
);
2635 addReplySds(c
,sdsnewlen(buf
,len
));
2638 static void addReplyUlong(redisClient
*c
, unsigned long ul
) {
2643 addReply(c
,shared
.czero
);
2645 } else if (ul
== 1) {
2646 addReply(c
,shared
.cone
);
2649 len
= snprintf(buf
,sizeof(buf
),":%lu\r\n",ul
);
2650 addReplySds(c
,sdsnewlen(buf
,len
));
2653 static void addReplyBulkLen(redisClient
*c
, robj
*obj
) {
2656 if (obj
->encoding
== REDIS_ENCODING_RAW
) {
2657 len
= sdslen(obj
->ptr
);
2659 long n
= (long)obj
->ptr
;
2661 /* Compute how many bytes will take this integer as a radix 10 string */
2667 while((n
= n
/10) != 0) {
2671 addReplySds(c
,sdscatprintf(sdsempty(),"$%lu\r\n",(unsigned long)len
));
2674 static void addReplyBulk(redisClient
*c
, robj
*obj
) {
2675 addReplyBulkLen(c
,obj
);
2677 addReply(c
,shared
.crlf
);
2680 /* In the CONFIG command we need to add vanilla C string as bulk replies */
2681 static void addReplyBulkCString(redisClient
*c
, char *s
) {
2683 addReply(c
,shared
.nullbulk
);
2685 robj
*o
= createStringObject(s
,strlen(s
));
2691 static void acceptHandler(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
2696 REDIS_NOTUSED(mask
);
2697 REDIS_NOTUSED(privdata
);
2699 cfd
= anetAccept(server
.neterr
, fd
, cip
, &cport
);
2700 if (cfd
== AE_ERR
) {
2701 redisLog(REDIS_VERBOSE
,"Accepting client connection: %s", server
.neterr
);
2704 redisLog(REDIS_VERBOSE
,"Accepted %s:%d", cip
, cport
);
2705 if ((c
= createClient(cfd
)) == NULL
) {
2706 redisLog(REDIS_WARNING
,"Error allocating resoures for the client");
2707 close(cfd
); /* May be already closed, just ingore errors */
2710 /* If maxclient directive is set and this is one client more... close the
2711 * connection. Note that we create the client instead to check before
2712 * for this condition, since now the socket is already set in nonblocking
2713 * mode and we can send an error for free using the Kernel I/O */
2714 if (server
.maxclients
&& listLength(server
.clients
) > server
.maxclients
) {
2715 char *err
= "-ERR max number of clients reached\r\n";
2717 /* That's a best effort error message, don't check write errors */
2718 if (write(c
->fd
,err
,strlen(err
)) == -1) {
2719 /* Nothing to do, Just to avoid the warning... */
2724 server
.stat_numconnections
++;
2727 /* ======================= Redis objects implementation ===================== */
2729 static robj
*createObject(int type
, void *ptr
) {
2732 if (server
.vm_enabled
) pthread_mutex_lock(&server
.obj_freelist_mutex
);
2733 if (listLength(server
.objfreelist
)) {
2734 listNode
*head
= listFirst(server
.objfreelist
);
2735 o
= listNodeValue(head
);
2736 listDelNode(server
.objfreelist
,head
);
2737 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
2739 if (server
.vm_enabled
) {
2740 pthread_mutex_unlock(&server
.obj_freelist_mutex
);
2741 o
= zmalloc(sizeof(*o
));
2743 o
= zmalloc(sizeof(*o
)-sizeof(struct redisObjectVM
));
2747 o
->encoding
= REDIS_ENCODING_RAW
;
2750 if (server
.vm_enabled
) {
2751 /* Note that this code may run in the context of an I/O thread
2752 * and accessing to server.unixtime in theory is an error
2753 * (no locks). But in practice this is safe, and even if we read
2754 * garbage Redis will not fail, as it's just a statistical info */
2755 o
->vm
.atime
= server
.unixtime
;
2756 o
->storage
= REDIS_VM_MEMORY
;
2761 static robj
*createStringObject(char *ptr
, size_t len
) {
2762 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
2765 static robj
*dupStringObject(robj
*o
) {
2766 assert(o
->encoding
== REDIS_ENCODING_RAW
);
2767 return createStringObject(o
->ptr
,sdslen(o
->ptr
));
2770 static robj
*createListObject(void) {
2771 list
*l
= listCreate();
2773 listSetFreeMethod(l
,decrRefCount
);
2774 return createObject(REDIS_LIST
,l
);
2777 static robj
*createSetObject(void) {
2778 dict
*d
= dictCreate(&setDictType
,NULL
);
2779 return createObject(REDIS_SET
,d
);
2782 static robj
*createHashObject(void) {
2783 /* All the Hashes start as zipmaps. Will be automatically converted
2784 * into hash tables if there are enough elements or big elements
2786 unsigned char *zm
= zipmapNew();
2787 robj
*o
= createObject(REDIS_HASH
,zm
);
2788 o
->encoding
= REDIS_ENCODING_ZIPMAP
;
2792 static robj
*createZsetObject(void) {
2793 zset
*zs
= zmalloc(sizeof(*zs
));
2795 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
2796 zs
->zsl
= zslCreate();
2797 return createObject(REDIS_ZSET
,zs
);
2800 static void freeStringObject(robj
*o
) {
2801 if (o
->encoding
== REDIS_ENCODING_RAW
) {
2806 static void freeListObject(robj
*o
) {
2807 listRelease((list
*) o
->ptr
);
2810 static void freeSetObject(robj
*o
) {
2811 dictRelease((dict
*) o
->ptr
);
2814 static void freeZsetObject(robj
*o
) {
2817 dictRelease(zs
->dict
);
2822 static void freeHashObject(robj
*o
) {
2823 switch (o
->encoding
) {
2824 case REDIS_ENCODING_HT
:
2825 dictRelease((dict
*) o
->ptr
);
2827 case REDIS_ENCODING_ZIPMAP
:
2836 static void incrRefCount(robj
*o
) {
2840 static void decrRefCount(void *obj
) {
2843 /* Object is a key of a swapped out value, or in the process of being
2845 if (server
.vm_enabled
&&
2846 (o
->storage
== REDIS_VM_SWAPPED
|| o
->storage
== REDIS_VM_LOADING
))
2848 if (o
->storage
== REDIS_VM_SWAPPED
|| o
->storage
== REDIS_VM_LOADING
) {
2849 redisAssert(o
->refcount
== 1);
2851 if (o
->storage
== REDIS_VM_LOADING
) vmCancelThreadedIOJob(obj
);
2852 redisAssert(o
->type
== REDIS_STRING
);
2853 freeStringObject(o
);
2854 vmMarkPagesFree(o
->vm
.page
,o
->vm
.usedpages
);
2855 pthread_mutex_lock(&server
.obj_freelist_mutex
);
2856 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
2857 !listAddNodeHead(server
.objfreelist
,o
))
2859 pthread_mutex_unlock(&server
.obj_freelist_mutex
);
2860 server
.vm_stats_swapped_objects
--;
2863 /* Object is in memory, or in the process of being swapped out. */
2864 if (--(o
->refcount
) == 0) {
2865 if (server
.vm_enabled
&& o
->storage
== REDIS_VM_SWAPPING
)
2866 vmCancelThreadedIOJob(obj
);
2868 case REDIS_STRING
: freeStringObject(o
); break;
2869 case REDIS_LIST
: freeListObject(o
); break;
2870 case REDIS_SET
: freeSetObject(o
); break;
2871 case REDIS_ZSET
: freeZsetObject(o
); break;
2872 case REDIS_HASH
: freeHashObject(o
); break;
2873 default: redisAssert(0); break;
2875 if (server
.vm_enabled
) pthread_mutex_lock(&server
.obj_freelist_mutex
);
2876 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
2877 !listAddNodeHead(server
.objfreelist
,o
))
2879 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
2883 static robj
*lookupKey(redisDb
*db
, robj
*key
) {
2884 dictEntry
*de
= dictFind(db
->dict
,key
);
2886 robj
*key
= dictGetEntryKey(de
);
2887 robj
*val
= dictGetEntryVal(de
);
2889 if (server
.vm_enabled
) {
2890 if (key
->storage
== REDIS_VM_MEMORY
||
2891 key
->storage
== REDIS_VM_SWAPPING
)
2893 /* If we were swapping the object out, stop it, this key
2895 if (key
->storage
== REDIS_VM_SWAPPING
)
2896 vmCancelThreadedIOJob(key
);
2897 /* Update the access time of the key for the aging algorithm. */
2898 key
->vm
.atime
= server
.unixtime
;
2900 int notify
= (key
->storage
== REDIS_VM_LOADING
);
2902 /* Our value was swapped on disk. Bring it at home. */
2903 redisAssert(val
== NULL
);
2904 val
= vmLoadObject(key
);
2905 dictGetEntryVal(de
) = val
;
2907 /* Clients blocked by the VM subsystem may be waiting for
2909 if (notify
) handleClientsBlockedOnSwappedKey(db
,key
);
2918 static robj
*lookupKeyRead(redisDb
*db
, robj
*key
) {
2919 expireIfNeeded(db
,key
);
2920 return lookupKey(db
,key
);
2923 static robj
*lookupKeyWrite(redisDb
*db
, robj
*key
) {
2924 deleteIfVolatile(db
,key
);
2925 return lookupKey(db
,key
);
2928 static robj
*lookupKeyReadOrReply(redisClient
*c
, robj
*key
, robj
*reply
) {
2929 robj
*o
= lookupKeyRead(c
->db
, key
);
2930 if (!o
) addReply(c
,reply
);
2934 static robj
*lookupKeyWriteOrReply(redisClient
*c
, robj
*key
, robj
*reply
) {
2935 robj
*o
= lookupKeyWrite(c
->db
, key
);
2936 if (!o
) addReply(c
,reply
);
2940 static int checkType(redisClient
*c
, robj
*o
, int type
) {
2941 if (o
->type
!= type
) {
2942 addReply(c
,shared
.wrongtypeerr
);
2948 static int deleteKey(redisDb
*db
, robj
*key
) {
2951 /* We need to protect key from destruction: after the first dictDelete()
2952 * it may happen that 'key' is no longer valid if we don't increment
2953 * it's count. This may happen when we get the object reference directly
2954 * from the hash table with dictRandomKey() or dict iterators */
2956 if (dictSize(db
->expires
)) dictDelete(db
->expires
,key
);
2957 retval
= dictDelete(db
->dict
,key
);
2960 return retval
== DICT_OK
;
2963 /* Try to share an object against the shared objects pool */
2964 static robj
*tryObjectSharing(robj
*o
) {
2965 struct dictEntry
*de
;
2968 if (o
== NULL
|| server
.shareobjects
== 0) return o
;
2970 redisAssert(o
->type
== REDIS_STRING
);
2971 de
= dictFind(server
.sharingpool
,o
);
2973 robj
*shared
= dictGetEntryKey(de
);
2975 c
= ((unsigned long) dictGetEntryVal(de
))+1;
2976 dictGetEntryVal(de
) = (void*) c
;
2977 incrRefCount(shared
);
2981 /* Here we are using a stream algorihtm: Every time an object is
2982 * shared we increment its count, everytime there is a miss we
2983 * recrement the counter of a random object. If this object reaches
2984 * zero we remove the object and put the current object instead. */
2985 if (dictSize(server
.sharingpool
) >=
2986 server
.sharingpoolsize
) {
2987 de
= dictGetRandomKey(server
.sharingpool
);
2988 redisAssert(de
!= NULL
);
2989 c
= ((unsigned long) dictGetEntryVal(de
))-1;
2990 dictGetEntryVal(de
) = (void*) c
;
2992 dictDelete(server
.sharingpool
,de
->key
);
2995 c
= 0; /* If the pool is empty we want to add this object */
3000 retval
= dictAdd(server
.sharingpool
,o
,(void*)1);
3001 redisAssert(retval
== DICT_OK
);
3008 /* Check if the nul-terminated string 's' can be represented by a long
3009 * (that is, is a number that fits into long without any other space or
3010 * character before or after the digits).
3012 * If so, the function returns REDIS_OK and *longval is set to the value
3013 * of the number. Otherwise REDIS_ERR is returned */
3014 static int isStringRepresentableAsLong(sds s
, long *longval
) {
3015 char buf
[32], *endptr
;
3019 value
= strtol(s
, &endptr
, 10);
3020 if (endptr
[0] != '\0') return REDIS_ERR
;
3021 slen
= snprintf(buf
,32,"%ld",value
);
3023 /* If the number converted back into a string is not identical
3024 * then it's not possible to encode the string as integer */
3025 if (sdslen(s
) != (unsigned)slen
|| memcmp(buf
,s
,slen
)) return REDIS_ERR
;
3026 if (longval
) *longval
= value
;
3030 /* Try to encode a string object in order to save space */
3031 static int tryObjectEncoding(robj
*o
) {
3035 if (o
->encoding
!= REDIS_ENCODING_RAW
)
3036 return REDIS_ERR
; /* Already encoded */
3038 /* It's not save to encode shared objects: shared objects can be shared
3039 * everywhere in the "object space" of Redis. Encoded objects can only
3040 * appear as "values" (and not, for instance, as keys) */
3041 if (o
->refcount
> 1) return REDIS_ERR
;
3043 /* Currently we try to encode only strings */
3044 redisAssert(o
->type
== REDIS_STRING
);
3046 /* Check if we can represent this string as a long integer */
3047 if (isStringRepresentableAsLong(s
,&value
) == REDIS_ERR
) return REDIS_ERR
;
3049 /* Ok, this object can be encoded */
3050 o
->encoding
= REDIS_ENCODING_INT
;
3052 o
->ptr
= (void*) value
;
3056 /* Get a decoded version of an encoded object (returned as a new object).
3057 * If the object is already raw-encoded just increment the ref count. */
3058 static robj
*getDecodedObject(robj
*o
) {
3061 if (o
->encoding
== REDIS_ENCODING_RAW
) {
3065 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
3068 snprintf(buf
,32,"%ld",(long)o
->ptr
);
3069 dec
= createStringObject(buf
,strlen(buf
));
3072 redisAssert(1 != 1);
3076 /* Compare two string objects via strcmp() or alike.
3077 * Note that the objects may be integer-encoded. In such a case we
3078 * use snprintf() to get a string representation of the numbers on the stack
3079 * and compare the strings, it's much faster than calling getDecodedObject().
3081 * Important note: if objects are not integer encoded, but binary-safe strings,
3082 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
3084 static int compareStringObjects(robj
*a
, robj
*b
) {
3085 redisAssert(a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
3086 char bufa
[128], bufb
[128], *astr
, *bstr
;
3089 if (a
== b
) return 0;
3090 if (a
->encoding
!= REDIS_ENCODING_RAW
) {
3091 snprintf(bufa
,sizeof(bufa
),"%ld",(long) a
->ptr
);
3097 if (b
->encoding
!= REDIS_ENCODING_RAW
) {
3098 snprintf(bufb
,sizeof(bufb
),"%ld",(long) b
->ptr
);
3104 return bothsds
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
);
3107 static size_t stringObjectLen(robj
*o
) {
3108 redisAssert(o
->type
== REDIS_STRING
);
3109 if (o
->encoding
== REDIS_ENCODING_RAW
) {
3110 return sdslen(o
->ptr
);
3114 return snprintf(buf
,32,"%ld",(long)o
->ptr
);
3118 /*============================ RDB saving/loading =========================== */
3120 static int rdbSaveType(FILE *fp
, unsigned char type
) {
3121 if (fwrite(&type
,1,1,fp
) == 0) return -1;
3125 static int rdbSaveTime(FILE *fp
, time_t t
) {
3126 int32_t t32
= (int32_t) t
;
3127 if (fwrite(&t32
,4,1,fp
) == 0) return -1;
3131 /* check rdbLoadLen() comments for more info */
3132 static int rdbSaveLen(FILE *fp
, uint32_t len
) {
3133 unsigned char buf
[2];
3136 /* Save a 6 bit len */
3137 buf
[0] = (len
&0xFF)|(REDIS_RDB_6BITLEN
<<6);
3138 if (fwrite(buf
,1,1,fp
) == 0) return -1;
3139 } else if (len
< (1<<14)) {
3140 /* Save a 14 bit len */
3141 buf
[0] = ((len
>>8)&0xFF)|(REDIS_RDB_14BITLEN
<<6);
3143 if (fwrite(buf
,2,1,fp
) == 0) return -1;
3145 /* Save a 32 bit len */
3146 buf
[0] = (REDIS_RDB_32BITLEN
<<6);
3147 if (fwrite(buf
,1,1,fp
) == 0) return -1;
3149 if (fwrite(&len
,4,1,fp
) == 0) return -1;
3154 /* String objects in the form "2391" "-100" without any space and with a
3155 * range of values that can fit in an 8, 16 or 32 bit signed value can be
3156 * encoded as integers to save space */
3157 static int rdbTryIntegerEncoding(char *s
, size_t len
, unsigned char *enc
) {
3159 char *endptr
, buf
[32];
3161 /* Check if it's possible to encode this value as a number */
3162 value
= strtoll(s
, &endptr
, 10);
3163 if (endptr
[0] != '\0') return 0;
3164 snprintf(buf
,32,"%lld",value
);
3166 /* If the number converted back into a string is not identical
3167 * then it's not possible to encode the string as integer */
3168 if (strlen(buf
) != len
|| memcmp(buf
,s
,len
)) return 0;
3170 /* Finally check if it fits in our ranges */
3171 if (value
>= -(1<<7) && value
<= (1<<7)-1) {
3172 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT8
;
3173 enc
[1] = value
&0xFF;
3175 } else if (value
>= -(1<<15) && value
<= (1<<15)-1) {
3176 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT16
;
3177 enc
[1] = value
&0xFF;
3178 enc
[2] = (value
>>8)&0xFF;
3180 } else if (value
>= -((long long)1<<31) && value
<= ((long long)1<<31)-1) {
3181 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT32
;
3182 enc
[1] = value
&0xFF;
3183 enc
[2] = (value
>>8)&0xFF;
3184 enc
[3] = (value
>>16)&0xFF;
3185 enc
[4] = (value
>>24)&0xFF;
3192 static int rdbSaveLzfStringObject(FILE *fp
, unsigned char *s
, size_t len
) {
3193 size_t comprlen
, outlen
;
3197 /* We require at least four bytes compression for this to be worth it */
3198 if (len
<= 4) return 0;
3200 if ((out
= zmalloc(outlen
+1)) == NULL
) return 0;
3201 comprlen
= lzf_compress(s
, len
, out
, outlen
);
3202 if (comprlen
== 0) {
3206 /* Data compressed! Let's save it on disk */
3207 byte
= (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_LZF
;
3208 if (fwrite(&byte
,1,1,fp
) == 0) goto writeerr
;
3209 if (rdbSaveLen(fp
,comprlen
) == -1) goto writeerr
;
3210 if (rdbSaveLen(fp
,len
) == -1) goto writeerr
;
3211 if (fwrite(out
,comprlen
,1,fp
) == 0) goto writeerr
;
3220 /* Save a string objet as [len][data] on disk. If the object is a string
3221 * representation of an integer value we try to safe it in a special form */
3222 static int rdbSaveRawString(FILE *fp
, unsigned char *s
, size_t len
) {
3225 /* Try integer encoding */
3227 unsigned char buf
[5];
3228 if ((enclen
= rdbTryIntegerEncoding((char*)s
,len
,buf
)) > 0) {
3229 if (fwrite(buf
,enclen
,1,fp
) == 0) return -1;
3234 /* Try LZF compression - under 20 bytes it's unable to compress even
3235 * aaaaaaaaaaaaaaaaaa so skip it */
3236 if (server
.rdbcompression
&& len
> 20) {
3239 retval
= rdbSaveLzfStringObject(fp
,s
,len
);
3240 if (retval
== -1) return -1;
3241 if (retval
> 0) return 0;
3242 /* retval == 0 means data can't be compressed, save the old way */
3245 /* Store verbatim */
3246 if (rdbSaveLen(fp
,len
) == -1) return -1;
3247 if (len
&& fwrite(s
,len
,1,fp
) == 0) return -1;
3251 /* Like rdbSaveStringObjectRaw() but handle encoded objects */
3252 static int rdbSaveStringObject(FILE *fp
, robj
*obj
) {
3255 /* Avoid incr/decr ref count business when possible.
3256 * This plays well with copy-on-write given that we are probably
3257 * in a child process (BGSAVE). Also this makes sure key objects
3258 * of swapped objects are not incRefCount-ed (an assert does not allow
3259 * this in order to avoid bugs) */
3260 if (obj
->encoding
!= REDIS_ENCODING_RAW
) {
3261 obj
= getDecodedObject(obj
);
3262 retval
= rdbSaveRawString(fp
,obj
->ptr
,sdslen(obj
->ptr
));
3265 retval
= rdbSaveRawString(fp
,obj
->ptr
,sdslen(obj
->ptr
));
3270 /* Save a double value. Doubles are saved as strings prefixed by an unsigned
3271 * 8 bit integer specifing the length of the representation.
3272 * This 8 bit integer has special values in order to specify the following
3278 static int rdbSaveDoubleValue(FILE *fp
, double val
) {
3279 unsigned char buf
[128];
3285 } else if (!isfinite(val
)) {
3287 buf
[0] = (val
< 0) ? 255 : 254;
3289 snprintf((char*)buf
+1,sizeof(buf
)-1,"%.17g",val
);
3290 buf
[0] = strlen((char*)buf
+1);
3293 if (fwrite(buf
,len
,1,fp
) == 0) return -1;
3297 /* Save a Redis object. */
3298 static int rdbSaveObject(FILE *fp
, robj
*o
) {
3299 if (o
->type
== REDIS_STRING
) {
3300 /* Save a string value */
3301 if (rdbSaveStringObject(fp
,o
) == -1) return -1;
3302 } else if (o
->type
== REDIS_LIST
) {
3303 /* Save a list value */
3304 list
*list
= o
->ptr
;
3308 if (rdbSaveLen(fp
,listLength(list
)) == -1) return -1;
3309 listRewind(list
,&li
);
3310 while((ln
= listNext(&li
))) {
3311 robj
*eleobj
= listNodeValue(ln
);
3313 if (rdbSaveStringObject(fp
,eleobj
) == -1) return -1;
3315 } else if (o
->type
== REDIS_SET
) {
3316 /* Save a set value */
3318 dictIterator
*di
= dictGetIterator(set
);
3321 if (rdbSaveLen(fp
,dictSize(set
)) == -1) return -1;
3322 while((de
= dictNext(di
)) != NULL
) {
3323 robj
*eleobj
= dictGetEntryKey(de
);
3325 if (rdbSaveStringObject(fp
,eleobj
) == -1) return -1;
3327 dictReleaseIterator(di
);
3328 } else if (o
->type
== REDIS_ZSET
) {
3329 /* Save a set value */
3331 dictIterator
*di
= dictGetIterator(zs
->dict
);
3334 if (rdbSaveLen(fp
,dictSize(zs
->dict
)) == -1) return -1;
3335 while((de
= dictNext(di
)) != NULL
) {
3336 robj
*eleobj
= dictGetEntryKey(de
);
3337 double *score
= dictGetEntryVal(de
);
3339 if (rdbSaveStringObject(fp
,eleobj
) == -1) return -1;
3340 if (rdbSaveDoubleValue(fp
,*score
) == -1) return -1;
3342 dictReleaseIterator(di
);
3343 } else if (o
->type
== REDIS_HASH
) {
3344 /* Save a hash value */
3345 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
3346 unsigned char *p
= zipmapRewind(o
->ptr
);
3347 unsigned int count
= zipmapLen(o
->ptr
);
3348 unsigned char *key
, *val
;
3349 unsigned int klen
, vlen
;
3351 if (rdbSaveLen(fp
,count
) == -1) return -1;
3352 while((p
= zipmapNext(p
,&key
,&klen
,&val
,&vlen
)) != NULL
) {
3353 if (rdbSaveRawString(fp
,key
,klen
) == -1) return -1;
3354 if (rdbSaveRawString(fp
,val
,vlen
) == -1) return -1;
3357 dictIterator
*di
= dictGetIterator(o
->ptr
);
3360 if (rdbSaveLen(fp
,dictSize((dict
*)o
->ptr
)) == -1) return -1;
3361 while((de
= dictNext(di
)) != NULL
) {
3362 robj
*key
= dictGetEntryKey(de
);
3363 robj
*val
= dictGetEntryVal(de
);
3365 if (rdbSaveStringObject(fp
,key
) == -1) return -1;
3366 if (rdbSaveStringObject(fp
,val
) == -1) return -1;
3368 dictReleaseIterator(di
);
3376 /* Return the length the object will have on disk if saved with
3377 * the rdbSaveObject() function. Currently we use a trick to get
3378 * this length with very little changes to the code. In the future
3379 * we could switch to a faster solution. */
3380 static off_t
rdbSavedObjectLen(robj
*o
, FILE *fp
) {
3381 if (fp
== NULL
) fp
= server
.devnull
;
3383 assert(rdbSaveObject(fp
,o
) != 1);
3387 /* Return the number of pages required to save this object in the swap file */
3388 static off_t
rdbSavedObjectPages(robj
*o
, FILE *fp
) {
3389 off_t bytes
= rdbSavedObjectLen(o
,fp
);
3391 return (bytes
+(server
.vm_page_size
-1))/server
.vm_page_size
;
3394 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
3395 static int rdbSave(char *filename
) {
3396 dictIterator
*di
= NULL
;
3401 time_t now
= time(NULL
);
3403 /* Wait for I/O therads to terminate, just in case this is a
3404 * foreground-saving, to avoid seeking the swap file descriptor at the
3406 if (server
.vm_enabled
)
3407 waitEmptyIOJobsQueue();
3409 snprintf(tmpfile
,256,"temp-%d.rdb", (int) getpid());
3410 fp
= fopen(tmpfile
,"w");
3412 redisLog(REDIS_WARNING
, "Failed saving the DB: %s", strerror(errno
));
3415 if (fwrite("REDIS0001",9,1,fp
) == 0) goto werr
;
3416 for (j
= 0; j
< server
.dbnum
; j
++) {
3417 redisDb
*db
= server
.db
+j
;
3419 if (dictSize(d
) == 0) continue;
3420 di
= dictGetIterator(d
);
3426 /* Write the SELECT DB opcode */
3427 if (rdbSaveType(fp
,REDIS_SELECTDB
) == -1) goto werr
;
3428 if (rdbSaveLen(fp
,j
) == -1) goto werr
;
3430 /* Iterate this DB writing every entry */
3431 while((de
= dictNext(di
)) != NULL
) {
3432 robj
*key
= dictGetEntryKey(de
);
3433 robj
*o
= dictGetEntryVal(de
);
3434 time_t expiretime
= getExpire(db
,key
);
3436 /* Save the expire time */
3437 if (expiretime
!= -1) {
3438 /* If this key is already expired skip it */
3439 if (expiretime
< now
) continue;
3440 if (rdbSaveType(fp
,REDIS_EXPIRETIME
) == -1) goto werr
;
3441 if (rdbSaveTime(fp
,expiretime
) == -1) goto werr
;
3443 /* Save the key and associated value. This requires special
3444 * handling if the value is swapped out. */
3445 if (!server
.vm_enabled
|| key
->storage
== REDIS_VM_MEMORY
||
3446 key
->storage
== REDIS_VM_SWAPPING
) {
3447 /* Save type, key, value */
3448 if (rdbSaveType(fp
,o
->type
) == -1) goto werr
;
3449 if (rdbSaveStringObject(fp
,key
) == -1) goto werr
;
3450 if (rdbSaveObject(fp
,o
) == -1) goto werr
;
3452 /* REDIS_VM_SWAPPED or REDIS_VM_LOADING */
3454 /* Get a preview of the object in memory */
3455 po
= vmPreviewObject(key
);
3456 /* Save type, key, value */
3457 if (rdbSaveType(fp
,key
->vtype
) == -1) goto werr
;
3458 if (rdbSaveStringObject(fp
,key
) == -1) goto werr
;
3459 if (rdbSaveObject(fp
,po
) == -1) goto werr
;
3460 /* Remove the loaded object from memory */
3464 dictReleaseIterator(di
);
3467 if (rdbSaveType(fp
,REDIS_EOF
) == -1) goto werr
;
3469 /* Make sure data will not remain on the OS's output buffers */
3474 /* Use RENAME to make sure the DB file is changed atomically only
3475 * if the generate DB file is ok. */
3476 if (rename(tmpfile
,filename
) == -1) {
3477 redisLog(REDIS_WARNING
,"Error moving temp DB file on the final destination: %s", strerror(errno
));
3481 redisLog(REDIS_NOTICE
,"DB saved on disk");
3483 server
.lastsave
= time(NULL
);
3489 redisLog(REDIS_WARNING
,"Write error saving DB on disk: %s", strerror(errno
));
3490 if (di
) dictReleaseIterator(di
);
3494 static int rdbSaveBackground(char *filename
) {
3497 if (server
.bgsavechildpid
!= -1) return REDIS_ERR
;
3498 if (server
.vm_enabled
) waitEmptyIOJobsQueue();
3499 if ((childpid
= fork()) == 0) {
3501 if (server
.vm_enabled
) vmReopenSwapFile();
3503 if (rdbSave(filename
) == REDIS_OK
) {
3510 if (childpid
== -1) {
3511 redisLog(REDIS_WARNING
,"Can't save in background: fork: %s",
3515 redisLog(REDIS_NOTICE
,"Background saving started by pid %d",childpid
);
3516 server
.bgsavechildpid
= childpid
;
3517 updateDictResizePolicy();
3520 return REDIS_OK
; /* unreached */
3523 static void rdbRemoveTempFile(pid_t childpid
) {
3526 snprintf(tmpfile
,256,"temp-%d.rdb", (int) childpid
);
3530 static int rdbLoadType(FILE *fp
) {
3532 if (fread(&type
,1,1,fp
) == 0) return -1;
3536 static time_t rdbLoadTime(FILE *fp
) {
3538 if (fread(&t32
,4,1,fp
) == 0) return -1;
3539 return (time_t) t32
;
3542 /* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
3543 * of this file for a description of how this are stored on disk.
3545 * isencoded is set to 1 if the readed length is not actually a length but
3546 * an "encoding type", check the above comments for more info */
3547 static uint32_t rdbLoadLen(FILE *fp
, int *isencoded
) {
3548 unsigned char buf
[2];
3552 if (isencoded
) *isencoded
= 0;
3553 if (fread(buf
,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
3554 type
= (buf
[0]&0xC0)>>6;
3555 if (type
== REDIS_RDB_6BITLEN
) {
3556 /* Read a 6 bit len */
3558 } else if (type
== REDIS_RDB_ENCVAL
) {
3559 /* Read a 6 bit len encoding type */
3560 if (isencoded
) *isencoded
= 1;
3562 } else if (type
== REDIS_RDB_14BITLEN
) {
3563 /* Read a 14 bit len */
3564 if (fread(buf
+1,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
3565 return ((buf
[0]&0x3F)<<8)|buf
[1];
3567 /* Read a 32 bit len */
3568 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
3573 static robj
*rdbLoadIntegerObject(FILE *fp
, int enctype
) {
3574 unsigned char enc
[4];
3577 if (enctype
== REDIS_RDB_ENC_INT8
) {
3578 if (fread(enc
,1,1,fp
) == 0) return NULL
;
3579 val
= (signed char)enc
[0];
3580 } else if (enctype
== REDIS_RDB_ENC_INT16
) {
3582 if (fread(enc
,2,1,fp
) == 0) return NULL
;
3583 v
= enc
[0]|(enc
[1]<<8);
3585 } else if (enctype
== REDIS_RDB_ENC_INT32
) {
3587 if (fread(enc
,4,1,fp
) == 0) return NULL
;
3588 v
= enc
[0]|(enc
[1]<<8)|(enc
[2]<<16)|(enc
[3]<<24);
3591 val
= 0; /* anti-warning */
3594 return createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",val
));
3597 static robj
*rdbLoadLzfStringObject(FILE*fp
) {
3598 unsigned int len
, clen
;
3599 unsigned char *c
= NULL
;
3602 if ((clen
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3603 if ((len
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3604 if ((c
= zmalloc(clen
)) == NULL
) goto err
;
3605 if ((val
= sdsnewlen(NULL
,len
)) == NULL
) goto err
;
3606 if (fread(c
,clen
,1,fp
) == 0) goto err
;
3607 if (lzf_decompress(c
,clen
,val
,len
) == 0) goto err
;
3609 return createObject(REDIS_STRING
,val
);
3616 static robj
*rdbLoadStringObject(FILE*fp
) {
3621 len
= rdbLoadLen(fp
,&isencoded
);
3624 case REDIS_RDB_ENC_INT8
:
3625 case REDIS_RDB_ENC_INT16
:
3626 case REDIS_RDB_ENC_INT32
:
3627 return tryObjectSharing(rdbLoadIntegerObject(fp
,len
));
3628 case REDIS_RDB_ENC_LZF
:
3629 return tryObjectSharing(rdbLoadLzfStringObject(fp
));
3635 if (len
== REDIS_RDB_LENERR
) return NULL
;
3636 val
= sdsnewlen(NULL
,len
);
3637 if (len
&& fread(val
,len
,1,fp
) == 0) {
3641 return tryObjectSharing(createObject(REDIS_STRING
,val
));
3644 /* For information about double serialization check rdbSaveDoubleValue() */
3645 static int rdbLoadDoubleValue(FILE *fp
, double *val
) {
3649 if (fread(&len
,1,1,fp
) == 0) return -1;
3651 case 255: *val
= R_NegInf
; return 0;
3652 case 254: *val
= R_PosInf
; return 0;
3653 case 253: *val
= R_Nan
; return 0;
3655 if (fread(buf
,len
,1,fp
) == 0) return -1;
3657 sscanf(buf
, "%lg", val
);
3662 /* Load a Redis object of the specified type from the specified file.
3663 * On success a newly allocated object is returned, otherwise NULL. */
3664 static robj
*rdbLoadObject(int type
, FILE *fp
) {
3667 redisLog(REDIS_DEBUG
,"LOADING OBJECT %d (at %d)\n",type
,ftell(fp
));
3668 if (type
== REDIS_STRING
) {
3669 /* Read string value */
3670 if ((o
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3671 tryObjectEncoding(o
);
3672 } else if (type
== REDIS_LIST
|| type
== REDIS_SET
) {
3673 /* Read list/set value */
3676 if ((listlen
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3677 o
= (type
== REDIS_LIST
) ? createListObject() : createSetObject();
3678 /* It's faster to expand the dict to the right size asap in order
3679 * to avoid rehashing */
3680 if (type
== REDIS_SET
&& listlen
> DICT_HT_INITIAL_SIZE
)
3681 dictExpand(o
->ptr
,listlen
);
3682 /* Load every single element of the list/set */
3686 if ((ele
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3687 tryObjectEncoding(ele
);
3688 if (type
== REDIS_LIST
) {
3689 listAddNodeTail((list
*)o
->ptr
,ele
);
3691 dictAdd((dict
*)o
->ptr
,ele
,NULL
);
3694 } else if (type
== REDIS_ZSET
) {
3695 /* Read list/set value */
3699 if ((zsetlen
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3700 o
= createZsetObject();
3702 /* Load every single element of the list/set */
3705 double *score
= zmalloc(sizeof(double));
3707 if ((ele
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3708 tryObjectEncoding(ele
);
3709 if (rdbLoadDoubleValue(fp
,score
) == -1) return NULL
;
3710 dictAdd(zs
->dict
,ele
,score
);
3711 zslInsert(zs
->zsl
,*score
,ele
);
3712 incrRefCount(ele
); /* added to skiplist */
3714 } else if (type
== REDIS_HASH
) {
3717 if ((hashlen
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3718 o
= createHashObject();
3719 /* Too many entries? Use an hash table. */
3720 if (hashlen
> server
.hash_max_zipmap_entries
)
3721 convertToRealHash(o
);
3722 /* Load every key/value, then set it into the zipmap or hash
3723 * table, as needed. */
3727 if ((key
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3728 if ((val
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3729 /* If we are using a zipmap and there are too big values
3730 * the object is converted to real hash table encoding. */
3731 if (o
->encoding
!= REDIS_ENCODING_HT
&&
3732 (sdslen(key
->ptr
) > server
.hash_max_zipmap_value
||
3733 sdslen(val
->ptr
) > server
.hash_max_zipmap_value
))
3735 convertToRealHash(o
);
3738 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
3739 unsigned char *zm
= o
->ptr
;
3741 zm
= zipmapSet(zm
,key
->ptr
,sdslen(key
->ptr
),
3742 val
->ptr
,sdslen(val
->ptr
),NULL
);
3747 tryObjectEncoding(key
);
3748 tryObjectEncoding(val
);
3749 dictAdd((dict
*)o
->ptr
,key
,val
);
3758 static int rdbLoad(char *filename
) {
3760 robj
*keyobj
= NULL
;
3762 int type
, retval
, rdbver
;
3763 dict
*d
= server
.db
[0].dict
;
3764 redisDb
*db
= server
.db
+0;
3766 time_t expiretime
= -1, now
= time(NULL
);
3767 long long loadedkeys
= 0;
3769 fp
= fopen(filename
,"r");
3770 if (!fp
) return REDIS_ERR
;
3771 if (fread(buf
,9,1,fp
) == 0) goto eoferr
;
3773 if (memcmp(buf
,"REDIS",5) != 0) {
3775 redisLog(REDIS_WARNING
,"Wrong signature trying to load DB from file");
3778 rdbver
= atoi(buf
+5);
3781 redisLog(REDIS_WARNING
,"Can't handle RDB format version %d",rdbver
);
3788 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
3789 if (type
== REDIS_EXPIRETIME
) {
3790 if ((expiretime
= rdbLoadTime(fp
)) == -1) goto eoferr
;
3791 /* We read the time so we need to read the object type again */
3792 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
3794 if (type
== REDIS_EOF
) break;
3795 /* Handle SELECT DB opcode as a special case */
3796 if (type
== REDIS_SELECTDB
) {
3797 if ((dbid
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
)
3799 if (dbid
>= (unsigned)server
.dbnum
) {
3800 redisLog(REDIS_WARNING
,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server
.dbnum
);
3803 db
= server
.db
+dbid
;
3808 if ((keyobj
= rdbLoadStringObject(fp
)) == NULL
) goto eoferr
;
3810 if ((o
= rdbLoadObject(type
,fp
)) == NULL
) goto eoferr
;
3811 /* Add the new object in the hash table */
3812 retval
= dictAdd(d
,keyobj
,o
);
3813 if (retval
== DICT_ERR
) {
3814 redisLog(REDIS_WARNING
,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj
->ptr
);
3817 /* Set the expire time if needed */
3818 if (expiretime
!= -1) {
3819 setExpire(db
,keyobj
,expiretime
);
3820 /* Delete this key if already expired */
3821 if (expiretime
< now
) deleteKey(db
,keyobj
);
3825 /* Handle swapping while loading big datasets when VM is on */
3827 if (server
.vm_enabled
&& (loadedkeys
% 5000) == 0) {
3828 while (zmalloc_used_memory() > server
.vm_max_memory
) {
3829 if (vmSwapOneObjectBlocking() == REDIS_ERR
) break;
3836 eoferr
: /* unexpected end of file is handled here with a fatal exit */
3837 if (keyobj
) decrRefCount(keyobj
);
3838 redisLog(REDIS_WARNING
,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
3840 return REDIS_ERR
; /* Just to avoid warning */
3843 /*================================== Commands =============================== */
3845 static void authCommand(redisClient
*c
) {
3846 if (!server
.requirepass
|| !strcmp(c
->argv
[1]->ptr
, server
.requirepass
)) {
3847 c
->authenticated
= 1;
3848 addReply(c
,shared
.ok
);
3850 c
->authenticated
= 0;
3851 addReplySds(c
,sdscatprintf(sdsempty(),"-ERR invalid password\r\n"));
3855 static void pingCommand(redisClient
*c
) {
3856 addReply(c
,shared
.pong
);
3859 static void echoCommand(redisClient
*c
) {
3860 addReplyBulk(c
,c
->argv
[1]);
3863 /*=================================== Strings =============================== */
3865 static void setGenericCommand(redisClient
*c
, int nx
) {
3868 if (nx
) deleteIfVolatile(c
->db
,c
->argv
[1]);
3869 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
3870 if (retval
== DICT_ERR
) {
3872 /* If the key is about a swapped value, we want a new key object
3873 * to overwrite the old. So we delete the old key in the database.
3874 * This will also make sure that swap pages about the old object
3875 * will be marked as free. */
3876 if (server
.vm_enabled
&& deleteIfSwapped(c
->db
,c
->argv
[1]))
3877 incrRefCount(c
->argv
[1]);
3878 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
3879 incrRefCount(c
->argv
[2]);
3881 addReply(c
,shared
.czero
);
3885 incrRefCount(c
->argv
[1]);
3886 incrRefCount(c
->argv
[2]);
3889 removeExpire(c
->db
,c
->argv
[1]);
3890 addReply(c
, nx
? shared
.cone
: shared
.ok
);
3893 static void setCommand(redisClient
*c
) {
3894 setGenericCommand(c
,0);
3897 static void setnxCommand(redisClient
*c
) {
3898 setGenericCommand(c
,1);
3901 static int getGenericCommand(redisClient
*c
) {
3904 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
)
3907 if (o
->type
!= REDIS_STRING
) {
3908 addReply(c
,shared
.wrongtypeerr
);
3916 static void getCommand(redisClient
*c
) {
3917 getGenericCommand(c
);
3920 static void getsetCommand(redisClient
*c
) {
3921 if (getGenericCommand(c
) == REDIS_ERR
) return;
3922 if (dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]) == DICT_ERR
) {
3923 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
3925 incrRefCount(c
->argv
[1]);
3927 incrRefCount(c
->argv
[2]);
3929 removeExpire(c
->db
,c
->argv
[1]);
3932 static void mgetCommand(redisClient
*c
) {
3935 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",c
->argc
-1));
3936 for (j
= 1; j
< c
->argc
; j
++) {
3937 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
3939 addReply(c
,shared
.nullbulk
);
3941 if (o
->type
!= REDIS_STRING
) {
3942 addReply(c
,shared
.nullbulk
);
3950 static void msetGenericCommand(redisClient
*c
, int nx
) {
3951 int j
, busykeys
= 0;
3953 if ((c
->argc
% 2) == 0) {
3954 addReplySds(c
,sdsnew("-ERR wrong number of arguments for MSET\r\n"));
3957 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
3958 * set nothing at all if at least one already key exists. */
3960 for (j
= 1; j
< c
->argc
; j
+= 2) {
3961 if (lookupKeyWrite(c
->db
,c
->argv
[j
]) != NULL
) {
3967 addReply(c
, shared
.czero
);
3971 for (j
= 1; j
< c
->argc
; j
+= 2) {
3974 tryObjectEncoding(c
->argv
[j
+1]);
3975 retval
= dictAdd(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
3976 if (retval
== DICT_ERR
) {
3977 dictReplace(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
3978 incrRefCount(c
->argv
[j
+1]);
3980 incrRefCount(c
->argv
[j
]);
3981 incrRefCount(c
->argv
[j
+1]);
3983 removeExpire(c
->db
,c
->argv
[j
]);
3985 server
.dirty
+= (c
->argc
-1)/2;
3986 addReply(c
, nx
? shared
.cone
: shared
.ok
);
3989 static void msetCommand(redisClient
*c
) {
3990 msetGenericCommand(c
,0);
3993 static void msetnxCommand(redisClient
*c
) {
3994 msetGenericCommand(c
,1);
3997 static void incrDecrCommand(redisClient
*c
, long long incr
) {
4002 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4006 if (o
->type
!= REDIS_STRING
) {
4011 if (o
->encoding
== REDIS_ENCODING_RAW
)
4012 value
= strtoll(o
->ptr
, &eptr
, 10);
4013 else if (o
->encoding
== REDIS_ENCODING_INT
)
4014 value
= (long)o
->ptr
;
4016 redisAssert(1 != 1);
4021 o
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",value
));
4022 tryObjectEncoding(o
);
4023 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],o
);
4024 if (retval
== DICT_ERR
) {
4025 dictReplace(c
->db
->dict
,c
->argv
[1],o
);
4026 removeExpire(c
->db
,c
->argv
[1]);
4028 incrRefCount(c
->argv
[1]);
4031 addReply(c
,shared
.colon
);
4033 addReply(c
,shared
.crlf
);
4036 static void incrCommand(redisClient
*c
) {
4037 incrDecrCommand(c
,1);
4040 static void decrCommand(redisClient
*c
) {
4041 incrDecrCommand(c
,-1);
4044 static void incrbyCommand(redisClient
*c
) {
4045 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
4046 incrDecrCommand(c
,incr
);
4049 static void decrbyCommand(redisClient
*c
) {
4050 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
4051 incrDecrCommand(c
,-incr
);
4054 static void appendCommand(redisClient
*c
) {
4059 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4061 /* Create the key */
4062 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
4063 incrRefCount(c
->argv
[1]);
4064 incrRefCount(c
->argv
[2]);
4065 totlen
= stringObjectLen(c
->argv
[2]);
4069 de
= dictFind(c
->db
->dict
,c
->argv
[1]);
4072 o
= dictGetEntryVal(de
);
4073 if (o
->type
!= REDIS_STRING
) {
4074 addReply(c
,shared
.wrongtypeerr
);
4077 /* If the object is specially encoded or shared we have to make
4079 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
4080 robj
*decoded
= getDecodedObject(o
);
4082 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
4083 decrRefCount(decoded
);
4084 dictReplace(c
->db
->dict
,c
->argv
[1],o
);
4087 if (c
->argv
[2]->encoding
== REDIS_ENCODING_RAW
) {
4088 o
->ptr
= sdscatlen(o
->ptr
,
4089 c
->argv
[2]->ptr
, sdslen(c
->argv
[2]->ptr
));
4091 o
->ptr
= sdscatprintf(o
->ptr
, "%ld",
4092 (unsigned long) c
->argv
[2]->ptr
);
4094 totlen
= sdslen(o
->ptr
);
4097 addReplySds(c
,sdscatprintf(sdsempty(),":%lu\r\n",(unsigned long)totlen
));
4100 static void substrCommand(redisClient
*c
) {
4102 long start
= atoi(c
->argv
[2]->ptr
);
4103 long end
= atoi(c
->argv
[3]->ptr
);
4104 size_t rangelen
, strlen
;
4107 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4108 checkType(c
,o
,REDIS_STRING
)) return;
4110 o
= getDecodedObject(o
);
4111 strlen
= sdslen(o
->ptr
);
4113 /* convert negative indexes */
4114 if (start
< 0) start
= strlen
+start
;
4115 if (end
< 0) end
= strlen
+end
;
4116 if (start
< 0) start
= 0;
4117 if (end
< 0) end
= 0;
4119 /* indexes sanity checks */
4120 if (start
> end
|| (size_t)start
>= strlen
) {
4121 /* Out of range start or start > end result in null reply */
4122 addReply(c
,shared
.nullbulk
);
4126 if ((size_t)end
>= strlen
) end
= strlen
-1;
4127 rangelen
= (end
-start
)+1;
4129 /* Return the result */
4130 addReplySds(c
,sdscatprintf(sdsempty(),"$%zu\r\n",rangelen
));
4131 range
= sdsnewlen((char*)o
->ptr
+start
,rangelen
);
4132 addReplySds(c
,range
);
4133 addReply(c
,shared
.crlf
);
4137 /* ========================= Type agnostic commands ========================= */
4139 static void delCommand(redisClient
*c
) {
4142 for (j
= 1; j
< c
->argc
; j
++) {
4143 if (deleteKey(c
->db
,c
->argv
[j
])) {
4148 addReplyLong(c
,deleted
);
4151 static void existsCommand(redisClient
*c
) {
4152 addReply(c
,lookupKeyRead(c
->db
,c
->argv
[1]) ? shared
.cone
: shared
.czero
);
4155 static void selectCommand(redisClient
*c
) {
4156 int id
= atoi(c
->argv
[1]->ptr
);
4158 if (selectDb(c
,id
) == REDIS_ERR
) {
4159 addReplySds(c
,sdsnew("-ERR invalid DB index\r\n"));
4161 addReply(c
,shared
.ok
);
4165 static void randomkeyCommand(redisClient
*c
) {
4169 de
= dictGetRandomKey(c
->db
->dict
);
4170 if (!de
|| expireIfNeeded(c
->db
,dictGetEntryKey(de
)) == 0) break;
4173 addReply(c
,shared
.plus
);
4174 addReply(c
,shared
.crlf
);
4176 addReply(c
,shared
.plus
);
4177 addReply(c
,dictGetEntryKey(de
));
4178 addReply(c
,shared
.crlf
);
4182 static void keysCommand(redisClient
*c
) {
4185 sds pattern
= c
->argv
[1]->ptr
;
4186 int plen
= sdslen(pattern
);
4187 unsigned long numkeys
= 0;
4188 robj
*lenobj
= createObject(REDIS_STRING
,NULL
);
4190 di
= dictGetIterator(c
->db
->dict
);
4192 decrRefCount(lenobj
);
4193 while((de
= dictNext(di
)) != NULL
) {
4194 robj
*keyobj
= dictGetEntryKey(de
);
4196 sds key
= keyobj
->ptr
;
4197 if ((pattern
[0] == '*' && pattern
[1] == '\0') ||
4198 stringmatchlen(pattern
,plen
,key
,sdslen(key
),0)) {
4199 if (expireIfNeeded(c
->db
,keyobj
) == 0) {
4200 addReplyBulk(c
,keyobj
);
4205 dictReleaseIterator(di
);
4206 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%lu\r\n",numkeys
);
4209 static void dbsizeCommand(redisClient
*c
) {
4211 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c
->db
->dict
)));
4214 static void lastsaveCommand(redisClient
*c
) {
4216 sdscatprintf(sdsempty(),":%lu\r\n",server
.lastsave
));
4219 static void typeCommand(redisClient
*c
) {
4223 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4228 case REDIS_STRING
: type
= "+string"; break;
4229 case REDIS_LIST
: type
= "+list"; break;
4230 case REDIS_SET
: type
= "+set"; break;
4231 case REDIS_ZSET
: type
= "+zset"; break;
4232 case REDIS_HASH
: type
= "+hash"; break;
4233 default: type
= "+unknown"; break;
4236 addReplySds(c
,sdsnew(type
));
4237 addReply(c
,shared
.crlf
);
4240 static void saveCommand(redisClient
*c
) {
4241 if (server
.bgsavechildpid
!= -1) {
4242 addReplySds(c
,sdsnew("-ERR background save in progress\r\n"));
4245 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
4246 addReply(c
,shared
.ok
);
4248 addReply(c
,shared
.err
);
4252 static void bgsaveCommand(redisClient
*c
) {
4253 if (server
.bgsavechildpid
!= -1) {
4254 addReplySds(c
,sdsnew("-ERR background save already in progress\r\n"));
4257 if (rdbSaveBackground(server
.dbfilename
) == REDIS_OK
) {
4258 char *status
= "+Background saving started\r\n";
4259 addReplySds(c
,sdsnew(status
));
4261 addReply(c
,shared
.err
);
4265 static void shutdownCommand(redisClient
*c
) {
4266 redisLog(REDIS_WARNING
,"User requested shutdown, saving DB...");
4267 /* Kill the saving child if there is a background saving in progress.
4268 We want to avoid race conditions, for instance our saving child may
4269 overwrite the synchronous saving did by SHUTDOWN. */
4270 if (server
.bgsavechildpid
!= -1) {
4271 redisLog(REDIS_WARNING
,"There is a live saving child. Killing it!");
4272 kill(server
.bgsavechildpid
,SIGKILL
);
4273 rdbRemoveTempFile(server
.bgsavechildpid
);
4275 if (server
.appendonly
) {
4276 /* Append only file: fsync() the AOF and exit */
4277 fsync(server
.appendfd
);
4278 if (server
.vm_enabled
) unlink(server
.vm_swap_file
);
4281 /* Snapshotting. Perform a SYNC SAVE and exit */
4282 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
4283 if (server
.daemonize
)
4284 unlink(server
.pidfile
);
4285 redisLog(REDIS_WARNING
,"%zu bytes used at exit",zmalloc_used_memory());
4286 redisLog(REDIS_WARNING
,"Server exit now, bye bye...");
4287 if (server
.vm_enabled
) unlink(server
.vm_swap_file
);
4290 /* Ooops.. error saving! The best we can do is to continue
4291 * operating. Note that if there was a background saving process,
4292 * in the next cron() Redis will be notified that the background
4293 * saving aborted, handling special stuff like slaves pending for
4294 * synchronization... */
4295 redisLog(REDIS_WARNING
,"Error trying to save the DB, can't exit");
4297 sdsnew("-ERR can't quit, problems saving the DB\r\n"));
4302 static void renameGenericCommand(redisClient
*c
, int nx
) {
4305 /* To use the same key as src and dst is probably an error */
4306 if (sdscmp(c
->argv
[1]->ptr
,c
->argv
[2]->ptr
) == 0) {
4307 addReply(c
,shared
.sameobjecterr
);
4311 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.nokeyerr
)) == NULL
)
4315 deleteIfVolatile(c
->db
,c
->argv
[2]);
4316 if (dictAdd(c
->db
->dict
,c
->argv
[2],o
) == DICT_ERR
) {
4319 addReply(c
,shared
.czero
);
4322 dictReplace(c
->db
->dict
,c
->argv
[2],o
);
4324 incrRefCount(c
->argv
[2]);
4326 deleteKey(c
->db
,c
->argv
[1]);
4328 addReply(c
,nx
? shared
.cone
: shared
.ok
);
4331 static void renameCommand(redisClient
*c
) {
4332 renameGenericCommand(c
,0);
4335 static void renamenxCommand(redisClient
*c
) {
4336 renameGenericCommand(c
,1);
4339 static void moveCommand(redisClient
*c
) {
4344 /* Obtain source and target DB pointers */
4347 if (selectDb(c
,atoi(c
->argv
[2]->ptr
)) == REDIS_ERR
) {
4348 addReply(c
,shared
.outofrangeerr
);
4352 selectDb(c
,srcid
); /* Back to the source DB */
4354 /* If the user is moving using as target the same
4355 * DB as the source DB it is probably an error. */
4357 addReply(c
,shared
.sameobjecterr
);
4361 /* Check if the element exists and get a reference */
4362 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4364 addReply(c
,shared
.czero
);
4368 /* Try to add the element to the target DB */
4369 deleteIfVolatile(dst
,c
->argv
[1]);
4370 if (dictAdd(dst
->dict
,c
->argv
[1],o
) == DICT_ERR
) {
4371 addReply(c
,shared
.czero
);
4374 incrRefCount(c
->argv
[1]);
4377 /* OK! key moved, free the entry in the source DB */
4378 deleteKey(src
,c
->argv
[1]);
4380 addReply(c
,shared
.cone
);
4383 /* =================================== Lists ================================ */
4384 static void pushGenericCommand(redisClient
*c
, int where
) {
4388 lobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4390 if (handleClientsWaitingListPush(c
,c
->argv
[1],c
->argv
[2])) {
4391 addReply(c
,shared
.cone
);
4394 lobj
= createListObject();
4396 if (where
== REDIS_HEAD
) {
4397 listAddNodeHead(list
,c
->argv
[2]);
4399 listAddNodeTail(list
,c
->argv
[2]);
4401 dictAdd(c
->db
->dict
,c
->argv
[1],lobj
);
4402 incrRefCount(c
->argv
[1]);
4403 incrRefCount(c
->argv
[2]);
4405 if (lobj
->type
!= REDIS_LIST
) {
4406 addReply(c
,shared
.wrongtypeerr
);
4409 if (handleClientsWaitingListPush(c
,c
->argv
[1],c
->argv
[2])) {
4410 addReply(c
,shared
.cone
);
4414 if (where
== REDIS_HEAD
) {
4415 listAddNodeHead(list
,c
->argv
[2]);
4417 listAddNodeTail(list
,c
->argv
[2]);
4419 incrRefCount(c
->argv
[2]);
4422 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",listLength(list
)));
4425 static void lpushCommand(redisClient
*c
) {
4426 pushGenericCommand(c
,REDIS_HEAD
);
4429 static void rpushCommand(redisClient
*c
) {
4430 pushGenericCommand(c
,REDIS_TAIL
);
4433 static void llenCommand(redisClient
*c
) {
4437 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
4438 checkType(c
,o
,REDIS_LIST
)) return;
4441 addReplyUlong(c
,listLength(l
));
4444 static void lindexCommand(redisClient
*c
) {
4446 int index
= atoi(c
->argv
[2]->ptr
);
4450 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4451 checkType(c
,o
,REDIS_LIST
)) return;
4454 ln
= listIndex(list
, index
);
4456 addReply(c
,shared
.nullbulk
);
4458 robj
*ele
= listNodeValue(ln
);
4459 addReplyBulk(c
,ele
);
4463 static void lsetCommand(redisClient
*c
) {
4465 int index
= atoi(c
->argv
[2]->ptr
);
4469 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.nokeyerr
)) == NULL
||
4470 checkType(c
,o
,REDIS_LIST
)) return;
4473 ln
= listIndex(list
, index
);
4475 addReply(c
,shared
.outofrangeerr
);
4477 robj
*ele
= listNodeValue(ln
);
4480 listNodeValue(ln
) = c
->argv
[3];
4481 incrRefCount(c
->argv
[3]);
4482 addReply(c
,shared
.ok
);
4487 static void popGenericCommand(redisClient
*c
, int where
) {
4492 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4493 checkType(c
,o
,REDIS_LIST
)) return;
4496 if (where
== REDIS_HEAD
)
4497 ln
= listFirst(list
);
4499 ln
= listLast(list
);
4502 addReply(c
,shared
.nullbulk
);
4504 robj
*ele
= listNodeValue(ln
);
4505 addReplyBulk(c
,ele
);
4506 listDelNode(list
,ln
);
4507 if (listLength(list
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4512 static void lpopCommand(redisClient
*c
) {
4513 popGenericCommand(c
,REDIS_HEAD
);
4516 static void rpopCommand(redisClient
*c
) {
4517 popGenericCommand(c
,REDIS_TAIL
);
4520 static void lrangeCommand(redisClient
*c
) {
4522 int start
= atoi(c
->argv
[2]->ptr
);
4523 int end
= atoi(c
->argv
[3]->ptr
);
4530 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullmultibulk
)) == NULL
||
4531 checkType(c
,o
,REDIS_LIST
)) return;
4533 llen
= listLength(list
);
4535 /* convert negative indexes */
4536 if (start
< 0) start
= llen
+start
;
4537 if (end
< 0) end
= llen
+end
;
4538 if (start
< 0) start
= 0;
4539 if (end
< 0) end
= 0;
4541 /* indexes sanity checks */
4542 if (start
> end
|| start
>= llen
) {
4543 /* Out of range start or start > end result in empty list */
4544 addReply(c
,shared
.emptymultibulk
);
4547 if (end
>= llen
) end
= llen
-1;
4548 rangelen
= (end
-start
)+1;
4550 /* Return the result in form of a multi-bulk reply */
4551 ln
= listIndex(list
, start
);
4552 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",rangelen
));
4553 for (j
= 0; j
< rangelen
; j
++) {
4554 ele
= listNodeValue(ln
);
4555 addReplyBulk(c
,ele
);
4560 static void ltrimCommand(redisClient
*c
) {
4562 int start
= atoi(c
->argv
[2]->ptr
);
4563 int end
= atoi(c
->argv
[3]->ptr
);
4565 int j
, ltrim
, rtrim
;
4569 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.ok
)) == NULL
||
4570 checkType(c
,o
,REDIS_LIST
)) return;
4572 llen
= listLength(list
);
4574 /* convert negative indexes */
4575 if (start
< 0) start
= llen
+start
;
4576 if (end
< 0) end
= llen
+end
;
4577 if (start
< 0) start
= 0;
4578 if (end
< 0) end
= 0;
4580 /* indexes sanity checks */
4581 if (start
> end
|| start
>= llen
) {
4582 /* Out of range start or start > end result in empty list */
4586 if (end
>= llen
) end
= llen
-1;
4591 /* Remove list elements to perform the trim */
4592 for (j
= 0; j
< ltrim
; j
++) {
4593 ln
= listFirst(list
);
4594 listDelNode(list
,ln
);
4596 for (j
= 0; j
< rtrim
; j
++) {
4597 ln
= listLast(list
);
4598 listDelNode(list
,ln
);
4600 if (listLength(list
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4602 addReply(c
,shared
.ok
);
4605 static void lremCommand(redisClient
*c
) {
4608 listNode
*ln
, *next
;
4609 int toremove
= atoi(c
->argv
[2]->ptr
);
4613 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
4614 checkType(c
,o
,REDIS_LIST
)) return;
4618 toremove
= -toremove
;
4621 ln
= fromtail
? list
->tail
: list
->head
;
4623 robj
*ele
= listNodeValue(ln
);
4625 next
= fromtail
? ln
->prev
: ln
->next
;
4626 if (compareStringObjects(ele
,c
->argv
[3]) == 0) {
4627 listDelNode(list
,ln
);
4630 if (toremove
&& removed
== toremove
) break;
4634 if (listLength(list
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4635 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",removed
));
4638 /* This is the semantic of this command:
4639 * RPOPLPUSH srclist dstlist:
4640 * IF LLEN(srclist) > 0
4641 * element = RPOP srclist
4642 * LPUSH dstlist element
4649 * The idea is to be able to get an element from a list in a reliable way
4650 * since the element is not just returned but pushed against another list
4651 * as well. This command was originally proposed by Ezra Zygmuntowicz.
4653 static void rpoplpushcommand(redisClient
*c
) {
4658 if ((sobj
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4659 checkType(c
,sobj
,REDIS_LIST
)) return;
4660 srclist
= sobj
->ptr
;
4661 ln
= listLast(srclist
);
4664 addReply(c
,shared
.nullbulk
);
4666 robj
*dobj
= lookupKeyWrite(c
->db
,c
->argv
[2]);
4667 robj
*ele
= listNodeValue(ln
);
4670 if (dobj
&& dobj
->type
!= REDIS_LIST
) {
4671 addReply(c
,shared
.wrongtypeerr
);
4675 /* Add the element to the target list (unless it's directly
4676 * passed to some BLPOP-ing client */
4677 if (!handleClientsWaitingListPush(c
,c
->argv
[2],ele
)) {
4679 /* Create the list if the key does not exist */
4680 dobj
= createListObject();
4681 dictAdd(c
->db
->dict
,c
->argv
[2],dobj
);
4682 incrRefCount(c
->argv
[2]);
4684 dstlist
= dobj
->ptr
;
4685 listAddNodeHead(dstlist
,ele
);
4689 /* Send the element to the client as reply as well */
4690 addReplyBulk(c
,ele
);
4692 /* Finally remove the element from the source list */
4693 listDelNode(srclist
,ln
);
4694 if (listLength(srclist
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4699 /* ==================================== Sets ================================ */
4701 static void saddCommand(redisClient
*c
) {
4704 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4706 set
= createSetObject();
4707 dictAdd(c
->db
->dict
,c
->argv
[1],set
);
4708 incrRefCount(c
->argv
[1]);
4710 if (set
->type
!= REDIS_SET
) {
4711 addReply(c
,shared
.wrongtypeerr
);
4715 if (dictAdd(set
->ptr
,c
->argv
[2],NULL
) == DICT_OK
) {
4716 incrRefCount(c
->argv
[2]);
4718 addReply(c
,shared
.cone
);
4720 addReply(c
,shared
.czero
);
4724 static void sremCommand(redisClient
*c
) {
4727 if ((set
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
4728 checkType(c
,set
,REDIS_SET
)) return;
4730 if (dictDelete(set
->ptr
,c
->argv
[2]) == DICT_OK
) {
4732 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
4733 if (dictSize((dict
*)set
->ptr
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4734 addReply(c
,shared
.cone
);
4736 addReply(c
,shared
.czero
);
4740 static void smoveCommand(redisClient
*c
) {
4741 robj
*srcset
, *dstset
;
4743 srcset
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4744 dstset
= lookupKeyWrite(c
->db
,c
->argv
[2]);
4746 /* If the source key does not exist return 0, if it's of the wrong type
4748 if (srcset
== NULL
|| srcset
->type
!= REDIS_SET
) {
4749 addReply(c
, srcset
? shared
.wrongtypeerr
: shared
.czero
);
4752 /* Error if the destination key is not a set as well */
4753 if (dstset
&& dstset
->type
!= REDIS_SET
) {
4754 addReply(c
,shared
.wrongtypeerr
);
4757 /* Remove the element from the source set */
4758 if (dictDelete(srcset
->ptr
,c
->argv
[3]) == DICT_ERR
) {
4759 /* Key not found in the src set! return zero */
4760 addReply(c
,shared
.czero
);
4763 if (dictSize((dict
*)srcset
->ptr
) == 0 && srcset
!= dstset
)
4764 deleteKey(c
->db
,c
->argv
[1]);
4766 /* Add the element to the destination set */
4768 dstset
= createSetObject();
4769 dictAdd(c
->db
->dict
,c
->argv
[2],dstset
);
4770 incrRefCount(c
->argv
[2]);
4772 if (dictAdd(dstset
->ptr
,c
->argv
[3],NULL
) == DICT_OK
)
4773 incrRefCount(c
->argv
[3]);
4774 addReply(c
,shared
.cone
);
4777 static void sismemberCommand(redisClient
*c
) {
4780 if ((set
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
4781 checkType(c
,set
,REDIS_SET
)) return;
4783 if (dictFind(set
->ptr
,c
->argv
[2]))
4784 addReply(c
,shared
.cone
);
4786 addReply(c
,shared
.czero
);
4789 static void scardCommand(redisClient
*c
) {
4793 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
4794 checkType(c
,o
,REDIS_SET
)) return;
4797 addReplyUlong(c
,dictSize(s
));
4800 static void spopCommand(redisClient
*c
) {
4804 if ((set
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4805 checkType(c
,set
,REDIS_SET
)) return;
4807 de
= dictGetRandomKey(set
->ptr
);
4809 addReply(c
,shared
.nullbulk
);
4811 robj
*ele
= dictGetEntryKey(de
);
4813 addReplyBulk(c
,ele
);
4814 dictDelete(set
->ptr
,ele
);
4815 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
4816 if (dictSize((dict
*)set
->ptr
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4821 static void srandmemberCommand(redisClient
*c
) {
4825 if ((set
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4826 checkType(c
,set
,REDIS_SET
)) return;
4828 de
= dictGetRandomKey(set
->ptr
);
4830 addReply(c
,shared
.nullbulk
);
4832 robj
*ele
= dictGetEntryKey(de
);
4834 addReplyBulk(c
,ele
);
4838 static int qsortCompareSetsByCardinality(const void *s1
, const void *s2
) {
4839 dict
**d1
= (void*) s1
, **d2
= (void*) s2
;
4841 return dictSize(*d1
)-dictSize(*d2
);
4844 static void sinterGenericCommand(redisClient
*c
, robj
**setskeys
, unsigned long setsnum
, robj
*dstkey
) {
4845 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
4848 robj
*lenobj
= NULL
, *dstset
= NULL
;
4849 unsigned long j
, cardinality
= 0;
4851 for (j
= 0; j
< setsnum
; j
++) {
4855 lookupKeyWrite(c
->db
,setskeys
[j
]) :
4856 lookupKeyRead(c
->db
,setskeys
[j
]);
4860 if (deleteKey(c
->db
,dstkey
))
4862 addReply(c
,shared
.czero
);
4864 addReply(c
,shared
.nullmultibulk
);
4868 if (setobj
->type
!= REDIS_SET
) {
4870 addReply(c
,shared
.wrongtypeerr
);
4873 dv
[j
] = setobj
->ptr
;
4875 /* Sort sets from the smallest to largest, this will improve our
4876 * algorithm's performace */
4877 qsort(dv
,setsnum
,sizeof(dict
*),qsortCompareSetsByCardinality
);
4879 /* The first thing we should output is the total number of elements...
4880 * since this is a multi-bulk write, but at this stage we don't know
4881 * the intersection set size, so we use a trick, append an empty object
4882 * to the output list and save the pointer to later modify it with the
4885 lenobj
= createObject(REDIS_STRING
,NULL
);
4887 decrRefCount(lenobj
);
4889 /* If we have a target key where to store the resulting set
4890 * create this key with an empty set inside */
4891 dstset
= createSetObject();
4894 /* Iterate all the elements of the first (smallest) set, and test
4895 * the element against all the other sets, if at least one set does
4896 * not include the element it is discarded */
4897 di
= dictGetIterator(dv
[0]);
4899 while((de
= dictNext(di
)) != NULL
) {
4902 for (j
= 1; j
< setsnum
; j
++)
4903 if (dictFind(dv
[j
],dictGetEntryKey(de
)) == NULL
) break;
4905 continue; /* at least one set does not contain the member */
4906 ele
= dictGetEntryKey(de
);
4908 addReplyBulk(c
,ele
);
4911 dictAdd(dstset
->ptr
,ele
,NULL
);
4915 dictReleaseIterator(di
);
4918 /* Store the resulting set into the target, if the intersection
4919 * is not an empty set. */
4920 deleteKey(c
->db
,dstkey
);
4921 if (dictSize((dict
*)dstset
->ptr
) > 0) {
4922 dictAdd(c
->db
->dict
,dstkey
,dstset
);
4923 incrRefCount(dstkey
);
4924 addReplyLong(c
,dictSize((dict
*)dstset
->ptr
));
4926 decrRefCount(dstset
);
4927 addReply(c
,shared
.czero
);
4931 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%lu\r\n",cardinality
);
4936 static void sinterCommand(redisClient
*c
) {
4937 sinterGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
);
4940 static void sinterstoreCommand(redisClient
*c
) {
4941 sinterGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1]);
4944 #define REDIS_OP_UNION 0
4945 #define REDIS_OP_DIFF 1
4946 #define REDIS_OP_INTER 2
4948 static void sunionDiffGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
, int op
) {
4949 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
4952 robj
*dstset
= NULL
;
4953 int j
, cardinality
= 0;
4955 for (j
= 0; j
< setsnum
; j
++) {
4959 lookupKeyWrite(c
->db
,setskeys
[j
]) :
4960 lookupKeyRead(c
->db
,setskeys
[j
]);
4965 if (setobj
->type
!= REDIS_SET
) {
4967 addReply(c
,shared
.wrongtypeerr
);
4970 dv
[j
] = setobj
->ptr
;
4973 /* We need a temp set object to store our union. If the dstkey
4974 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
4975 * this set object will be the resulting object to set into the target key*/
4976 dstset
= createSetObject();
4978 /* Iterate all the elements of all the sets, add every element a single
4979 * time to the result set */
4980 for (j
= 0; j
< setsnum
; j
++) {
4981 if (op
== REDIS_OP_DIFF
&& j
== 0 && !dv
[j
]) break; /* result set is empty */
4982 if (!dv
[j
]) continue; /* non existing keys are like empty sets */
4984 di
= dictGetIterator(dv
[j
]);
4986 while((de
= dictNext(di
)) != NULL
) {
4989 /* dictAdd will not add the same element multiple times */
4990 ele
= dictGetEntryKey(de
);
4991 if (op
== REDIS_OP_UNION
|| j
== 0) {
4992 if (dictAdd(dstset
->ptr
,ele
,NULL
) == DICT_OK
) {
4996 } else if (op
== REDIS_OP_DIFF
) {
4997 if (dictDelete(dstset
->ptr
,ele
) == DICT_OK
) {
5002 dictReleaseIterator(di
);
5004 /* result set is empty? Exit asap. */
5005 if (op
== REDIS_OP_DIFF
&& cardinality
== 0) break;
5008 /* Output the content of the resulting set, if not in STORE mode */
5010 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",cardinality
));
5011 di
= dictGetIterator(dstset
->ptr
);
5012 while((de
= dictNext(di
)) != NULL
) {
5015 ele
= dictGetEntryKey(de
);
5016 addReplyBulk(c
,ele
);
5018 dictReleaseIterator(di
);
5019 decrRefCount(dstset
);
5021 /* If we have a target key where to store the resulting set
5022 * create this key with the result set inside */
5023 deleteKey(c
->db
,dstkey
);
5024 if (dictSize((dict
*)dstset
->ptr
) > 0) {
5025 dictAdd(c
->db
->dict
,dstkey
,dstset
);
5026 incrRefCount(dstkey
);
5027 addReplyLong(c
,dictSize((dict
*)dstset
->ptr
));
5029 decrRefCount(dstset
);
5030 addReply(c
,shared
.czero
);
5037 static void sunionCommand(redisClient
*c
) {
5038 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_UNION
);
5041 static void sunionstoreCommand(redisClient
*c
) {
5042 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_UNION
);
5045 static void sdiffCommand(redisClient
*c
) {
5046 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_DIFF
);
5049 static void sdiffstoreCommand(redisClient
*c
) {
5050 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_DIFF
);
5053 /* ==================================== ZSets =============================== */
5055 /* ZSETs are ordered sets using two data structures to hold the same elements
5056 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
5059 * The elements are added to an hash table mapping Redis objects to scores.
5060 * At the same time the elements are added to a skip list mapping scores
5061 * to Redis objects (so objects are sorted by scores in this "view"). */
5063 /* This skiplist implementation is almost a C translation of the original
5064 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
5065 * Alternative to Balanced Trees", modified in three ways:
5066 * a) this implementation allows for repeated values.
5067 * b) the comparison is not just by key (our 'score') but by satellite data.
5068 * c) there is a back pointer, so it's a doubly linked list with the back
5069 * pointers being only at "level 1". This allows to traverse the list
5070 * from tail to head, useful for ZREVRANGE. */
5072 static zskiplistNode
*zslCreateNode(int level
, double score
, robj
*obj
) {
5073 zskiplistNode
*zn
= zmalloc(sizeof(*zn
));
5075 zn
->forward
= zmalloc(sizeof(zskiplistNode
*) * level
);
5077 zn
->span
= zmalloc(sizeof(unsigned int) * (level
- 1));
5083 static zskiplist
*zslCreate(void) {
5087 zsl
= zmalloc(sizeof(*zsl
));
5090 zsl
->header
= zslCreateNode(ZSKIPLIST_MAXLEVEL
,0,NULL
);
5091 for (j
= 0; j
< ZSKIPLIST_MAXLEVEL
; j
++) {
5092 zsl
->header
->forward
[j
] = NULL
;
5094 /* span has space for ZSKIPLIST_MAXLEVEL-1 elements */
5095 if (j
< ZSKIPLIST_MAXLEVEL
-1)
5096 zsl
->header
->span
[j
] = 0;
5098 zsl
->header
->backward
= NULL
;
5103 static void zslFreeNode(zskiplistNode
*node
) {
5104 decrRefCount(node
->obj
);
5105 zfree(node
->forward
);
5110 static void zslFree(zskiplist
*zsl
) {
5111 zskiplistNode
*node
= zsl
->header
->forward
[0], *next
;
5113 zfree(zsl
->header
->forward
);
5114 zfree(zsl
->header
->span
);
5117 next
= node
->forward
[0];
5124 static int zslRandomLevel(void) {
5126 while ((random()&0xFFFF) < (ZSKIPLIST_P
* 0xFFFF))
5128 return (level
<ZSKIPLIST_MAXLEVEL
) ? level
: ZSKIPLIST_MAXLEVEL
;
5131 static void zslInsert(zskiplist
*zsl
, double score
, robj
*obj
) {
5132 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
5133 unsigned int rank
[ZSKIPLIST_MAXLEVEL
];
5137 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5138 /* store rank that is crossed to reach the insert position */
5139 rank
[i
] = i
== (zsl
->level
-1) ? 0 : rank
[i
+1];
5141 while (x
->forward
[i
] &&
5142 (x
->forward
[i
]->score
< score
||
5143 (x
->forward
[i
]->score
== score
&&
5144 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0))) {
5145 rank
[i
] += i
> 0 ? x
->span
[i
-1] : 1;
5150 /* we assume the key is not already inside, since we allow duplicated
5151 * scores, and the re-insertion of score and redis object should never
5152 * happpen since the caller of zslInsert() should test in the hash table
5153 * if the element is already inside or not. */
5154 level
= zslRandomLevel();
5155 if (level
> zsl
->level
) {
5156 for (i
= zsl
->level
; i
< level
; i
++) {
5158 update
[i
] = zsl
->header
;
5159 update
[i
]->span
[i
-1] = zsl
->length
;
5163 x
= zslCreateNode(level
,score
,obj
);
5164 for (i
= 0; i
< level
; i
++) {
5165 x
->forward
[i
] = update
[i
]->forward
[i
];
5166 update
[i
]->forward
[i
] = x
;
5168 /* update span covered by update[i] as x is inserted here */
5170 x
->span
[i
-1] = update
[i
]->span
[i
-1] - (rank
[0] - rank
[i
]);
5171 update
[i
]->span
[i
-1] = (rank
[0] - rank
[i
]) + 1;
5175 /* increment span for untouched levels */
5176 for (i
= level
; i
< zsl
->level
; i
++) {
5177 update
[i
]->span
[i
-1]++;
5180 x
->backward
= (update
[0] == zsl
->header
) ? NULL
: update
[0];
5182 x
->forward
[0]->backward
= x
;
5188 /* Internal function used by zslDelete, zslDeleteByScore and zslDeleteByRank */
5189 void zslDeleteNode(zskiplist
*zsl
, zskiplistNode
*x
, zskiplistNode
**update
) {
5191 for (i
= 0; i
< zsl
->level
; i
++) {
5192 if (update
[i
]->forward
[i
] == x
) {
5194 update
[i
]->span
[i
-1] += x
->span
[i
-1] - 1;
5196 update
[i
]->forward
[i
] = x
->forward
[i
];
5198 /* invariant: i > 0, because update[0]->forward[0]
5199 * is always equal to x */
5200 update
[i
]->span
[i
-1] -= 1;
5203 if (x
->forward
[0]) {
5204 x
->forward
[0]->backward
= x
->backward
;
5206 zsl
->tail
= x
->backward
;
5208 while(zsl
->level
> 1 && zsl
->header
->forward
[zsl
->level
-1] == NULL
)
5213 /* Delete an element with matching score/object from the skiplist. */
5214 static int zslDelete(zskiplist
*zsl
, double score
, robj
*obj
) {
5215 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
5219 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5220 while (x
->forward
[i
] &&
5221 (x
->forward
[i
]->score
< score
||
5222 (x
->forward
[i
]->score
== score
&&
5223 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0)))
5227 /* We may have multiple elements with the same score, what we need
5228 * is to find the element with both the right score and object. */
5230 if (x
&& score
== x
->score
&& compareStringObjects(x
->obj
,obj
) == 0) {
5231 zslDeleteNode(zsl
, x
, update
);
5235 return 0; /* not found */
5237 return 0; /* not found */
5240 /* Delete all the elements with score between min and max from the skiplist.
5241 * Min and mx are inclusive, so a score >= min || score <= max is deleted.
5242 * Note that this function takes the reference to the hash table view of the
5243 * sorted set, in order to remove the elements from the hash table too. */
5244 static unsigned long zslDeleteRangeByScore(zskiplist
*zsl
, double min
, double max
, dict
*dict
) {
5245 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
5246 unsigned long removed
= 0;
5250 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5251 while (x
->forward
[i
] && x
->forward
[i
]->score
< min
)
5255 /* We may have multiple elements with the same score, what we need
5256 * is to find the element with both the right score and object. */
5258 while (x
&& x
->score
<= max
) {
5259 zskiplistNode
*next
= x
->forward
[0];
5260 zslDeleteNode(zsl
, x
, update
);
5261 dictDelete(dict
,x
->obj
);
5266 return removed
; /* not found */
5269 /* Delete all the elements with rank between start and end from the skiplist.
5270 * Start and end are inclusive. Note that start and end need to be 1-based */
5271 static unsigned long zslDeleteRangeByRank(zskiplist
*zsl
, unsigned int start
, unsigned int end
, dict
*dict
) {
5272 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
5273 unsigned long traversed
= 0, removed
= 0;
5277 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5278 while (x
->forward
[i
] && (traversed
+ (i
> 0 ? x
->span
[i
-1] : 1)) < start
) {
5279 traversed
+= i
> 0 ? x
->span
[i
-1] : 1;
5287 while (x
&& traversed
<= end
) {
5288 zskiplistNode
*next
= x
->forward
[0];
5289 zslDeleteNode(zsl
, x
, update
);
5290 dictDelete(dict
,x
->obj
);
5299 /* Find the first node having a score equal or greater than the specified one.
5300 * Returns NULL if there is no match. */
5301 static zskiplistNode
*zslFirstWithScore(zskiplist
*zsl
, double score
) {
5306 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5307 while (x
->forward
[i
] && x
->forward
[i
]->score
< score
)
5310 /* We may have multiple elements with the same score, what we need
5311 * is to find the element with both the right score and object. */
5312 return x
->forward
[0];
5315 /* Find the rank for an element by both score and key.
5316 * Returns 0 when the element cannot be found, rank otherwise.
5317 * Note that the rank is 1-based due to the span of zsl->header to the
5319 static unsigned long zslGetRank(zskiplist
*zsl
, double score
, robj
*o
) {
5321 unsigned long rank
= 0;
5325 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5326 while (x
->forward
[i
] &&
5327 (x
->forward
[i
]->score
< score
||
5328 (x
->forward
[i
]->score
== score
&&
5329 compareStringObjects(x
->forward
[i
]->obj
,o
) <= 0))) {
5330 rank
+= i
> 0 ? x
->span
[i
-1] : 1;
5334 /* x might be equal to zsl->header, so test if obj is non-NULL */
5335 if (x
->obj
&& compareStringObjects(x
->obj
,o
) == 0) {
5342 /* Finds an element by its rank. The rank argument needs to be 1-based. */
5343 zskiplistNode
* zslGetElementByRank(zskiplist
*zsl
, unsigned long rank
) {
5345 unsigned long traversed
= 0;
5349 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5350 while (x
->forward
[i
] && (traversed
+ (i
>0 ? x
->span
[i
-1] : 1)) <= rank
)
5352 traversed
+= i
> 0 ? x
->span
[i
-1] : 1;
5355 if (traversed
== rank
) {
5362 /* The actual Z-commands implementations */
5364 /* This generic command implements both ZADD and ZINCRBY.
5365 * scoreval is the score if the operation is a ZADD (doincrement == 0) or
5366 * the increment if the operation is a ZINCRBY (doincrement == 1). */
5367 static void zaddGenericCommand(redisClient
*c
, robj
*key
, robj
*ele
, double scoreval
, int doincrement
) {
5372 zsetobj
= lookupKeyWrite(c
->db
,key
);
5373 if (zsetobj
== NULL
) {
5374 zsetobj
= createZsetObject();
5375 dictAdd(c
->db
->dict
,key
,zsetobj
);
5378 if (zsetobj
->type
!= REDIS_ZSET
) {
5379 addReply(c
,shared
.wrongtypeerr
);
5385 /* Ok now since we implement both ZADD and ZINCRBY here the code
5386 * needs to handle the two different conditions. It's all about setting
5387 * '*score', that is, the new score to set, to the right value. */
5388 score
= zmalloc(sizeof(double));
5392 /* Read the old score. If the element was not present starts from 0 */
5393 de
= dictFind(zs
->dict
,ele
);
5395 double *oldscore
= dictGetEntryVal(de
);
5396 *score
= *oldscore
+ scoreval
;
5404 /* What follows is a simple remove and re-insert operation that is common
5405 * to both ZADD and ZINCRBY... */
5406 if (dictAdd(zs
->dict
,ele
,score
) == DICT_OK
) {
5407 /* case 1: New element */
5408 incrRefCount(ele
); /* added to hash */
5409 zslInsert(zs
->zsl
,*score
,ele
);
5410 incrRefCount(ele
); /* added to skiplist */
5413 addReplyDouble(c
,*score
);
5415 addReply(c
,shared
.cone
);
5420 /* case 2: Score update operation */
5421 de
= dictFind(zs
->dict
,ele
);
5422 redisAssert(de
!= NULL
);
5423 oldscore
= dictGetEntryVal(de
);
5424 if (*score
!= *oldscore
) {
5427 /* Remove and insert the element in the skip list with new score */
5428 deleted
= zslDelete(zs
->zsl
,*oldscore
,ele
);
5429 redisAssert(deleted
!= 0);
5430 zslInsert(zs
->zsl
,*score
,ele
);
5432 /* Update the score in the hash table */
5433 dictReplace(zs
->dict
,ele
,score
);
5439 addReplyDouble(c
,*score
);
5441 addReply(c
,shared
.czero
);
5445 static void zaddCommand(redisClient
*c
) {
5448 scoreval
= strtod(c
->argv
[2]->ptr
,NULL
);
5449 zaddGenericCommand(c
,c
->argv
[1],c
->argv
[3],scoreval
,0);
5452 static void zincrbyCommand(redisClient
*c
) {
5455 scoreval
= strtod(c
->argv
[2]->ptr
,NULL
);
5456 zaddGenericCommand(c
,c
->argv
[1],c
->argv
[3],scoreval
,1);
5459 static void zremCommand(redisClient
*c
) {
5466 if ((zsetobj
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
5467 checkType(c
,zsetobj
,REDIS_ZSET
)) return;
5470 de
= dictFind(zs
->dict
,c
->argv
[2]);
5472 addReply(c
,shared
.czero
);
5475 /* Delete from the skiplist */
5476 oldscore
= dictGetEntryVal(de
);
5477 deleted
= zslDelete(zs
->zsl
,*oldscore
,c
->argv
[2]);
5478 redisAssert(deleted
!= 0);
5480 /* Delete from the hash table */
5481 dictDelete(zs
->dict
,c
->argv
[2]);
5482 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
5483 if (dictSize(zs
->dict
) == 0) deleteKey(c
->db
,c
->argv
[1]);
5485 addReply(c
,shared
.cone
);
5488 static void zremrangebyscoreCommand(redisClient
*c
) {
5489 double min
= strtod(c
->argv
[2]->ptr
,NULL
);
5490 double max
= strtod(c
->argv
[3]->ptr
,NULL
);
5495 if ((zsetobj
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
5496 checkType(c
,zsetobj
,REDIS_ZSET
)) return;
5499 deleted
= zslDeleteRangeByScore(zs
->zsl
,min
,max
,zs
->dict
);
5500 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
5501 if (dictSize(zs
->dict
) == 0) deleteKey(c
->db
,c
->argv
[1]);
5502 server
.dirty
+= deleted
;
5503 addReplyLong(c
,deleted
);
5506 static void zremrangebyrankCommand(redisClient
*c
) {
5507 int start
= atoi(c
->argv
[2]->ptr
);
5508 int end
= atoi(c
->argv
[3]->ptr
);
5514 if ((zsetobj
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
5515 checkType(c
,zsetobj
,REDIS_ZSET
)) return;
5517 llen
= zs
->zsl
->length
;
5519 /* convert negative indexes */
5520 if (start
< 0) start
= llen
+start
;
5521 if (end
< 0) end
= llen
+end
;
5522 if (start
< 0) start
= 0;
5523 if (end
< 0) end
= 0;
5525 /* indexes sanity checks */
5526 if (start
> end
|| start
>= llen
) {
5527 addReply(c
,shared
.czero
);
5530 if (end
>= llen
) end
= llen
-1;
5532 /* increment start and end because zsl*Rank functions
5533 * use 1-based rank */
5534 deleted
= zslDeleteRangeByRank(zs
->zsl
,start
+1,end
+1,zs
->dict
);
5535 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
5536 if (dictSize(zs
->dict
) == 0) deleteKey(c
->db
,c
->argv
[1]);
5537 server
.dirty
+= deleted
;
5538 addReplyLong(c
, deleted
);
5546 static int qsortCompareZsetopsrcByCardinality(const void *s1
, const void *s2
) {
5547 zsetopsrc
*d1
= (void*) s1
, *d2
= (void*) s2
;
5548 unsigned long size1
, size2
;
5549 size1
= d1
->dict
? dictSize(d1
->dict
) : 0;
5550 size2
= d2
->dict
? dictSize(d2
->dict
) : 0;
5551 return size1
- size2
;
5554 #define REDIS_AGGR_SUM 1
5555 #define REDIS_AGGR_MIN 2
5556 #define REDIS_AGGR_MAX 3
5558 inline static void zunionInterAggregate(double *target
, double val
, int aggregate
) {
5559 if (aggregate
== REDIS_AGGR_SUM
) {
5560 *target
= *target
+ val
;
5561 } else if (aggregate
== REDIS_AGGR_MIN
) {
5562 *target
= val
< *target
? val
: *target
;
5563 } else if (aggregate
== REDIS_AGGR_MAX
) {
5564 *target
= val
> *target
? val
: *target
;
5567 redisAssert(0 != 0);
5571 static void zunionInterGenericCommand(redisClient
*c
, robj
*dstkey
, int op
) {
5573 int aggregate
= REDIS_AGGR_SUM
;
5580 /* expect zsetnum input keys to be given */
5581 zsetnum
= atoi(c
->argv
[2]->ptr
);
5583 addReplySds(c
,sdsnew("-ERR at least 1 input key is needed for ZUNION/ZINTER\r\n"));
5587 /* test if the expected number of keys would overflow */
5588 if (3+zsetnum
> c
->argc
) {
5589 addReply(c
,shared
.syntaxerr
);
5593 /* read keys to be used for input */
5594 src
= zmalloc(sizeof(zsetopsrc
) * zsetnum
);
5595 for (i
= 0, j
= 3; i
< zsetnum
; i
++, j
++) {
5596 robj
*zsetobj
= lookupKeyWrite(c
->db
,c
->argv
[j
]);
5600 if (zsetobj
->type
!= REDIS_ZSET
) {
5602 addReply(c
,shared
.wrongtypeerr
);
5605 src
[i
].dict
= ((zset
*)zsetobj
->ptr
)->dict
;
5608 /* default all weights to 1 */
5609 src
[i
].weight
= 1.0;
5612 /* parse optional extra arguments */
5614 int remaining
= c
->argc
- j
;
5617 if (remaining
>= (zsetnum
+ 1) && !strcasecmp(c
->argv
[j
]->ptr
,"weights")) {
5619 for (i
= 0; i
< zsetnum
; i
++, j
++, remaining
--) {
5620 src
[i
].weight
= strtod(c
->argv
[j
]->ptr
, NULL
);
5622 } else if (remaining
>= 2 && !strcasecmp(c
->argv
[j
]->ptr
,"aggregate")) {
5624 if (!strcasecmp(c
->argv
[j
]->ptr
,"sum")) {
5625 aggregate
= REDIS_AGGR_SUM
;
5626 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"min")) {
5627 aggregate
= REDIS_AGGR_MIN
;
5628 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"max")) {
5629 aggregate
= REDIS_AGGR_MAX
;
5632 addReply(c
,shared
.syntaxerr
);
5638 addReply(c
,shared
.syntaxerr
);
5644 /* sort sets from the smallest to largest, this will improve our
5645 * algorithm's performance */
5646 qsort(src
,zsetnum
,sizeof(zsetopsrc
), qsortCompareZsetopsrcByCardinality
);
5648 dstobj
= createZsetObject();
5649 dstzset
= dstobj
->ptr
;
5651 if (op
== REDIS_OP_INTER
) {
5652 /* skip going over all entries if the smallest zset is NULL or empty */
5653 if (src
[0].dict
&& dictSize(src
[0].dict
) > 0) {
5654 /* precondition: as src[0].dict is non-empty and the zsets are ordered
5655 * from small to large, all src[i > 0].dict are non-empty too */
5656 di
= dictGetIterator(src
[0].dict
);
5657 while((de
= dictNext(di
)) != NULL
) {
5658 double *score
= zmalloc(sizeof(double)), value
;
5659 *score
= src
[0].weight
* (*(double*)dictGetEntryVal(de
));
5661 for (j
= 1; j
< zsetnum
; j
++) {
5662 dictEntry
*other
= dictFind(src
[j
].dict
,dictGetEntryKey(de
));
5664 value
= src
[j
].weight
* (*(double*)dictGetEntryVal(other
));
5665 zunionInterAggregate(score
, value
, aggregate
);
5671 /* skip entry when not present in every source dict */
5675 robj
*o
= dictGetEntryKey(de
);
5676 dictAdd(dstzset
->dict
,o
,score
);
5677 incrRefCount(o
); /* added to dictionary */
5678 zslInsert(dstzset
->zsl
,*score
,o
);
5679 incrRefCount(o
); /* added to skiplist */
5682 dictReleaseIterator(di
);
5684 } else if (op
== REDIS_OP_UNION
) {
5685 for (i
= 0; i
< zsetnum
; i
++) {
5686 if (!src
[i
].dict
) continue;
5688 di
= dictGetIterator(src
[i
].dict
);
5689 while((de
= dictNext(di
)) != NULL
) {
5690 /* skip key when already processed */
5691 if (dictFind(dstzset
->dict
,dictGetEntryKey(de
)) != NULL
) continue;
5693 double *score
= zmalloc(sizeof(double)), value
;
5694 *score
= src
[i
].weight
* (*(double*)dictGetEntryVal(de
));
5696 /* because the zsets are sorted by size, its only possible
5697 * for sets at larger indices to hold this entry */
5698 for (j
= (i
+1); j
< zsetnum
; j
++) {
5699 dictEntry
*other
= dictFind(src
[j
].dict
,dictGetEntryKey(de
));
5701 value
= src
[j
].weight
* (*(double*)dictGetEntryVal(other
));
5702 zunionInterAggregate(score
, value
, aggregate
);
5706 robj
*o
= dictGetEntryKey(de
);
5707 dictAdd(dstzset
->dict
,o
,score
);
5708 incrRefCount(o
); /* added to dictionary */
5709 zslInsert(dstzset
->zsl
,*score
,o
);
5710 incrRefCount(o
); /* added to skiplist */
5712 dictReleaseIterator(di
);
5715 /* unknown operator */
5716 redisAssert(op
== REDIS_OP_INTER
|| op
== REDIS_OP_UNION
);
5719 deleteKey(c
->db
,dstkey
);
5720 if (dstzset
->zsl
->length
) {
5721 dictAdd(c
->db
->dict
,dstkey
,dstobj
);
5722 incrRefCount(dstkey
);
5723 addReplyLong(c
, dstzset
->zsl
->length
);
5726 decrRefCount(dstobj
);
5727 addReply(c
, shared
.czero
);
5732 static void zunionCommand(redisClient
*c
) {
5733 zunionInterGenericCommand(c
,c
->argv
[1], REDIS_OP_UNION
);
5736 static void zinterCommand(redisClient
*c
) {
5737 zunionInterGenericCommand(c
,c
->argv
[1], REDIS_OP_INTER
);
5740 static void zrangeGenericCommand(redisClient
*c
, int reverse
) {
5742 int start
= atoi(c
->argv
[2]->ptr
);
5743 int end
= atoi(c
->argv
[3]->ptr
);
5752 if (c
->argc
== 5 && !strcasecmp(c
->argv
[4]->ptr
,"withscores")) {
5754 } else if (c
->argc
>= 5) {
5755 addReply(c
,shared
.syntaxerr
);
5759 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullmultibulk
)) == NULL
||
5760 checkType(c
,o
,REDIS_ZSET
)) return;
5765 /* convert negative indexes */
5766 if (start
< 0) start
= llen
+start
;
5767 if (end
< 0) end
= llen
+end
;
5768 if (start
< 0) start
= 0;
5769 if (end
< 0) end
= 0;
5771 /* indexes sanity checks */
5772 if (start
> end
|| start
>= llen
) {
5773 /* Out of range start or start > end result in empty list */
5774 addReply(c
,shared
.emptymultibulk
);
5777 if (end
>= llen
) end
= llen
-1;
5778 rangelen
= (end
-start
)+1;
5780 /* check if starting point is trivial, before searching
5781 * the element in log(N) time */
5783 ln
= start
== 0 ? zsl
->tail
: zslGetElementByRank(zsl
, llen
-start
);
5786 zsl
->header
->forward
[0] : zslGetElementByRank(zsl
, start
+1);
5789 /* Return the result in form of a multi-bulk reply */
5790 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",
5791 withscores
? (rangelen
*2) : rangelen
));
5792 for (j
= 0; j
< rangelen
; j
++) {
5794 addReplyBulk(c
,ele
);
5796 addReplyDouble(c
,ln
->score
);
5797 ln
= reverse
? ln
->backward
: ln
->forward
[0];
5801 static void zrangeCommand(redisClient
*c
) {
5802 zrangeGenericCommand(c
,0);
5805 static void zrevrangeCommand(redisClient
*c
) {
5806 zrangeGenericCommand(c
,1);
5809 /* This command implements both ZRANGEBYSCORE and ZCOUNT.
5810 * If justcount is non-zero, just the count is returned. */
5811 static void genericZrangebyscoreCommand(redisClient
*c
, int justcount
) {
5814 int minex
= 0, maxex
= 0; /* are min or max exclusive? */
5815 int offset
= 0, limit
= -1;
5819 /* Parse the min-max interval. If one of the values is prefixed
5820 * by the "(" character, it's considered "open". For instance
5821 * ZRANGEBYSCORE zset (1.5 (2.5 will match min < x < max
5822 * ZRANGEBYSCORE zset 1.5 2.5 will instead match min <= x <= max */
5823 if (((char*)c
->argv
[2]->ptr
)[0] == '(') {
5824 min
= strtod((char*)c
->argv
[2]->ptr
+1,NULL
);
5827 min
= strtod(c
->argv
[2]->ptr
,NULL
);
5829 if (((char*)c
->argv
[3]->ptr
)[0] == '(') {
5830 max
= strtod((char*)c
->argv
[3]->ptr
+1,NULL
);
5833 max
= strtod(c
->argv
[3]->ptr
,NULL
);
5836 /* Parse "WITHSCORES": note that if the command was called with
5837 * the name ZCOUNT then we are sure that c->argc == 4, so we'll never
5838 * enter the following paths to parse WITHSCORES and LIMIT. */
5839 if (c
->argc
== 5 || c
->argc
== 8) {
5840 if (strcasecmp(c
->argv
[c
->argc
-1]->ptr
,"withscores") == 0)
5845 if (c
->argc
!= (4 + withscores
) && c
->argc
!= (7 + withscores
))
5849 sdsnew("-ERR wrong number of arguments for ZRANGEBYSCORE\r\n"));
5854 if (c
->argc
== (7 + withscores
) && strcasecmp(c
->argv
[4]->ptr
,"limit")) {
5855 addReply(c
,shared
.syntaxerr
);
5857 } else if (c
->argc
== (7 + withscores
)) {
5858 offset
= atoi(c
->argv
[5]->ptr
);
5859 limit
= atoi(c
->argv
[6]->ptr
);
5860 if (offset
< 0) offset
= 0;
5863 /* Ok, lookup the key and get the range */
5864 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
5866 addReply(c
,justcount
? shared
.czero
: shared
.nullmultibulk
);
5868 if (o
->type
!= REDIS_ZSET
) {
5869 addReply(c
,shared
.wrongtypeerr
);
5871 zset
*zsetobj
= o
->ptr
;
5872 zskiplist
*zsl
= zsetobj
->zsl
;
5874 robj
*ele
, *lenobj
= NULL
;
5875 unsigned long rangelen
= 0;
5877 /* Get the first node with the score >= min, or with
5878 * score > min if 'minex' is true. */
5879 ln
= zslFirstWithScore(zsl
,min
);
5880 while (minex
&& ln
&& ln
->score
== min
) ln
= ln
->forward
[0];
5883 /* No element matching the speciifed interval */
5884 addReply(c
,justcount
? shared
.czero
: shared
.emptymultibulk
);
5888 /* We don't know in advance how many matching elements there
5889 * are in the list, so we push this object that will represent
5890 * the multi-bulk length in the output buffer, and will "fix"
5893 lenobj
= createObject(REDIS_STRING
,NULL
);
5895 decrRefCount(lenobj
);
5898 while(ln
&& (maxex
? (ln
->score
< max
) : (ln
->score
<= max
))) {
5901 ln
= ln
->forward
[0];
5904 if (limit
== 0) break;
5907 addReplyBulk(c
,ele
);
5909 addReplyDouble(c
,ln
->score
);
5911 ln
= ln
->forward
[0];
5913 if (limit
> 0) limit
--;
5916 addReplyLong(c
,(long)rangelen
);
5918 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%lu\r\n",
5919 withscores
? (rangelen
*2) : rangelen
);
5925 static void zrangebyscoreCommand(redisClient
*c
) {
5926 genericZrangebyscoreCommand(c
,0);
5929 static void zcountCommand(redisClient
*c
) {
5930 genericZrangebyscoreCommand(c
,1);
5933 static void zcardCommand(redisClient
*c
) {
5937 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
5938 checkType(c
,o
,REDIS_ZSET
)) return;
5941 addReplyUlong(c
,zs
->zsl
->length
);
5944 static void zscoreCommand(redisClient
*c
) {
5949 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
5950 checkType(c
,o
,REDIS_ZSET
)) return;
5953 de
= dictFind(zs
->dict
,c
->argv
[2]);
5955 addReply(c
,shared
.nullbulk
);
5957 double *score
= dictGetEntryVal(de
);
5959 addReplyDouble(c
,*score
);
5963 static void zrankGenericCommand(redisClient
*c
, int reverse
) {
5971 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
5972 checkType(c
,o
,REDIS_ZSET
)) return;
5976 de
= dictFind(zs
->dict
,c
->argv
[2]);
5978 addReply(c
,shared
.nullbulk
);
5982 score
= dictGetEntryVal(de
);
5983 rank
= zslGetRank(zsl
, *score
, c
->argv
[2]);
5986 addReplyLong(c
, zsl
->length
- rank
);
5988 addReplyLong(c
, rank
-1);
5991 addReply(c
,shared
.nullbulk
);
5995 static void zrankCommand(redisClient
*c
) {
5996 zrankGenericCommand(c
, 0);
5999 static void zrevrankCommand(redisClient
*c
) {
6000 zrankGenericCommand(c
, 1);
6003 /* =================================== Hashes =============================== */
6004 static void hsetCommand(redisClient
*c
) {
6006 robj
*o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
6009 o
= createHashObject();
6010 dictAdd(c
->db
->dict
,c
->argv
[1],o
);
6011 incrRefCount(c
->argv
[1]);
6013 if (o
->type
!= REDIS_HASH
) {
6014 addReply(c
,shared
.wrongtypeerr
);
6018 /* We want to convert the zipmap into an hash table right now if the
6019 * entry to be added is too big. Note that we check if the object
6020 * is integer encoded before to try fetching the length in the test below.
6021 * This is because integers are small, but currently stringObjectLen()
6022 * performs a slow conversion: not worth it. */
6023 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
&&
6024 ((c
->argv
[2]->encoding
== REDIS_ENCODING_RAW
&&
6025 sdslen(c
->argv
[2]->ptr
) > server
.hash_max_zipmap_value
) ||
6026 (c
->argv
[3]->encoding
== REDIS_ENCODING_RAW
&&
6027 sdslen(c
->argv
[3]->ptr
) > server
.hash_max_zipmap_value
)))
6029 convertToRealHash(o
);
6032 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6033 unsigned char *zm
= o
->ptr
;
6034 robj
*valobj
= getDecodedObject(c
->argv
[3]);
6036 zm
= zipmapSet(zm
,c
->argv
[2]->ptr
,sdslen(c
->argv
[2]->ptr
),
6037 valobj
->ptr
,sdslen(valobj
->ptr
),&update
);
6038 decrRefCount(valobj
);
6041 /* And here there is the second check for hash conversion. */
6042 if (zipmapLen(zm
) > server
.hash_max_zipmap_entries
)
6043 convertToRealHash(o
);
6045 tryObjectEncoding(c
->argv
[2]);
6046 /* note that c->argv[3] is already encoded, as the latest arg
6047 * of a bulk command is always integer encoded if possible. */
6048 if (dictReplace(o
->ptr
,c
->argv
[2],c
->argv
[3])) {
6049 incrRefCount(c
->argv
[2]);
6053 incrRefCount(c
->argv
[3]);
6056 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",update
== 0));
6059 static void hincrbyCommand(redisClient
*c
) {
6060 long long value
= 0, incr
= 0;
6061 robj
*o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
6064 o
= createHashObject();
6065 dictAdd(c
->db
->dict
,c
->argv
[1],o
);
6066 incrRefCount(c
->argv
[1]);
6068 if (o
->type
!= REDIS_HASH
) {
6069 addReply(c
,shared
.wrongtypeerr
);
6074 incr
= strtoll(c
->argv
[3]->ptr
, NULL
, 10);
6075 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6076 unsigned char *zm
= o
->ptr
;
6077 unsigned char *zval
;
6080 /* Find value if already present in hash */
6081 if (zipmapGet(zm
,c
->argv
[2]->ptr
,sdslen(c
->argv
[2]->ptr
),
6083 /* strtoll needs the char* to have a trailing \0, but
6084 * the zipmap doesn't include them. */
6085 sds szval
= sdsnewlen(zval
, zvlen
);
6086 value
= strtoll(szval
,NULL
,10);
6091 sds svalue
= sdscatprintf(sdsempty(),"%lld",value
);
6092 zm
= zipmapSet(zm
,c
->argv
[2]->ptr
,sdslen(c
->argv
[2]->ptr
),
6093 (unsigned char*)svalue
,sdslen(svalue
),NULL
);
6097 /* Check if the zipmap needs to be converted. */
6098 if (zipmapLen(zm
) > server
.hash_max_zipmap_entries
)
6099 convertToRealHash(o
);
6104 /* Find value if already present in hash */
6105 de
= dictFind(o
->ptr
,c
->argv
[2]);
6107 hval
= dictGetEntryVal(de
);
6108 if (hval
->encoding
== REDIS_ENCODING_RAW
)
6109 value
= strtoll(hval
->ptr
,NULL
,10);
6110 else if (hval
->encoding
== REDIS_ENCODING_INT
)
6111 value
= (long)hval
->ptr
;
6113 redisAssert(1 != 1);
6117 hval
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",value
));
6118 tryObjectEncoding(hval
);
6119 if (dictReplace(o
->ptr
,c
->argv
[2],hval
)) {
6120 incrRefCount(c
->argv
[2]);
6125 addReplyLongLong(c
, value
);
6128 static void hgetCommand(redisClient
*c
) {
6131 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
6132 checkType(c
,o
,REDIS_HASH
)) return;
6134 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6135 unsigned char *zm
= o
->ptr
;
6140 field
= getDecodedObject(c
->argv
[2]);
6141 if (zipmapGet(zm
,field
->ptr
,sdslen(field
->ptr
), &val
,&vlen
)) {
6142 addReplySds(c
,sdscatprintf(sdsempty(),"$%u\r\n", vlen
));
6143 addReplySds(c
,sdsnewlen(val
,vlen
));
6144 addReply(c
,shared
.crlf
);
6145 decrRefCount(field
);
6148 addReply(c
,shared
.nullbulk
);
6149 decrRefCount(field
);
6153 struct dictEntry
*de
;
6155 de
= dictFind(o
->ptr
,c
->argv
[2]);
6157 addReply(c
,shared
.nullbulk
);
6159 robj
*e
= dictGetEntryVal(de
);
6166 static void hdelCommand(redisClient
*c
) {
6170 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
6171 checkType(c
,o
,REDIS_HASH
)) return;
6173 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6174 robj
*field
= getDecodedObject(c
->argv
[2]);
6176 o
->ptr
= zipmapDel((unsigned char*) o
->ptr
,
6177 (unsigned char*) field
->ptr
,
6178 sdslen(field
->ptr
), &deleted
);
6179 decrRefCount(field
);
6180 if (zipmapLen((unsigned char*) o
->ptr
) == 0)
6181 deleteKey(c
->db
,c
->argv
[1]);
6183 deleted
= dictDelete((dict
*)o
->ptr
,c
->argv
[2]) == DICT_OK
;
6184 if (htNeedsResize(o
->ptr
)) dictResize(o
->ptr
);
6185 if (dictSize((dict
*)o
->ptr
) == 0) deleteKey(c
->db
,c
->argv
[1]);
6187 if (deleted
) server
.dirty
++;
6188 addReply(c
,deleted
? shared
.cone
: shared
.czero
);
6191 static void hlenCommand(redisClient
*c
) {
6195 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
6196 checkType(c
,o
,REDIS_HASH
)) return;
6198 len
= (o
->encoding
== REDIS_ENCODING_ZIPMAP
) ?
6199 zipmapLen((unsigned char*)o
->ptr
) : dictSize((dict
*)o
->ptr
);
6200 addReplyUlong(c
,len
);
6203 #define REDIS_GETALL_KEYS 1
6204 #define REDIS_GETALL_VALS 2
6205 static void genericHgetallCommand(redisClient
*c
, int flags
) {
6207 unsigned long count
= 0;
6209 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullmultibulk
)) == NULL
6210 || checkType(c
,o
,REDIS_HASH
)) return;
6212 lenobj
= createObject(REDIS_STRING
,NULL
);
6214 decrRefCount(lenobj
);
6216 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6217 unsigned char *p
= zipmapRewind(o
->ptr
);
6218 unsigned char *field
, *val
;
6219 unsigned int flen
, vlen
;
6221 while((p
= zipmapNext(p
,&field
,&flen
,&val
,&vlen
)) != NULL
) {
6224 if (flags
& REDIS_GETALL_KEYS
) {
6225 aux
= createStringObject((char*)field
,flen
);
6226 addReplyBulk(c
,aux
);
6230 if (flags
& REDIS_GETALL_VALS
) {
6231 aux
= createStringObject((char*)val
,vlen
);
6232 addReplyBulk(c
,aux
);
6238 dictIterator
*di
= dictGetIterator(o
->ptr
);
6241 while((de
= dictNext(di
)) != NULL
) {
6242 robj
*fieldobj
= dictGetEntryKey(de
);
6243 robj
*valobj
= dictGetEntryVal(de
);
6245 if (flags
& REDIS_GETALL_KEYS
) {
6246 addReplyBulk(c
,fieldobj
);
6249 if (flags
& REDIS_GETALL_VALS
) {
6250 addReplyBulk(c
,valobj
);
6254 dictReleaseIterator(di
);
6256 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%lu\r\n",count
);
6259 static void hkeysCommand(redisClient
*c
) {
6260 genericHgetallCommand(c
,REDIS_GETALL_KEYS
);
6263 static void hvalsCommand(redisClient
*c
) {
6264 genericHgetallCommand(c
,REDIS_GETALL_VALS
);
6267 static void hgetallCommand(redisClient
*c
) {
6268 genericHgetallCommand(c
,REDIS_GETALL_KEYS
|REDIS_GETALL_VALS
);
6271 static void hexistsCommand(redisClient
*c
) {
6275 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
6276 checkType(c
,o
,REDIS_HASH
)) return;
6278 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6280 unsigned char *zm
= o
->ptr
;
6282 field
= getDecodedObject(c
->argv
[2]);
6283 exists
= zipmapExists(zm
,field
->ptr
,sdslen(field
->ptr
));
6284 decrRefCount(field
);
6286 exists
= dictFind(o
->ptr
,c
->argv
[2]) != NULL
;
6288 addReply(c
,exists
? shared
.cone
: shared
.czero
);
6291 static void convertToRealHash(robj
*o
) {
6292 unsigned char *key
, *val
, *p
, *zm
= o
->ptr
;
6293 unsigned int klen
, vlen
;
6294 dict
*dict
= dictCreate(&hashDictType
,NULL
);
6296 assert(o
->type
== REDIS_HASH
&& o
->encoding
!= REDIS_ENCODING_HT
);
6297 p
= zipmapRewind(zm
);
6298 while((p
= zipmapNext(p
,&key
,&klen
,&val
,&vlen
)) != NULL
) {
6299 robj
*keyobj
, *valobj
;
6301 keyobj
= createStringObject((char*)key
,klen
);
6302 valobj
= createStringObject((char*)val
,vlen
);
6303 tryObjectEncoding(keyobj
);
6304 tryObjectEncoding(valobj
);
6305 dictAdd(dict
,keyobj
,valobj
);
6307 o
->encoding
= REDIS_ENCODING_HT
;
6312 /* ========================= Non type-specific commands ==================== */
6314 static void flushdbCommand(redisClient
*c
) {
6315 server
.dirty
+= dictSize(c
->db
->dict
);
6316 dictEmpty(c
->db
->dict
);
6317 dictEmpty(c
->db
->expires
);
6318 addReply(c
,shared
.ok
);
6321 static void flushallCommand(redisClient
*c
) {
6322 server
.dirty
+= emptyDb();
6323 addReply(c
,shared
.ok
);
6324 if (server
.bgsavechildpid
!= -1) {
6325 kill(server
.bgsavechildpid
,SIGKILL
);
6326 rdbRemoveTempFile(server
.bgsavechildpid
);
6328 rdbSave(server
.dbfilename
);
6332 static redisSortOperation
*createSortOperation(int type
, robj
*pattern
) {
6333 redisSortOperation
*so
= zmalloc(sizeof(*so
));
6335 so
->pattern
= pattern
;
6339 /* Return the value associated to the key with a name obtained
6340 * substituting the first occurence of '*' in 'pattern' with 'subst' */
6341 static robj
*lookupKeyByPattern(redisDb
*db
, robj
*pattern
, robj
*subst
) {
6345 int prefixlen
, sublen
, postfixlen
;
6346 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
6350 char buf
[REDIS_SORTKEY_MAX
+1];
6353 /* If the pattern is "#" return the substitution object itself in order
6354 * to implement the "SORT ... GET #" feature. */
6355 spat
= pattern
->ptr
;
6356 if (spat
[0] == '#' && spat
[1] == '\0') {
6360 /* The substitution object may be specially encoded. If so we create
6361 * a decoded object on the fly. Otherwise getDecodedObject will just
6362 * increment the ref count, that we'll decrement later. */
6363 subst
= getDecodedObject(subst
);
6366 if (sdslen(spat
)+sdslen(ssub
)-1 > REDIS_SORTKEY_MAX
) return NULL
;
6367 p
= strchr(spat
,'*');
6369 decrRefCount(subst
);
6374 sublen
= sdslen(ssub
);
6375 postfixlen
= sdslen(spat
)-(prefixlen
+1);
6376 memcpy(keyname
.buf
,spat
,prefixlen
);
6377 memcpy(keyname
.buf
+prefixlen
,ssub
,sublen
);
6378 memcpy(keyname
.buf
+prefixlen
+sublen
,p
+1,postfixlen
);
6379 keyname
.buf
[prefixlen
+sublen
+postfixlen
] = '\0';
6380 keyname
.len
= prefixlen
+sublen
+postfixlen
;
6382 initStaticStringObject(keyobj
,((char*)&keyname
)+(sizeof(long)*2))
6383 decrRefCount(subst
);
6385 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
6386 return lookupKeyRead(db
,&keyobj
);
6389 /* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
6390 * the additional parameter is not standard but a BSD-specific we have to
6391 * pass sorting parameters via the global 'server' structure */
6392 static int sortCompare(const void *s1
, const void *s2
) {
6393 const redisSortObject
*so1
= s1
, *so2
= s2
;
6396 if (!server
.sort_alpha
) {
6397 /* Numeric sorting. Here it's trivial as we precomputed scores */
6398 if (so1
->u
.score
> so2
->u
.score
) {
6400 } else if (so1
->u
.score
< so2
->u
.score
) {
6406 /* Alphanumeric sorting */
6407 if (server
.sort_bypattern
) {
6408 if (!so1
->u
.cmpobj
|| !so2
->u
.cmpobj
) {
6409 /* At least one compare object is NULL */
6410 if (so1
->u
.cmpobj
== so2
->u
.cmpobj
)
6412 else if (so1
->u
.cmpobj
== NULL
)
6417 /* We have both the objects, use strcoll */
6418 cmp
= strcoll(so1
->u
.cmpobj
->ptr
,so2
->u
.cmpobj
->ptr
);
6421 /* Compare elements directly */
6424 dec1
= getDecodedObject(so1
->obj
);
6425 dec2
= getDecodedObject(so2
->obj
);
6426 cmp
= strcoll(dec1
->ptr
,dec2
->ptr
);
6431 return server
.sort_desc
? -cmp
: cmp
;
6434 /* The SORT command is the most complex command in Redis. Warning: this code
6435 * is optimized for speed and a bit less for readability */
6436 static void sortCommand(redisClient
*c
) {
6439 int desc
= 0, alpha
= 0;
6440 int limit_start
= 0, limit_count
= -1, start
, end
;
6441 int j
, dontsort
= 0, vectorlen
;
6442 int getop
= 0; /* GET operation counter */
6443 robj
*sortval
, *sortby
= NULL
, *storekey
= NULL
;
6444 redisSortObject
*vector
; /* Resulting vector to sort */
6446 /* Lookup the key to sort. It must be of the right types */
6447 sortval
= lookupKeyRead(c
->db
,c
->argv
[1]);
6448 if (sortval
== NULL
) {
6449 addReply(c
,shared
.nullmultibulk
);
6452 if (sortval
->type
!= REDIS_SET
&& sortval
->type
!= REDIS_LIST
&&
6453 sortval
->type
!= REDIS_ZSET
)
6455 addReply(c
,shared
.wrongtypeerr
);
6459 /* Create a list of operations to perform for every sorted element.
6460 * Operations can be GET/DEL/INCR/DECR */
6461 operations
= listCreate();
6462 listSetFreeMethod(operations
,zfree
);
6465 /* Now we need to protect sortval incrementing its count, in the future
6466 * SORT may have options able to overwrite/delete keys during the sorting
6467 * and the sorted key itself may get destroied */
6468 incrRefCount(sortval
);
6470 /* The SORT command has an SQL-alike syntax, parse it */
6471 while(j
< c
->argc
) {
6472 int leftargs
= c
->argc
-j
-1;
6473 if (!strcasecmp(c
->argv
[j
]->ptr
,"asc")) {
6475 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"desc")) {
6477 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"alpha")) {
6479 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"limit") && leftargs
>= 2) {
6480 limit_start
= atoi(c
->argv
[j
+1]->ptr
);
6481 limit_count
= atoi(c
->argv
[j
+2]->ptr
);
6483 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"store") && leftargs
>= 1) {
6484 storekey
= c
->argv
[j
+1];
6486 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"by") && leftargs
>= 1) {
6487 sortby
= c
->argv
[j
+1];
6488 /* If the BY pattern does not contain '*', i.e. it is constant,
6489 * we don't need to sort nor to lookup the weight keys. */
6490 if (strchr(c
->argv
[j
+1]->ptr
,'*') == NULL
) dontsort
= 1;
6492 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
6493 listAddNodeTail(operations
,createSortOperation(
6494 REDIS_SORT_GET
,c
->argv
[j
+1]));
6498 decrRefCount(sortval
);
6499 listRelease(operations
);
6500 addReply(c
,shared
.syntaxerr
);
6506 /* Load the sorting vector with all the objects to sort */
6507 switch(sortval
->type
) {
6508 case REDIS_LIST
: vectorlen
= listLength((list
*)sortval
->ptr
); break;
6509 case REDIS_SET
: vectorlen
= dictSize((dict
*)sortval
->ptr
); break;
6510 case REDIS_ZSET
: vectorlen
= dictSize(((zset
*)sortval
->ptr
)->dict
); break;
6511 default: vectorlen
= 0; redisAssert(0); /* Avoid GCC warning */
6513 vector
= zmalloc(sizeof(redisSortObject
)*vectorlen
);
6516 if (sortval
->type
== REDIS_LIST
) {
6517 list
*list
= sortval
->ptr
;
6521 listRewind(list
,&li
);
6522 while((ln
= listNext(&li
))) {
6523 robj
*ele
= ln
->value
;
6524 vector
[j
].obj
= ele
;
6525 vector
[j
].u
.score
= 0;
6526 vector
[j
].u
.cmpobj
= NULL
;
6534 if (sortval
->type
== REDIS_SET
) {
6537 zset
*zs
= sortval
->ptr
;
6541 di
= dictGetIterator(set
);
6542 while((setele
= dictNext(di
)) != NULL
) {
6543 vector
[j
].obj
= dictGetEntryKey(setele
);
6544 vector
[j
].u
.score
= 0;
6545 vector
[j
].u
.cmpobj
= NULL
;
6548 dictReleaseIterator(di
);
6550 redisAssert(j
== vectorlen
);
6552 /* Now it's time to load the right scores in the sorting vector */
6553 if (dontsort
== 0) {
6554 for (j
= 0; j
< vectorlen
; j
++) {
6558 byval
= lookupKeyByPattern(c
->db
,sortby
,vector
[j
].obj
);
6559 if (!byval
|| byval
->type
!= REDIS_STRING
) continue;
6561 vector
[j
].u
.cmpobj
= getDecodedObject(byval
);
6563 if (byval
->encoding
== REDIS_ENCODING_RAW
) {
6564 vector
[j
].u
.score
= strtod(byval
->ptr
,NULL
);
6566 /* Don't need to decode the object if it's
6567 * integer-encoded (the only encoding supported) so
6568 * far. We can just cast it */
6569 if (byval
->encoding
== REDIS_ENCODING_INT
) {
6570 vector
[j
].u
.score
= (long)byval
->ptr
;
6572 redisAssert(1 != 1);
6577 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_RAW
)
6578 vector
[j
].u
.score
= strtod(vector
[j
].obj
->ptr
,NULL
);
6580 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_INT
)
6581 vector
[j
].u
.score
= (long) vector
[j
].obj
->ptr
;
6583 redisAssert(1 != 1);
6590 /* We are ready to sort the vector... perform a bit of sanity check
6591 * on the LIMIT option too. We'll use a partial version of quicksort. */
6592 start
= (limit_start
< 0) ? 0 : limit_start
;
6593 end
= (limit_count
< 0) ? vectorlen
-1 : start
+limit_count
-1;
6594 if (start
>= vectorlen
) {
6595 start
= vectorlen
-1;
6598 if (end
>= vectorlen
) end
= vectorlen
-1;
6600 if (dontsort
== 0) {
6601 server
.sort_desc
= desc
;
6602 server
.sort_alpha
= alpha
;
6603 server
.sort_bypattern
= sortby
? 1 : 0;
6604 if (sortby
&& (start
!= 0 || end
!= vectorlen
-1))
6605 pqsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
, start
,end
);
6607 qsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
);
6610 /* Send command output to the output buffer, performing the specified
6611 * GET/DEL/INCR/DECR operations if any. */
6612 outputlen
= getop
? getop
*(end
-start
+1) : end
-start
+1;
6613 if (storekey
== NULL
) {
6614 /* STORE option not specified, sent the sorting result to client */
6615 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",outputlen
));
6616 for (j
= start
; j
<= end
; j
++) {
6620 if (!getop
) addReplyBulk(c
,vector
[j
].obj
);
6621 listRewind(operations
,&li
);
6622 while((ln
= listNext(&li
))) {
6623 redisSortOperation
*sop
= ln
->value
;
6624 robj
*val
= lookupKeyByPattern(c
->db
,sop
->pattern
,
6627 if (sop
->type
== REDIS_SORT_GET
) {
6628 if (!val
|| val
->type
!= REDIS_STRING
) {
6629 addReply(c
,shared
.nullbulk
);
6631 addReplyBulk(c
,val
);
6634 redisAssert(sop
->type
== REDIS_SORT_GET
); /* always fails */
6639 robj
*listObject
= createListObject();
6640 list
*listPtr
= (list
*) listObject
->ptr
;
6642 /* STORE option specified, set the sorting result as a List object */
6643 for (j
= start
; j
<= end
; j
++) {
6648 listAddNodeTail(listPtr
,vector
[j
].obj
);
6649 incrRefCount(vector
[j
].obj
);
6651 listRewind(operations
,&li
);
6652 while((ln
= listNext(&li
))) {
6653 redisSortOperation
*sop
= ln
->value
;
6654 robj
*val
= lookupKeyByPattern(c
->db
,sop
->pattern
,
6657 if (sop
->type
== REDIS_SORT_GET
) {
6658 if (!val
|| val
->type
!= REDIS_STRING
) {
6659 listAddNodeTail(listPtr
,createStringObject("",0));
6661 listAddNodeTail(listPtr
,val
);
6665 redisAssert(sop
->type
== REDIS_SORT_GET
); /* always fails */
6669 if (dictReplace(c
->db
->dict
,storekey
,listObject
)) {
6670 incrRefCount(storekey
);
6672 /* Note: we add 1 because the DB is dirty anyway since even if the
6673 * SORT result is empty a new key is set and maybe the old content
6675 server
.dirty
+= 1+outputlen
;
6676 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",outputlen
));
6680 decrRefCount(sortval
);
6681 listRelease(operations
);
6682 for (j
= 0; j
< vectorlen
; j
++) {
6683 if (sortby
&& alpha
&& vector
[j
].u
.cmpobj
)
6684 decrRefCount(vector
[j
].u
.cmpobj
);
6689 /* Convert an amount of bytes into a human readable string in the form
6690 * of 100B, 2G, 100M, 4K, and so forth. */
6691 static void bytesToHuman(char *s
, unsigned long long n
) {
6696 sprintf(s
,"%lluB",n
);
6698 } else if (n
< (1024*1024)) {
6699 d
= (double)n
/(1024);
6700 sprintf(s
,"%.2fK",d
);
6701 } else if (n
< (1024LL*1024*1024)) {
6702 d
= (double)n
/(1024*1024);
6703 sprintf(s
,"%.2fM",d
);
6704 } else if (n
< (1024LL*1024*1024*1024)) {
6705 d
= (double)n
/(1024LL*1024*1024);
6706 sprintf(s
,"%.2fG",d
);
6710 /* Create the string returned by the INFO command. This is decoupled
6711 * by the INFO command itself as we need to report the same information
6712 * on memory corruption problems. */
6713 static sds
genRedisInfoString(void) {
6715 time_t uptime
= time(NULL
)-server
.stat_starttime
;
6719 bytesToHuman(hmem
,zmalloc_used_memory());
6720 info
= sdscatprintf(sdsempty(),
6721 "redis_version:%s\r\n"
6723 "multiplexing_api:%s\r\n"
6724 "process_id:%ld\r\n"
6725 "uptime_in_seconds:%ld\r\n"
6726 "uptime_in_days:%ld\r\n"
6727 "connected_clients:%d\r\n"
6728 "connected_slaves:%d\r\n"
6729 "blocked_clients:%d\r\n"
6730 "used_memory:%zu\r\n"
6731 "used_memory_human:%s\r\n"
6732 "changes_since_last_save:%lld\r\n"
6733 "bgsave_in_progress:%d\r\n"
6734 "last_save_time:%ld\r\n"
6735 "bgrewriteaof_in_progress:%d\r\n"
6736 "total_connections_received:%lld\r\n"
6737 "total_commands_processed:%lld\r\n"
6738 "expired_keys:%lld\r\n"
6739 "hash_max_zipmap_entries:%ld\r\n"
6740 "hash_max_zipmap_value:%ld\r\n"
6741 "pubsub_channels:%ld\r\n"
6742 "pubsub_patterns:%u\r\n"
6746 (sizeof(long) == 8) ? "64" : "32",
6751 listLength(server
.clients
)-listLength(server
.slaves
),
6752 listLength(server
.slaves
),
6753 server
.blpop_blocked_clients
,
6754 zmalloc_used_memory(),
6757 server
.bgsavechildpid
!= -1,
6759 server
.bgrewritechildpid
!= -1,
6760 server
.stat_numconnections
,
6761 server
.stat_numcommands
,
6762 server
.stat_expiredkeys
,
6763 server
.hash_max_zipmap_entries
,
6764 server
.hash_max_zipmap_value
,
6765 dictSize(server
.pubsub_channels
),
6766 listLength(server
.pubsub_patterns
),
6767 server
.vm_enabled
!= 0,
6768 server
.masterhost
== NULL
? "master" : "slave"
6770 if (server
.masterhost
) {
6771 info
= sdscatprintf(info
,
6772 "master_host:%s\r\n"
6773 "master_port:%d\r\n"
6774 "master_link_status:%s\r\n"
6775 "master_last_io_seconds_ago:%d\r\n"
6778 (server
.replstate
== REDIS_REPL_CONNECTED
) ?
6780 server
.master
? ((int)(time(NULL
)-server
.master
->lastinteraction
)) : -1
6783 if (server
.vm_enabled
) {
6785 info
= sdscatprintf(info
,
6786 "vm_conf_max_memory:%llu\r\n"
6787 "vm_conf_page_size:%llu\r\n"
6788 "vm_conf_pages:%llu\r\n"
6789 "vm_stats_used_pages:%llu\r\n"
6790 "vm_stats_swapped_objects:%llu\r\n"
6791 "vm_stats_swappin_count:%llu\r\n"
6792 "vm_stats_swappout_count:%llu\r\n"
6793 "vm_stats_io_newjobs_len:%lu\r\n"
6794 "vm_stats_io_processing_len:%lu\r\n"
6795 "vm_stats_io_processed_len:%lu\r\n"
6796 "vm_stats_io_active_threads:%lu\r\n"
6797 "vm_stats_blocked_clients:%lu\r\n"
6798 ,(unsigned long long) server
.vm_max_memory
,
6799 (unsigned long long) server
.vm_page_size
,
6800 (unsigned long long) server
.vm_pages
,
6801 (unsigned long long) server
.vm_stats_used_pages
,
6802 (unsigned long long) server
.vm_stats_swapped_objects
,
6803 (unsigned long long) server
.vm_stats_swapins
,
6804 (unsigned long long) server
.vm_stats_swapouts
,
6805 (unsigned long) listLength(server
.io_newjobs
),
6806 (unsigned long) listLength(server
.io_processing
),
6807 (unsigned long) listLength(server
.io_processed
),
6808 (unsigned long) server
.io_active_threads
,
6809 (unsigned long) server
.vm_blocked_clients
6813 for (j
= 0; j
< server
.dbnum
; j
++) {
6814 long long keys
, vkeys
;
6816 keys
= dictSize(server
.db
[j
].dict
);
6817 vkeys
= dictSize(server
.db
[j
].expires
);
6818 if (keys
|| vkeys
) {
6819 info
= sdscatprintf(info
, "db%d:keys=%lld,expires=%lld\r\n",
6826 static void infoCommand(redisClient
*c
) {
6827 sds info
= genRedisInfoString();
6828 addReplySds(c
,sdscatprintf(sdsempty(),"$%lu\r\n",
6829 (unsigned long)sdslen(info
)));
6830 addReplySds(c
,info
);
6831 addReply(c
,shared
.crlf
);
6834 static void monitorCommand(redisClient
*c
) {
6835 /* ignore MONITOR if aleady slave or in monitor mode */
6836 if (c
->flags
& REDIS_SLAVE
) return;
6838 c
->flags
|= (REDIS_SLAVE
|REDIS_MONITOR
);
6840 listAddNodeTail(server
.monitors
,c
);
6841 addReply(c
,shared
.ok
);
6844 /* ================================= Expire ================================= */
6845 static int removeExpire(redisDb
*db
, robj
*key
) {
6846 if (dictDelete(db
->expires
,key
) == DICT_OK
) {
6853 static int setExpire(redisDb
*db
, robj
*key
, time_t when
) {
6854 if (dictAdd(db
->expires
,key
,(void*)when
) == DICT_ERR
) {
6862 /* Return the expire time of the specified key, or -1 if no expire
6863 * is associated with this key (i.e. the key is non volatile) */
6864 static time_t getExpire(redisDb
*db
, robj
*key
) {
6867 /* No expire? return ASAP */
6868 if (dictSize(db
->expires
) == 0 ||
6869 (de
= dictFind(db
->expires
,key
)) == NULL
) return -1;
6871 return (time_t) dictGetEntryVal(de
);
6874 static int expireIfNeeded(redisDb
*db
, robj
*key
) {
6878 /* No expire? return ASAP */
6879 if (dictSize(db
->expires
) == 0 ||
6880 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
6882 /* Lookup the expire */
6883 when
= (time_t) dictGetEntryVal(de
);
6884 if (time(NULL
) <= when
) return 0;
6886 /* Delete the key */
6887 dictDelete(db
->expires
,key
);
6888 server
.stat_expiredkeys
++;
6889 return dictDelete(db
->dict
,key
) == DICT_OK
;
6892 static int deleteIfVolatile(redisDb
*db
, robj
*key
) {
6895 /* No expire? return ASAP */
6896 if (dictSize(db
->expires
) == 0 ||
6897 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
6899 /* Delete the key */
6901 server
.stat_expiredkeys
++;
6902 dictDelete(db
->expires
,key
);
6903 return dictDelete(db
->dict
,key
) == DICT_OK
;
6906 static void expireGenericCommand(redisClient
*c
, robj
*key
, time_t seconds
) {
6909 de
= dictFind(c
->db
->dict
,key
);
6911 addReply(c
,shared
.czero
);
6915 if (deleteKey(c
->db
,key
)) server
.dirty
++;
6916 addReply(c
, shared
.cone
);
6919 time_t when
= time(NULL
)+seconds
;
6920 if (setExpire(c
->db
,key
,when
)) {
6921 addReply(c
,shared
.cone
);
6924 addReply(c
,shared
.czero
);
6930 static void expireCommand(redisClient
*c
) {
6931 expireGenericCommand(c
,c
->argv
[1],strtol(c
->argv
[2]->ptr
,NULL
,10));
6934 static void expireatCommand(redisClient
*c
) {
6935 expireGenericCommand(c
,c
->argv
[1],strtol(c
->argv
[2]->ptr
,NULL
,10)-time(NULL
));
6938 static void ttlCommand(redisClient
*c
) {
6942 expire
= getExpire(c
->db
,c
->argv
[1]);
6944 ttl
= (int) (expire
-time(NULL
));
6945 if (ttl
< 0) ttl
= -1;
6947 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",ttl
));
6950 /* ================================ MULTI/EXEC ============================== */
6952 /* Client state initialization for MULTI/EXEC */
6953 static void initClientMultiState(redisClient
*c
) {
6954 c
->mstate
.commands
= NULL
;
6955 c
->mstate
.count
= 0;
6958 /* Release all the resources associated with MULTI/EXEC state */
6959 static void freeClientMultiState(redisClient
*c
) {
6962 for (j
= 0; j
< c
->mstate
.count
; j
++) {
6964 multiCmd
*mc
= c
->mstate
.commands
+j
;
6966 for (i
= 0; i
< mc
->argc
; i
++)
6967 decrRefCount(mc
->argv
[i
]);
6970 zfree(c
->mstate
.commands
);
6973 /* Add a new command into the MULTI commands queue */
6974 static void queueMultiCommand(redisClient
*c
, struct redisCommand
*cmd
) {
6978 c
->mstate
.commands
= zrealloc(c
->mstate
.commands
,
6979 sizeof(multiCmd
)*(c
->mstate
.count
+1));
6980 mc
= c
->mstate
.commands
+c
->mstate
.count
;
6983 mc
->argv
= zmalloc(sizeof(robj
*)*c
->argc
);
6984 memcpy(mc
->argv
,c
->argv
,sizeof(robj
*)*c
->argc
);
6985 for (j
= 0; j
< c
->argc
; j
++)
6986 incrRefCount(mc
->argv
[j
]);
6990 static void multiCommand(redisClient
*c
) {
6991 c
->flags
|= REDIS_MULTI
;
6992 addReply(c
,shared
.ok
);
6995 static void discardCommand(redisClient
*c
) {
6996 if (!(c
->flags
& REDIS_MULTI
)) {
6997 addReplySds(c
,sdsnew("-ERR DISCARD without MULTI\r\n"));
7001 freeClientMultiState(c
);
7002 initClientMultiState(c
);
7003 c
->flags
&= (~REDIS_MULTI
);
7004 addReply(c
,shared
.ok
);
7007 static void execCommand(redisClient
*c
) {
7012 if (!(c
->flags
& REDIS_MULTI
)) {
7013 addReplySds(c
,sdsnew("-ERR EXEC without MULTI\r\n"));
7017 orig_argv
= c
->argv
;
7018 orig_argc
= c
->argc
;
7019 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",c
->mstate
.count
));
7020 for (j
= 0; j
< c
->mstate
.count
; j
++) {
7021 c
->argc
= c
->mstate
.commands
[j
].argc
;
7022 c
->argv
= c
->mstate
.commands
[j
].argv
;
7023 call(c
,c
->mstate
.commands
[j
].cmd
);
7025 c
->argv
= orig_argv
;
7026 c
->argc
= orig_argc
;
7027 freeClientMultiState(c
);
7028 initClientMultiState(c
);
7029 c
->flags
&= (~REDIS_MULTI
);
7032 /* =========================== Blocking Operations ========================= */
7034 /* Currently Redis blocking operations support is limited to list POP ops,
7035 * so the current implementation is not fully generic, but it is also not
7036 * completely specific so it will not require a rewrite to support new
7037 * kind of blocking operations in the future.
7039 * Still it's important to note that list blocking operations can be already
7040 * used as a notification mechanism in order to implement other blocking
7041 * operations at application level, so there must be a very strong evidence
7042 * of usefulness and generality before new blocking operations are implemented.
7044 * This is how the current blocking POP works, we use BLPOP as example:
7045 * - If the user calls BLPOP and the key exists and contains a non empty list
7046 * then LPOP is called instead. So BLPOP is semantically the same as LPOP
7047 * if there is not to block.
7048 * - If instead BLPOP is called and the key does not exists or the list is
7049 * empty we need to block. In order to do so we remove the notification for
7050 * new data to read in the client socket (so that we'll not serve new
7051 * requests if the blocking request is not served). Also we put the client
7052 * in a dictionary (db->blockingkeys) mapping keys to a list of clients
7053 * blocking for this keys.
7054 * - If a PUSH operation against a key with blocked clients waiting is
7055 * performed, we serve the first in the list: basically instead to push
7056 * the new element inside the list we return it to the (first / oldest)
7057 * blocking client, unblock the client, and remove it form the list.
7059 * The above comment and the source code should be enough in order to understand
7060 * the implementation and modify / fix it later.
7063 /* Set a client in blocking mode for the specified key, with the specified
7065 static void blockForKeys(redisClient
*c
, robj
**keys
, int numkeys
, time_t timeout
) {
7070 c
->blockingkeys
= zmalloc(sizeof(robj
*)*numkeys
);
7071 c
->blockingkeysnum
= numkeys
;
7072 c
->blockingto
= timeout
;
7073 for (j
= 0; j
< numkeys
; j
++) {
7074 /* Add the key in the client structure, to map clients -> keys */
7075 c
->blockingkeys
[j
] = keys
[j
];
7076 incrRefCount(keys
[j
]);
7078 /* And in the other "side", to map keys -> clients */
7079 de
= dictFind(c
->db
->blockingkeys
,keys
[j
]);
7083 /* For every key we take a list of clients blocked for it */
7085 retval
= dictAdd(c
->db
->blockingkeys
,keys
[j
],l
);
7086 incrRefCount(keys
[j
]);
7087 assert(retval
== DICT_OK
);
7089 l
= dictGetEntryVal(de
);
7091 listAddNodeTail(l
,c
);
7093 /* Mark the client as a blocked client */
7094 c
->flags
|= REDIS_BLOCKED
;
7095 server
.blpop_blocked_clients
++;
7098 /* Unblock a client that's waiting in a blocking operation such as BLPOP */
7099 static void unblockClientWaitingData(redisClient
*c
) {
7104 assert(c
->blockingkeys
!= NULL
);
7105 /* The client may wait for multiple keys, so unblock it for every key. */
7106 for (j
= 0; j
< c
->blockingkeysnum
; j
++) {
7107 /* Remove this client from the list of clients waiting for this key. */
7108 de
= dictFind(c
->db
->blockingkeys
,c
->blockingkeys
[j
]);
7110 l
= dictGetEntryVal(de
);
7111 listDelNode(l
,listSearchKey(l
,c
));
7112 /* If the list is empty we need to remove it to avoid wasting memory */
7113 if (listLength(l
) == 0)
7114 dictDelete(c
->db
->blockingkeys
,c
->blockingkeys
[j
]);
7115 decrRefCount(c
->blockingkeys
[j
]);
7117 /* Cleanup the client structure */
7118 zfree(c
->blockingkeys
);
7119 c
->blockingkeys
= NULL
;
7120 c
->flags
&= (~REDIS_BLOCKED
);
7121 server
.blpop_blocked_clients
--;
7122 /* We want to process data if there is some command waiting
7123 * in the input buffer. Note that this is safe even if
7124 * unblockClientWaitingData() gets called from freeClient() because
7125 * freeClient() will be smart enough to call this function
7126 * *after* c->querybuf was set to NULL. */
7127 if (c
->querybuf
&& sdslen(c
->querybuf
) > 0) processInputBuffer(c
);
7130 /* This should be called from any function PUSHing into lists.
7131 * 'c' is the "pushing client", 'key' is the key it is pushing data against,
7132 * 'ele' is the element pushed.
7134 * If the function returns 0 there was no client waiting for a list push
7137 * If the function returns 1 there was a client waiting for a list push
7138 * against this key, the element was passed to this client thus it's not
7139 * needed to actually add it to the list and the caller should return asap. */
7140 static int handleClientsWaitingListPush(redisClient
*c
, robj
*key
, robj
*ele
) {
7141 struct dictEntry
*de
;
7142 redisClient
*receiver
;
7146 de
= dictFind(c
->db
->blockingkeys
,key
);
7147 if (de
== NULL
) return 0;
7148 l
= dictGetEntryVal(de
);
7151 receiver
= ln
->value
;
7153 addReplySds(receiver
,sdsnew("*2\r\n"));
7154 addReplyBulk(receiver
,key
);
7155 addReplyBulk(receiver
,ele
);
7156 unblockClientWaitingData(receiver
);
7160 /* Blocking RPOP/LPOP */
7161 static void blockingPopGenericCommand(redisClient
*c
, int where
) {
7166 for (j
= 1; j
< c
->argc
-1; j
++) {
7167 o
= lookupKeyWrite(c
->db
,c
->argv
[j
]);
7169 if (o
->type
!= REDIS_LIST
) {
7170 addReply(c
,shared
.wrongtypeerr
);
7173 list
*list
= o
->ptr
;
7174 if (listLength(list
) != 0) {
7175 /* If the list contains elements fall back to the usual
7176 * non-blocking POP operation */
7177 robj
*argv
[2], **orig_argv
;
7180 /* We need to alter the command arguments before to call
7181 * popGenericCommand() as the command takes a single key. */
7182 orig_argv
= c
->argv
;
7183 orig_argc
= c
->argc
;
7184 argv
[1] = c
->argv
[j
];
7188 /* Also the return value is different, we need to output
7189 * the multi bulk reply header and the key name. The
7190 * "real" command will add the last element (the value)
7191 * for us. If this souds like an hack to you it's just
7192 * because it is... */
7193 addReplySds(c
,sdsnew("*2\r\n"));
7194 addReplyBulk(c
,argv
[1]);
7195 popGenericCommand(c
,where
);
7197 /* Fix the client structure with the original stuff */
7198 c
->argv
= orig_argv
;
7199 c
->argc
= orig_argc
;
7205 /* If the list is empty or the key does not exists we must block */
7206 timeout
= strtol(c
->argv
[c
->argc
-1]->ptr
,NULL
,10);
7207 if (timeout
> 0) timeout
+= time(NULL
);
7208 blockForKeys(c
,c
->argv
+1,c
->argc
-2,timeout
);
7211 static void blpopCommand(redisClient
*c
) {
7212 blockingPopGenericCommand(c
,REDIS_HEAD
);
7215 static void brpopCommand(redisClient
*c
) {
7216 blockingPopGenericCommand(c
,REDIS_TAIL
);
7219 /* =============================== Replication ============================= */
7221 static int syncWrite(int fd
, char *ptr
, ssize_t size
, int timeout
) {
7222 ssize_t nwritten
, ret
= size
;
7223 time_t start
= time(NULL
);
7227 if (aeWait(fd
,AE_WRITABLE
,1000) & AE_WRITABLE
) {
7228 nwritten
= write(fd
,ptr
,size
);
7229 if (nwritten
== -1) return -1;
7233 if ((time(NULL
)-start
) > timeout
) {
7241 static int syncRead(int fd
, char *ptr
, ssize_t size
, int timeout
) {
7242 ssize_t nread
, totread
= 0;
7243 time_t start
= time(NULL
);
7247 if (aeWait(fd
,AE_READABLE
,1000) & AE_READABLE
) {
7248 nread
= read(fd
,ptr
,size
);
7249 if (nread
== -1) return -1;
7254 if ((time(NULL
)-start
) > timeout
) {
7262 static int syncReadLine(int fd
, char *ptr
, ssize_t size
, int timeout
) {
7269 if (syncRead(fd
,&c
,1,timeout
) == -1) return -1;
7272 if (nread
&& *(ptr
-1) == '\r') *(ptr
-1) = '\0';
7283 static void syncCommand(redisClient
*c
) {
7284 /* ignore SYNC if aleady slave or in monitor mode */
7285 if (c
->flags
& REDIS_SLAVE
) return;
7287 /* SYNC can't be issued when the server has pending data to send to
7288 * the client about already issued commands. We need a fresh reply
7289 * buffer registering the differences between the BGSAVE and the current
7290 * dataset, so that we can copy to other slaves if needed. */
7291 if (listLength(c
->reply
) != 0) {
7292 addReplySds(c
,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
7296 redisLog(REDIS_NOTICE
,"Slave ask for synchronization");
7297 /* Here we need to check if there is a background saving operation
7298 * in progress, or if it is required to start one */
7299 if (server
.bgsavechildpid
!= -1) {
7300 /* Ok a background save is in progress. Let's check if it is a good
7301 * one for replication, i.e. if there is another slave that is
7302 * registering differences since the server forked to save */
7307 listRewind(server
.slaves
,&li
);
7308 while((ln
= listNext(&li
))) {
7310 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) break;
7313 /* Perfect, the server is already registering differences for
7314 * another slave. Set the right state, and copy the buffer. */
7315 listRelease(c
->reply
);
7316 c
->reply
= listDup(slave
->reply
);
7317 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
7318 redisLog(REDIS_NOTICE
,"Waiting for end of BGSAVE for SYNC");
7320 /* No way, we need to wait for the next BGSAVE in order to
7321 * register differences */
7322 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
7323 redisLog(REDIS_NOTICE
,"Waiting for next BGSAVE for SYNC");
7326 /* Ok we don't have a BGSAVE in progress, let's start one */
7327 redisLog(REDIS_NOTICE
,"Starting BGSAVE for SYNC");
7328 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
7329 redisLog(REDIS_NOTICE
,"Replication failed, can't BGSAVE");
7330 addReplySds(c
,sdsnew("-ERR Unalbe to perform background save\r\n"));
7333 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
7336 c
->flags
|= REDIS_SLAVE
;
7338 listAddNodeTail(server
.slaves
,c
);
7342 static void sendBulkToSlave(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
7343 redisClient
*slave
= privdata
;
7345 REDIS_NOTUSED(mask
);
7346 char buf
[REDIS_IOBUF_LEN
];
7347 ssize_t nwritten
, buflen
;
7349 if (slave
->repldboff
== 0) {
7350 /* Write the bulk write count before to transfer the DB. In theory here
7351 * we don't know how much room there is in the output buffer of the
7352 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
7353 * operations) will never be smaller than the few bytes we need. */
7356 bulkcount
= sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
7358 if (write(fd
,bulkcount
,sdslen(bulkcount
)) != (signed)sdslen(bulkcount
))
7366 lseek(slave
->repldbfd
,slave
->repldboff
,SEEK_SET
);
7367 buflen
= read(slave
->repldbfd
,buf
,REDIS_IOBUF_LEN
);
7369 redisLog(REDIS_WARNING
,"Read error sending DB to slave: %s",
7370 (buflen
== 0) ? "premature EOF" : strerror(errno
));
7374 if ((nwritten
= write(fd
,buf
,buflen
)) == -1) {
7375 redisLog(REDIS_VERBOSE
,"Write error sending DB to slave: %s",
7380 slave
->repldboff
+= nwritten
;
7381 if (slave
->repldboff
== slave
->repldbsize
) {
7382 close(slave
->repldbfd
);
7383 slave
->repldbfd
= -1;
7384 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
7385 slave
->replstate
= REDIS_REPL_ONLINE
;
7386 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
,
7387 sendReplyToClient
, slave
) == AE_ERR
) {
7391 addReplySds(slave
,sdsempty());
7392 redisLog(REDIS_NOTICE
,"Synchronization with slave succeeded");
7396 /* This function is called at the end of every backgrond saving.
7397 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
7398 * otherwise REDIS_ERR is passed to the function.
7400 * The goal of this function is to handle slaves waiting for a successful
7401 * background saving in order to perform non-blocking synchronization. */
7402 static void updateSlavesWaitingBgsave(int bgsaveerr
) {
7404 int startbgsave
= 0;
7407 listRewind(server
.slaves
,&li
);
7408 while((ln
= listNext(&li
))) {
7409 redisClient
*slave
= ln
->value
;
7411 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) {
7413 slave
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
7414 } else if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) {
7415 struct redis_stat buf
;
7417 if (bgsaveerr
!= REDIS_OK
) {
7419 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE child returned an error");
7422 if ((slave
->repldbfd
= open(server
.dbfilename
,O_RDONLY
)) == -1 ||
7423 redis_fstat(slave
->repldbfd
,&buf
) == -1) {
7425 redisLog(REDIS_WARNING
,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno
));
7428 slave
->repldboff
= 0;
7429 slave
->repldbsize
= buf
.st_size
;
7430 slave
->replstate
= REDIS_REPL_SEND_BULK
;
7431 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
7432 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
, sendBulkToSlave
, slave
) == AE_ERR
) {
7439 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
7442 listRewind(server
.slaves
,&li
);
7443 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE failed");
7444 while((ln
= listNext(&li
))) {
7445 redisClient
*slave
= ln
->value
;
7447 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
)
7454 static int syncWithMaster(void) {
7455 char buf
[1024], tmpfile
[256], authcmd
[1024];
7457 int fd
= anetTcpConnect(NULL
,server
.masterhost
,server
.masterport
);
7458 int dfd
, maxtries
= 5;
7461 redisLog(REDIS_WARNING
,"Unable to connect to MASTER: %s",
7466 /* AUTH with the master if required. */
7467 if(server
.masterauth
) {
7468 snprintf(authcmd
, 1024, "AUTH %s\r\n", server
.masterauth
);
7469 if (syncWrite(fd
, authcmd
, strlen(server
.masterauth
)+7, 5) == -1) {
7471 redisLog(REDIS_WARNING
,"Unable to AUTH to MASTER: %s",
7475 /* Read the AUTH result. */
7476 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
7478 redisLog(REDIS_WARNING
,"I/O error reading auth result from MASTER: %s",
7482 if (buf
[0] != '+') {
7484 redisLog(REDIS_WARNING
,"Cannot AUTH to MASTER, is the masterauth password correct?");
7489 /* Issue the SYNC command */
7490 if (syncWrite(fd
,"SYNC \r\n",7,5) == -1) {
7492 redisLog(REDIS_WARNING
,"I/O error writing to MASTER: %s",
7496 /* Read the bulk write count */
7497 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
7499 redisLog(REDIS_WARNING
,"I/O error reading bulk count from MASTER: %s",
7503 if (buf
[0] != '$') {
7505 redisLog(REDIS_WARNING
,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
7508 dumpsize
= strtol(buf
+1,NULL
,10);
7509 redisLog(REDIS_NOTICE
,"Receiving %ld bytes data dump from MASTER",dumpsize
);
7510 /* Read the bulk write data on a temp file */
7512 snprintf(tmpfile
,256,
7513 "temp-%d.%ld.rdb",(int)time(NULL
),(long int)getpid());
7514 dfd
= open(tmpfile
,O_CREAT
|O_WRONLY
|O_EXCL
,0644);
7515 if (dfd
!= -1) break;
7520 redisLog(REDIS_WARNING
,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno
));
7524 int nread
, nwritten
;
7526 nread
= read(fd
,buf
,(dumpsize
< 1024)?dumpsize
:1024);
7528 redisLog(REDIS_WARNING
,"I/O error trying to sync with MASTER: %s",
7534 nwritten
= write(dfd
,buf
,nread
);
7535 if (nwritten
== -1) {
7536 redisLog(REDIS_WARNING
,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno
));
7544 if (rename(tmpfile
,server
.dbfilename
) == -1) {
7545 redisLog(REDIS_WARNING
,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno
));
7551 if (rdbLoad(server
.dbfilename
) != REDIS_OK
) {
7552 redisLog(REDIS_WARNING
,"Failed trying to load the MASTER synchronization DB from disk");
7556 server
.master
= createClient(fd
);
7557 server
.master
->flags
|= REDIS_MASTER
;
7558 server
.master
->authenticated
= 1;
7559 server
.replstate
= REDIS_REPL_CONNECTED
;
7563 static void slaveofCommand(redisClient
*c
) {
7564 if (!strcasecmp(c
->argv
[1]->ptr
,"no") &&
7565 !strcasecmp(c
->argv
[2]->ptr
,"one")) {
7566 if (server
.masterhost
) {
7567 sdsfree(server
.masterhost
);
7568 server
.masterhost
= NULL
;
7569 if (server
.master
) freeClient(server
.master
);
7570 server
.replstate
= REDIS_REPL_NONE
;
7571 redisLog(REDIS_NOTICE
,"MASTER MODE enabled (user request)");
7574 sdsfree(server
.masterhost
);
7575 server
.masterhost
= sdsdup(c
->argv
[1]->ptr
);
7576 server
.masterport
= atoi(c
->argv
[2]->ptr
);
7577 if (server
.master
) freeClient(server
.master
);
7578 server
.replstate
= REDIS_REPL_CONNECT
;
7579 redisLog(REDIS_NOTICE
,"SLAVE OF %s:%d enabled (user request)",
7580 server
.masterhost
, server
.masterport
);
7582 addReply(c
,shared
.ok
);
7585 /* ============================ Maxmemory directive ======================== */
7587 /* Try to free one object form the pre-allocated objects free list.
7588 * This is useful under low mem conditions as by default we take 1 million
7589 * free objects allocated. On success REDIS_OK is returned, otherwise
7591 static int tryFreeOneObjectFromFreelist(void) {
7594 if (server
.vm_enabled
) pthread_mutex_lock(&server
.obj_freelist_mutex
);
7595 if (listLength(server
.objfreelist
)) {
7596 listNode
*head
= listFirst(server
.objfreelist
);
7597 o
= listNodeValue(head
);
7598 listDelNode(server
.objfreelist
,head
);
7599 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
7603 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
7608 /* This function gets called when 'maxmemory' is set on the config file to limit
7609 * the max memory used by the server, and we are out of memory.
7610 * This function will try to, in order:
7612 * - Free objects from the free list
7613 * - Try to remove keys with an EXPIRE set
7615 * It is not possible to free enough memory to reach used-memory < maxmemory
7616 * the server will start refusing commands that will enlarge even more the
7619 static void freeMemoryIfNeeded(void) {
7620 while (server
.maxmemory
&& zmalloc_used_memory() > server
.maxmemory
) {
7621 int j
, k
, freed
= 0;
7623 if (tryFreeOneObjectFromFreelist() == REDIS_OK
) continue;
7624 for (j
= 0; j
< server
.dbnum
; j
++) {
7626 robj
*minkey
= NULL
;
7627 struct dictEntry
*de
;
7629 if (dictSize(server
.db
[j
].expires
)) {
7631 /* From a sample of three keys drop the one nearest to
7632 * the natural expire */
7633 for (k
= 0; k
< 3; k
++) {
7636 de
= dictGetRandomKey(server
.db
[j
].expires
);
7637 t
= (time_t) dictGetEntryVal(de
);
7638 if (minttl
== -1 || t
< minttl
) {
7639 minkey
= dictGetEntryKey(de
);
7643 deleteKey(server
.db
+j
,minkey
);
7646 if (!freed
) return; /* nothing to free... */
7650 /* ============================== Append Only file ========================== */
7652 static void feedAppendOnlyFile(struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
) {
7653 sds buf
= sdsempty();
7659 /* The DB this command was targetting is not the same as the last command
7660 * we appendend. To issue a SELECT command is needed. */
7661 if (dictid
!= server
.appendseldb
) {
7664 snprintf(seldb
,sizeof(seldb
),"%d",dictid
);
7665 buf
= sdscatprintf(buf
,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
7666 (unsigned long)strlen(seldb
),seldb
);
7667 server
.appendseldb
= dictid
;
7670 /* "Fix" the argv vector if the command is EXPIRE. We want to translate
7671 * EXPIREs into EXPIREATs calls */
7672 if (cmd
->proc
== expireCommand
) {
7675 tmpargv
[0] = createStringObject("EXPIREAT",8);
7676 tmpargv
[1] = argv
[1];
7677 incrRefCount(argv
[1]);
7678 when
= time(NULL
)+strtol(argv
[2]->ptr
,NULL
,10);
7679 tmpargv
[2] = createObject(REDIS_STRING
,
7680 sdscatprintf(sdsempty(),"%ld",when
));
7684 /* Append the actual command */
7685 buf
= sdscatprintf(buf
,"*%d\r\n",argc
);
7686 for (j
= 0; j
< argc
; j
++) {
7689 o
= getDecodedObject(o
);
7690 buf
= sdscatprintf(buf
,"$%lu\r\n",(unsigned long)sdslen(o
->ptr
));
7691 buf
= sdscatlen(buf
,o
->ptr
,sdslen(o
->ptr
));
7692 buf
= sdscatlen(buf
,"\r\n",2);
7696 /* Free the objects from the modified argv for EXPIREAT */
7697 if (cmd
->proc
== expireCommand
) {
7698 for (j
= 0; j
< 3; j
++)
7699 decrRefCount(argv
[j
]);
7702 /* We want to perform a single write. This should be guaranteed atomic
7703 * at least if the filesystem we are writing is a real physical one.
7704 * While this will save us against the server being killed I don't think
7705 * there is much to do about the whole server stopping for power problems
7707 nwritten
= write(server
.appendfd
,buf
,sdslen(buf
));
7708 if (nwritten
!= (signed)sdslen(buf
)) {
7709 /* Ooops, we are in troubles. The best thing to do for now is
7710 * to simply exit instead to give the illusion that everything is
7711 * working as expected. */
7712 if (nwritten
== -1) {
7713 redisLog(REDIS_WARNING
,"Exiting on error writing to the append-only file: %s",strerror(errno
));
7715 redisLog(REDIS_WARNING
,"Exiting on short write while writing to the append-only file: %s",strerror(errno
));
7719 /* If a background append only file rewriting is in progress we want to
7720 * accumulate the differences between the child DB and the current one
7721 * in a buffer, so that when the child process will do its work we
7722 * can append the differences to the new append only file. */
7723 if (server
.bgrewritechildpid
!= -1)
7724 server
.bgrewritebuf
= sdscatlen(server
.bgrewritebuf
,buf
,sdslen(buf
));
7728 if (server
.appendfsync
== APPENDFSYNC_ALWAYS
||
7729 (server
.appendfsync
== APPENDFSYNC_EVERYSEC
&&
7730 now
-server
.lastfsync
> 1))
7732 fsync(server
.appendfd
); /* Let's try to get this data on the disk */
7733 server
.lastfsync
= now
;
7737 /* In Redis commands are always executed in the context of a client, so in
7738 * order to load the append only file we need to create a fake client. */
7739 static struct redisClient
*createFakeClient(void) {
7740 struct redisClient
*c
= zmalloc(sizeof(*c
));
7744 c
->querybuf
= sdsempty();
7748 /* We set the fake client as a slave waiting for the synchronization
7749 * so that Redis will not try to send replies to this client. */
7750 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
7751 c
->reply
= listCreate();
7752 listSetFreeMethod(c
->reply
,decrRefCount
);
7753 listSetDupMethod(c
->reply
,dupClientReplyValue
);
7757 static void freeFakeClient(struct redisClient
*c
) {
7758 sdsfree(c
->querybuf
);
7759 listRelease(c
->reply
);
7763 /* Replay the append log file. On error REDIS_OK is returned. On non fatal
7764 * error (the append only file is zero-length) REDIS_ERR is returned. On
7765 * fatal error an error message is logged and the program exists. */
7766 int loadAppendOnlyFile(char *filename
) {
7767 struct redisClient
*fakeClient
;
7768 FILE *fp
= fopen(filename
,"r");
7769 struct redis_stat sb
;
7770 unsigned long long loadedkeys
= 0;
7772 if (redis_fstat(fileno(fp
),&sb
) != -1 && sb
.st_size
== 0)
7776 redisLog(REDIS_WARNING
,"Fatal error: can't open the append log file for reading: %s",strerror(errno
));
7780 fakeClient
= createFakeClient();
7787 struct redisCommand
*cmd
;
7789 if (fgets(buf
,sizeof(buf
),fp
) == NULL
) {
7795 if (buf
[0] != '*') goto fmterr
;
7797 argv
= zmalloc(sizeof(robj
*)*argc
);
7798 for (j
= 0; j
< argc
; j
++) {
7799 if (fgets(buf
,sizeof(buf
),fp
) == NULL
) goto readerr
;
7800 if (buf
[0] != '$') goto fmterr
;
7801 len
= strtol(buf
+1,NULL
,10);
7802 argsds
= sdsnewlen(NULL
,len
);
7803 if (len
&& fread(argsds
,len
,1,fp
) == 0) goto fmterr
;
7804 argv
[j
] = createObject(REDIS_STRING
,argsds
);
7805 if (fread(buf
,2,1,fp
) == 0) goto fmterr
; /* discard CRLF */
7808 /* Command lookup */
7809 cmd
= lookupCommand(argv
[0]->ptr
);
7811 redisLog(REDIS_WARNING
,"Unknown command '%s' reading the append only file", argv
[0]->ptr
);
7814 /* Try object sharing and encoding */
7815 if (server
.shareobjects
) {
7817 for(j
= 1; j
< argc
; j
++)
7818 argv
[j
] = tryObjectSharing(argv
[j
]);
7820 if (cmd
->flags
& REDIS_CMD_BULK
)
7821 tryObjectEncoding(argv
[argc
-1]);
7822 /* Run the command in the context of a fake client */
7823 fakeClient
->argc
= argc
;
7824 fakeClient
->argv
= argv
;
7825 cmd
->proc(fakeClient
);
7826 /* Discard the reply objects list from the fake client */
7827 while(listLength(fakeClient
->reply
))
7828 listDelNode(fakeClient
->reply
,listFirst(fakeClient
->reply
));
7829 /* Clean up, ready for the next command */
7830 for (j
= 0; j
< argc
; j
++) decrRefCount(argv
[j
]);
7832 /* Handle swapping while loading big datasets when VM is on */
7834 if (server
.vm_enabled
&& (loadedkeys
% 5000) == 0) {
7835 while (zmalloc_used_memory() > server
.vm_max_memory
) {
7836 if (vmSwapOneObjectBlocking() == REDIS_ERR
) break;
7841 freeFakeClient(fakeClient
);
7846 redisLog(REDIS_WARNING
,"Unexpected end of file reading the append only file");
7848 redisLog(REDIS_WARNING
,"Unrecoverable error reading the append only file: %s", strerror(errno
));
7852 redisLog(REDIS_WARNING
,"Bad file format reading the append only file");
7856 /* Write an object into a file in the bulk format $<count>\r\n<payload>\r\n */
7857 static int fwriteBulkObject(FILE *fp
, robj
*obj
) {
7861 /* Avoid the incr/decr ref count business if possible to help
7862 * copy-on-write (we are often in a child process when this function
7864 * Also makes sure that key objects don't get incrRefCount-ed when VM
7866 if (obj
->encoding
!= REDIS_ENCODING_RAW
) {
7867 obj
= getDecodedObject(obj
);
7870 snprintf(buf
,sizeof(buf
),"$%ld\r\n",(long)sdslen(obj
->ptr
));
7871 if (fwrite(buf
,strlen(buf
),1,fp
) == 0) goto err
;
7872 if (sdslen(obj
->ptr
) && fwrite(obj
->ptr
,sdslen(obj
->ptr
),1,fp
) == 0)
7874 if (fwrite("\r\n",2,1,fp
) == 0) goto err
;
7875 if (decrrc
) decrRefCount(obj
);
7878 if (decrrc
) decrRefCount(obj
);
7882 /* Write binary-safe string into a file in the bulkformat
7883 * $<count>\r\n<payload>\r\n */
7884 static int fwriteBulkString(FILE *fp
, char *s
, unsigned long len
) {
7887 snprintf(buf
,sizeof(buf
),"$%ld\r\n",(unsigned long)len
);
7888 if (fwrite(buf
,strlen(buf
),1,fp
) == 0) return 0;
7889 if (len
&& fwrite(s
,len
,1,fp
) == 0) return 0;
7890 if (fwrite("\r\n",2,1,fp
) == 0) return 0;
7894 /* Write a double value in bulk format $<count>\r\n<payload>\r\n */
7895 static int fwriteBulkDouble(FILE *fp
, double d
) {
7896 char buf
[128], dbuf
[128];
7898 snprintf(dbuf
,sizeof(dbuf
),"%.17g\r\n",d
);
7899 snprintf(buf
,sizeof(buf
),"$%lu\r\n",(unsigned long)strlen(dbuf
)-2);
7900 if (fwrite(buf
,strlen(buf
),1,fp
) == 0) return 0;
7901 if (fwrite(dbuf
,strlen(dbuf
),1,fp
) == 0) return 0;
7905 /* Write a long value in bulk format $<count>\r\n<payload>\r\n */
7906 static int fwriteBulkLong(FILE *fp
, long l
) {
7907 char buf
[128], lbuf
[128];
7909 snprintf(lbuf
,sizeof(lbuf
),"%ld\r\n",l
);
7910 snprintf(buf
,sizeof(buf
),"$%lu\r\n",(unsigned long)strlen(lbuf
)-2);
7911 if (fwrite(buf
,strlen(buf
),1,fp
) == 0) return 0;
7912 if (fwrite(lbuf
,strlen(lbuf
),1,fp
) == 0) return 0;
7916 /* Write a sequence of commands able to fully rebuild the dataset into
7917 * "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
7918 static int rewriteAppendOnlyFile(char *filename
) {
7919 dictIterator
*di
= NULL
;
7924 time_t now
= time(NULL
);
7926 /* Note that we have to use a different temp name here compared to the
7927 * one used by rewriteAppendOnlyFileBackground() function. */
7928 snprintf(tmpfile
,256,"temp-rewriteaof-%d.aof", (int) getpid());
7929 fp
= fopen(tmpfile
,"w");
7931 redisLog(REDIS_WARNING
, "Failed rewriting the append only file: %s", strerror(errno
));
7934 for (j
= 0; j
< server
.dbnum
; j
++) {
7935 char selectcmd
[] = "*2\r\n$6\r\nSELECT\r\n";
7936 redisDb
*db
= server
.db
+j
;
7938 if (dictSize(d
) == 0) continue;
7939 di
= dictGetIterator(d
);
7945 /* SELECT the new DB */
7946 if (fwrite(selectcmd
,sizeof(selectcmd
)-1,1,fp
) == 0) goto werr
;
7947 if (fwriteBulkLong(fp
,j
) == 0) goto werr
;
7949 /* Iterate this DB writing every entry */
7950 while((de
= dictNext(di
)) != NULL
) {
7955 key
= dictGetEntryKey(de
);
7956 /* If the value for this key is swapped, load a preview in memory.
7957 * We use a "swapped" flag to remember if we need to free the
7958 * value object instead to just increment the ref count anyway
7959 * in order to avoid copy-on-write of pages if we are forked() */
7960 if (!server
.vm_enabled
|| key
->storage
== REDIS_VM_MEMORY
||
7961 key
->storage
== REDIS_VM_SWAPPING
) {
7962 o
= dictGetEntryVal(de
);
7965 o
= vmPreviewObject(key
);
7968 expiretime
= getExpire(db
,key
);
7970 /* Save the key and associated value */
7971 if (o
->type
== REDIS_STRING
) {
7972 /* Emit a SET command */
7973 char cmd
[]="*3\r\n$3\r\nSET\r\n";
7974 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
7976 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
7977 if (fwriteBulkObject(fp
,o
) == 0) goto werr
;
7978 } else if (o
->type
== REDIS_LIST
) {
7979 /* Emit the RPUSHes needed to rebuild the list */
7980 list
*list
= o
->ptr
;
7984 listRewind(list
,&li
);
7985 while((ln
= listNext(&li
))) {
7986 char cmd
[]="*3\r\n$5\r\nRPUSH\r\n";
7987 robj
*eleobj
= listNodeValue(ln
);
7989 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
7990 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
7991 if (fwriteBulkObject(fp
,eleobj
) == 0) goto werr
;
7993 } else if (o
->type
== REDIS_SET
) {
7994 /* Emit the SADDs needed to rebuild the set */
7996 dictIterator
*di
= dictGetIterator(set
);
7999 while((de
= dictNext(di
)) != NULL
) {
8000 char cmd
[]="*3\r\n$4\r\nSADD\r\n";
8001 robj
*eleobj
= dictGetEntryKey(de
);
8003 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
8004 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
8005 if (fwriteBulkObject(fp
,eleobj
) == 0) goto werr
;
8007 dictReleaseIterator(di
);
8008 } else if (o
->type
== REDIS_ZSET
) {
8009 /* Emit the ZADDs needed to rebuild the sorted set */
8011 dictIterator
*di
= dictGetIterator(zs
->dict
);
8014 while((de
= dictNext(di
)) != NULL
) {
8015 char cmd
[]="*4\r\n$4\r\nZADD\r\n";
8016 robj
*eleobj
= dictGetEntryKey(de
);
8017 double *score
= dictGetEntryVal(de
);
8019 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
8020 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
8021 if (fwriteBulkDouble(fp
,*score
) == 0) goto werr
;
8022 if (fwriteBulkObject(fp
,eleobj
) == 0) goto werr
;
8024 dictReleaseIterator(di
);
8025 } else if (o
->type
== REDIS_HASH
) {
8026 char cmd
[]="*4\r\n$4\r\nHSET\r\n";
8028 /* Emit the HSETs needed to rebuild the hash */
8029 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
8030 unsigned char *p
= zipmapRewind(o
->ptr
);
8031 unsigned char *field
, *val
;
8032 unsigned int flen
, vlen
;
8034 while((p
= zipmapNext(p
,&field
,&flen
,&val
,&vlen
)) != NULL
) {
8035 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
8036 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
8037 if (fwriteBulkString(fp
,(char*)field
,flen
) == -1)
8039 if (fwriteBulkString(fp
,(char*)val
,vlen
) == -1)
8043 dictIterator
*di
= dictGetIterator(o
->ptr
);
8046 while((de
= dictNext(di
)) != NULL
) {
8047 robj
*field
= dictGetEntryKey(de
);
8048 robj
*val
= dictGetEntryVal(de
);
8050 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
8051 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
8052 if (fwriteBulkObject(fp
,field
) == -1) return -1;
8053 if (fwriteBulkObject(fp
,val
) == -1) return -1;
8055 dictReleaseIterator(di
);
8060 /* Save the expire time */
8061 if (expiretime
!= -1) {
8062 char cmd
[]="*3\r\n$8\r\nEXPIREAT\r\n";
8063 /* If this key is already expired skip it */
8064 if (expiretime
< now
) continue;
8065 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
8066 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
8067 if (fwriteBulkLong(fp
,expiretime
) == 0) goto werr
;
8069 if (swapped
) decrRefCount(o
);
8071 dictReleaseIterator(di
);
8074 /* Make sure data will not remain on the OS's output buffers */
8079 /* Use RENAME to make sure the DB file is changed atomically only
8080 * if the generate DB file is ok. */
8081 if (rename(tmpfile
,filename
) == -1) {
8082 redisLog(REDIS_WARNING
,"Error moving temp append only file on the final destination: %s", strerror(errno
));
8086 redisLog(REDIS_NOTICE
,"SYNC append only file rewrite performed");
8092 redisLog(REDIS_WARNING
,"Write error writing append only file on disk: %s", strerror(errno
));
8093 if (di
) dictReleaseIterator(di
);
8097 /* This is how rewriting of the append only file in background works:
8099 * 1) The user calls BGREWRITEAOF
8100 * 2) Redis calls this function, that forks():
8101 * 2a) the child rewrite the append only file in a temp file.
8102 * 2b) the parent accumulates differences in server.bgrewritebuf.
8103 * 3) When the child finished '2a' exists.
8104 * 4) The parent will trap the exit code, if it's OK, will append the
8105 * data accumulated into server.bgrewritebuf into the temp file, and
8106 * finally will rename(2) the temp file in the actual file name.
8107 * The the new file is reopened as the new append only file. Profit!
8109 static int rewriteAppendOnlyFileBackground(void) {
8112 if (server
.bgrewritechildpid
!= -1) return REDIS_ERR
;
8113 if (server
.vm_enabled
) waitEmptyIOJobsQueue();
8114 if ((childpid
= fork()) == 0) {
8118 if (server
.vm_enabled
) vmReopenSwapFile();
8120 snprintf(tmpfile
,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
8121 if (rewriteAppendOnlyFile(tmpfile
) == REDIS_OK
) {
8128 if (childpid
== -1) {
8129 redisLog(REDIS_WARNING
,
8130 "Can't rewrite append only file in background: fork: %s",
8134 redisLog(REDIS_NOTICE
,
8135 "Background append only file rewriting started by pid %d",childpid
);
8136 server
.bgrewritechildpid
= childpid
;
8137 updateDictResizePolicy();
8138 /* We set appendseldb to -1 in order to force the next call to the
8139 * feedAppendOnlyFile() to issue a SELECT command, so the differences
8140 * accumulated by the parent into server.bgrewritebuf will start
8141 * with a SELECT statement and it will be safe to merge. */
8142 server
.appendseldb
= -1;
8145 return REDIS_OK
; /* unreached */
8148 static void bgrewriteaofCommand(redisClient
*c
) {
8149 if (server
.bgrewritechildpid
!= -1) {
8150 addReplySds(c
,sdsnew("-ERR background append only file rewriting already in progress\r\n"));
8153 if (rewriteAppendOnlyFileBackground() == REDIS_OK
) {
8154 char *status
= "+Background append only file rewriting started\r\n";
8155 addReplySds(c
,sdsnew(status
));
8157 addReply(c
,shared
.err
);
8161 static void aofRemoveTempFile(pid_t childpid
) {
8164 snprintf(tmpfile
,256,"temp-rewriteaof-bg-%d.aof", (int) childpid
);
8168 /* Virtual Memory is composed mainly of two subsystems:
8169 * - Blocking Virutal Memory
8170 * - Threaded Virtual Memory I/O
8171 * The two parts are not fully decoupled, but functions are split among two
8172 * different sections of the source code (delimited by comments) in order to
8173 * make more clear what functionality is about the blocking VM and what about
8174 * the threaded (not blocking) VM.
8178 * Redis VM is a blocking VM (one that blocks reading swapped values from
8179 * disk into memory when a value swapped out is needed in memory) that is made
8180 * unblocking by trying to examine the command argument vector in order to
8181 * load in background values that will likely be needed in order to exec
8182 * the command. The command is executed only once all the relevant keys
8183 * are loaded into memory.
8185 * This basically is almost as simple of a blocking VM, but almost as parallel
8186 * as a fully non-blocking VM.
8189 /* =================== Virtual Memory - Blocking Side ====================== */
8191 /* substitute the first occurrence of '%p' with the process pid in the
8192 * swap file name. */
8193 static void expandVmSwapFilename(void) {
8194 char *p
= strstr(server
.vm_swap_file
,"%p");
8200 new = sdscat(new,server
.vm_swap_file
);
8201 new = sdscatprintf(new,"%ld",(long) getpid());
8202 new = sdscat(new,p
+2);
8203 zfree(server
.vm_swap_file
);
8204 server
.vm_swap_file
= new;
8207 static void vmInit(void) {
8212 if (server
.vm_max_threads
!= 0)
8213 zmalloc_enable_thread_safeness(); /* we need thread safe zmalloc() */
8215 expandVmSwapFilename();
8216 redisLog(REDIS_NOTICE
,"Using '%s' as swap file",server
.vm_swap_file
);
8217 if ((server
.vm_fp
= fopen(server
.vm_swap_file
,"r+b")) == NULL
) {
8218 server
.vm_fp
= fopen(server
.vm_swap_file
,"w+b");
8220 if (server
.vm_fp
== NULL
) {
8221 redisLog(REDIS_WARNING
,
8222 "Impossible to open the swap file: %s. Exiting.",
8226 server
.vm_fd
= fileno(server
.vm_fp
);
8227 server
.vm_next_page
= 0;
8228 server
.vm_near_pages
= 0;
8229 server
.vm_stats_used_pages
= 0;
8230 server
.vm_stats_swapped_objects
= 0;
8231 server
.vm_stats_swapouts
= 0;
8232 server
.vm_stats_swapins
= 0;
8233 totsize
= server
.vm_pages
*server
.vm_page_size
;
8234 redisLog(REDIS_NOTICE
,"Allocating %lld bytes of swap file",totsize
);
8235 if (ftruncate(server
.vm_fd
,totsize
) == -1) {
8236 redisLog(REDIS_WARNING
,"Can't ftruncate swap file: %s. Exiting.",
8240 redisLog(REDIS_NOTICE
,"Swap file allocated with success");
8242 server
.vm_bitmap
= zmalloc((server
.vm_pages
+7)/8);
8243 redisLog(REDIS_VERBOSE
,"Allocated %lld bytes page table for %lld pages",
8244 (long long) (server
.vm_pages
+7)/8, server
.vm_pages
);
8245 memset(server
.vm_bitmap
,0,(server
.vm_pages
+7)/8);
8247 /* Initialize threaded I/O (used by Virtual Memory) */
8248 server
.io_newjobs
= listCreate();
8249 server
.io_processing
= listCreate();
8250 server
.io_processed
= listCreate();
8251 server
.io_ready_clients
= listCreate();
8252 pthread_mutex_init(&server
.io_mutex
,NULL
);
8253 pthread_mutex_init(&server
.obj_freelist_mutex
,NULL
);
8254 pthread_mutex_init(&server
.io_swapfile_mutex
,NULL
);
8255 server
.io_active_threads
= 0;
8256 if (pipe(pipefds
) == -1) {
8257 redisLog(REDIS_WARNING
,"Unable to intialized VM: pipe(2): %s. Exiting."
8261 server
.io_ready_pipe_read
= pipefds
[0];
8262 server
.io_ready_pipe_write
= pipefds
[1];
8263 redisAssert(anetNonBlock(NULL
,server
.io_ready_pipe_read
) != ANET_ERR
);
8264 /* LZF requires a lot of stack */
8265 pthread_attr_init(&server
.io_threads_attr
);
8266 pthread_attr_getstacksize(&server
.io_threads_attr
, &stacksize
);
8267 while (stacksize
< REDIS_THREAD_STACK_SIZE
) stacksize
*= 2;
8268 pthread_attr_setstacksize(&server
.io_threads_attr
, stacksize
);
8269 /* Listen for events in the threaded I/O pipe */
8270 if (aeCreateFileEvent(server
.el
, server
.io_ready_pipe_read
, AE_READABLE
,
8271 vmThreadedIOCompletedJob
, NULL
) == AE_ERR
)
8272 oom("creating file event");
8275 /* Mark the page as used */
8276 static void vmMarkPageUsed(off_t page
) {
8277 off_t byte
= page
/8;
8279 redisAssert(vmFreePage(page
) == 1);
8280 server
.vm_bitmap
[byte
] |= 1<<bit
;
8283 /* Mark N contiguous pages as used, with 'page' being the first. */
8284 static void vmMarkPagesUsed(off_t page
, off_t count
) {
8287 for (j
= 0; j
< count
; j
++)
8288 vmMarkPageUsed(page
+j
);
8289 server
.vm_stats_used_pages
+= count
;
8290 redisLog(REDIS_DEBUG
,"Mark USED pages: %lld pages at %lld\n",
8291 (long long)count
, (long long)page
);
8294 /* Mark the page as free */
8295 static void vmMarkPageFree(off_t page
) {
8296 off_t byte
= page
/8;
8298 redisAssert(vmFreePage(page
) == 0);
8299 server
.vm_bitmap
[byte
] &= ~(1<<bit
);
8302 /* Mark N contiguous pages as free, with 'page' being the first. */
8303 static void vmMarkPagesFree(off_t page
, off_t count
) {
8306 for (j
= 0; j
< count
; j
++)
8307 vmMarkPageFree(page
+j
);
8308 server
.vm_stats_used_pages
-= count
;
8309 redisLog(REDIS_DEBUG
,"Mark FREE pages: %lld pages at %lld\n",
8310 (long long)count
, (long long)page
);
8313 /* Test if the page is free */
8314 static int vmFreePage(off_t page
) {
8315 off_t byte
= page
/8;
8317 return (server
.vm_bitmap
[byte
] & (1<<bit
)) == 0;
8320 /* Find N contiguous free pages storing the first page of the cluster in *first.
8321 * Returns REDIS_OK if it was able to find N contiguous pages, otherwise
8322 * REDIS_ERR is returned.
8324 * This function uses a simple algorithm: we try to allocate
8325 * REDIS_VM_MAX_NEAR_PAGES sequentially, when we reach this limit we start
8326 * again from the start of the swap file searching for free spaces.
8328 * If it looks pretty clear that there are no free pages near our offset
8329 * we try to find less populated places doing a forward jump of
8330 * REDIS_VM_MAX_RANDOM_JUMP, then we start scanning again a few pages
8331 * without hurry, and then we jump again and so forth...
8333 * This function can be improved using a free list to avoid to guess
8334 * too much, since we could collect data about freed pages.
8336 * note: I implemented this function just after watching an episode of
8337 * Battlestar Galactica, where the hybrid was continuing to say "JUMP!"
8339 static int vmFindContiguousPages(off_t
*first
, off_t n
) {
8340 off_t base
, offset
= 0, since_jump
= 0, numfree
= 0;
8342 if (server
.vm_near_pages
== REDIS_VM_MAX_NEAR_PAGES
) {
8343 server
.vm_near_pages
= 0;
8344 server
.vm_next_page
= 0;
8346 server
.vm_near_pages
++; /* Yet another try for pages near to the old ones */
8347 base
= server
.vm_next_page
;
8349 while(offset
< server
.vm_pages
) {
8350 off_t
this = base
+offset
;
8352 /* If we overflow, restart from page zero */
8353 if (this >= server
.vm_pages
) {
8354 this -= server
.vm_pages
;
8356 /* Just overflowed, what we found on tail is no longer
8357 * interesting, as it's no longer contiguous. */
8361 if (vmFreePage(this)) {
8362 /* This is a free page */
8364 /* Already got N free pages? Return to the caller, with success */
8366 *first
= this-(n
-1);
8367 server
.vm_next_page
= this+1;
8368 redisLog(REDIS_DEBUG
, "FOUND CONTIGUOUS PAGES: %lld pages at %lld\n", (long long) n
, (long long) *first
);
8372 /* The current one is not a free page */
8376 /* Fast-forward if the current page is not free and we already
8377 * searched enough near this place. */
8379 if (!numfree
&& since_jump
>= REDIS_VM_MAX_RANDOM_JUMP
/4) {
8380 offset
+= random() % REDIS_VM_MAX_RANDOM_JUMP
;
8382 /* Note that even if we rewind after the jump, we are don't need
8383 * to make sure numfree is set to zero as we only jump *if* it
8384 * is set to zero. */
8386 /* Otherwise just check the next page */
8393 /* Write the specified object at the specified page of the swap file */
8394 static int vmWriteObjectOnSwap(robj
*o
, off_t page
) {
8395 if (server
.vm_enabled
) pthread_mutex_lock(&server
.io_swapfile_mutex
);
8396 if (fseeko(server
.vm_fp
,page
*server
.vm_page_size
,SEEK_SET
) == -1) {
8397 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.io_swapfile_mutex
);
8398 redisLog(REDIS_WARNING
,
8399 "Critical VM problem in vmWriteObjectOnSwap(): can't seek: %s",
8403 rdbSaveObject(server
.vm_fp
,o
);
8404 fflush(server
.vm_fp
);
8405 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.io_swapfile_mutex
);
8409 /* Swap the 'val' object relative to 'key' into disk. Store all the information
8410 * needed to later retrieve the object into the key object.
8411 * If we can't find enough contiguous empty pages to swap the object on disk
8412 * REDIS_ERR is returned. */
8413 static int vmSwapObjectBlocking(robj
*key
, robj
*val
) {
8414 off_t pages
= rdbSavedObjectPages(val
,NULL
);
8417 assert(key
->storage
== REDIS_VM_MEMORY
);
8418 assert(key
->refcount
== 1);
8419 if (vmFindContiguousPages(&page
,pages
) == REDIS_ERR
) return REDIS_ERR
;
8420 if (vmWriteObjectOnSwap(val
,page
) == REDIS_ERR
) return REDIS_ERR
;
8421 key
->vm
.page
= page
;
8422 key
->vm
.usedpages
= pages
;
8423 key
->storage
= REDIS_VM_SWAPPED
;
8424 key
->vtype
= val
->type
;
8425 decrRefCount(val
); /* Deallocate the object from memory. */
8426 vmMarkPagesUsed(page
,pages
);
8427 redisLog(REDIS_DEBUG
,"VM: object %s swapped out at %lld (%lld pages)",
8428 (unsigned char*) key
->ptr
,
8429 (unsigned long long) page
, (unsigned long long) pages
);
8430 server
.vm_stats_swapped_objects
++;
8431 server
.vm_stats_swapouts
++;
8435 static robj
*vmReadObjectFromSwap(off_t page
, int type
) {
8438 if (server
.vm_enabled
) pthread_mutex_lock(&server
.io_swapfile_mutex
);
8439 if (fseeko(server
.vm_fp
,page
*server
.vm_page_size
,SEEK_SET
) == -1) {
8440 redisLog(REDIS_WARNING
,
8441 "Unrecoverable VM problem in vmReadObjectFromSwap(): can't seek: %s",
8445 o
= rdbLoadObject(type
,server
.vm_fp
);
8447 redisLog(REDIS_WARNING
, "Unrecoverable VM problem in vmReadObjectFromSwap(): can't load object from swap file: %s", strerror(errno
));
8450 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.io_swapfile_mutex
);
8454 /* Load the value object relative to the 'key' object from swap to memory.
8455 * The newly allocated object is returned.
8457 * If preview is true the unserialized object is returned to the caller but
8458 * no changes are made to the key object, nor the pages are marked as freed */
8459 static robj
*vmGenericLoadObject(robj
*key
, int preview
) {
8462 redisAssert(key
->storage
== REDIS_VM_SWAPPED
|| key
->storage
== REDIS_VM_LOADING
);
8463 val
= vmReadObjectFromSwap(key
->vm
.page
,key
->vtype
);
8465 key
->storage
= REDIS_VM_MEMORY
;
8466 key
->vm
.atime
= server
.unixtime
;
8467 vmMarkPagesFree(key
->vm
.page
,key
->vm
.usedpages
);
8468 redisLog(REDIS_DEBUG
, "VM: object %s loaded from disk",
8469 (unsigned char*) key
->ptr
);
8470 server
.vm_stats_swapped_objects
--;
8472 redisLog(REDIS_DEBUG
, "VM: object %s previewed from disk",
8473 (unsigned char*) key
->ptr
);
8475 server
.vm_stats_swapins
++;
8479 /* Plain object loading, from swap to memory */
8480 static robj
*vmLoadObject(robj
*key
) {
8481 /* If we are loading the object in background, stop it, we
8482 * need to load this object synchronously ASAP. */
8483 if (key
->storage
== REDIS_VM_LOADING
)
8484 vmCancelThreadedIOJob(key
);
8485 return vmGenericLoadObject(key
,0);
8488 /* Just load the value on disk, without to modify the key.
8489 * This is useful when we want to perform some operation on the value
8490 * without to really bring it from swap to memory, like while saving the
8491 * dataset or rewriting the append only log. */
8492 static robj
*vmPreviewObject(robj
*key
) {
8493 return vmGenericLoadObject(key
,1);
8496 /* How a good candidate is this object for swapping?
8497 * The better candidate it is, the greater the returned value.
8499 * Currently we try to perform a fast estimation of the object size in
8500 * memory, and combine it with aging informations.
8502 * Basically swappability = idle-time * log(estimated size)
8504 * Bigger objects are preferred over smaller objects, but not
8505 * proportionally, this is why we use the logarithm. This algorithm is
8506 * just a first try and will probably be tuned later. */
8507 static double computeObjectSwappability(robj
*o
) {
8508 time_t age
= server
.unixtime
- o
->vm
.atime
;
8512 struct dictEntry
*de
;
8515 if (age
<= 0) return 0;
8518 if (o
->encoding
!= REDIS_ENCODING_RAW
) {
8521 asize
= sdslen(o
->ptr
)+sizeof(*o
)+sizeof(long)*2;
8526 listNode
*ln
= listFirst(l
);
8528 asize
= sizeof(list
);
8530 robj
*ele
= ln
->value
;
8533 elesize
= (ele
->encoding
== REDIS_ENCODING_RAW
) ?
8534 (sizeof(*o
)+sdslen(ele
->ptr
)) :
8536 asize
+= (sizeof(listNode
)+elesize
)*listLength(l
);
8541 z
= (o
->type
== REDIS_ZSET
);
8542 d
= z
? ((zset
*)o
->ptr
)->dict
: o
->ptr
;
8544 asize
= sizeof(dict
)+(sizeof(struct dictEntry
*)*dictSlots(d
));
8545 if (z
) asize
+= sizeof(zset
)-sizeof(dict
);
8550 de
= dictGetRandomKey(d
);
8551 ele
= dictGetEntryKey(de
);
8552 elesize
= (ele
->encoding
== REDIS_ENCODING_RAW
) ?
8553 (sizeof(*o
)+sdslen(ele
->ptr
)) :
8555 asize
+= (sizeof(struct dictEntry
)+elesize
)*dictSize(d
);
8556 if (z
) asize
+= sizeof(zskiplistNode
)*dictSize(d
);
8560 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
8561 unsigned char *p
= zipmapRewind((unsigned char*)o
->ptr
);
8562 unsigned int len
= zipmapLen((unsigned char*)o
->ptr
);
8563 unsigned int klen
, vlen
;
8564 unsigned char *key
, *val
;
8566 if ((p
= zipmapNext(p
,&key
,&klen
,&val
,&vlen
)) == NULL
) {
8570 asize
= len
*(klen
+vlen
+3);
8571 } else if (o
->encoding
== REDIS_ENCODING_HT
) {
8573 asize
= sizeof(dict
)+(sizeof(struct dictEntry
*)*dictSlots(d
));
8578 de
= dictGetRandomKey(d
);
8579 ele
= dictGetEntryKey(de
);
8580 elesize
= (ele
->encoding
== REDIS_ENCODING_RAW
) ?
8581 (sizeof(*o
)+sdslen(ele
->ptr
)) :
8583 ele
= dictGetEntryVal(de
);
8584 elesize
= (ele
->encoding
== REDIS_ENCODING_RAW
) ?
8585 (sizeof(*o
)+sdslen(ele
->ptr
)) :
8587 asize
+= (sizeof(struct dictEntry
)+elesize
)*dictSize(d
);
8592 return (double)age
*log(1+asize
);
8595 /* Try to swap an object that's a good candidate for swapping.
8596 * Returns REDIS_OK if the object was swapped, REDIS_ERR if it's not possible
8597 * to swap any object at all.
8599 * If 'usethreaded' is true, Redis will try to swap the object in background
8600 * using I/O threads. */
8601 static int vmSwapOneObject(int usethreads
) {
8603 struct dictEntry
*best
= NULL
;
8604 double best_swappability
= 0;
8605 redisDb
*best_db
= NULL
;
8608 for (j
= 0; j
< server
.dbnum
; j
++) {
8609 redisDb
*db
= server
.db
+j
;
8610 /* Why maxtries is set to 100?
8611 * Because this way (usually) we'll find 1 object even if just 1% - 2%
8612 * are swappable objects */
8615 if (dictSize(db
->dict
) == 0) continue;
8616 for (i
= 0; i
< 5; i
++) {
8618 double swappability
;
8620 if (maxtries
) maxtries
--;
8621 de
= dictGetRandomKey(db
->dict
);
8622 key
= dictGetEntryKey(de
);
8623 val
= dictGetEntryVal(de
);
8624 /* Only swap objects that are currently in memory.
8626 * Also don't swap shared objects if threaded VM is on, as we
8627 * try to ensure that the main thread does not touch the
8628 * object while the I/O thread is using it, but we can't
8629 * control other keys without adding additional mutex. */
8630 if (key
->storage
!= REDIS_VM_MEMORY
||
8631 (server
.vm_max_threads
!= 0 && val
->refcount
!= 1)) {
8632 if (maxtries
) i
--; /* don't count this try */
8635 swappability
= computeObjectSwappability(val
);
8636 if (!best
|| swappability
> best_swappability
) {
8638 best_swappability
= swappability
;
8643 if (best
== NULL
) return REDIS_ERR
;
8644 key
= dictGetEntryKey(best
);
8645 val
= dictGetEntryVal(best
);
8647 redisLog(REDIS_DEBUG
,"Key with best swappability: %s, %f",
8648 key
->ptr
, best_swappability
);
8650 /* Unshare the key if needed */
8651 if (key
->refcount
> 1) {
8652 robj
*newkey
= dupStringObject(key
);
8654 key
= dictGetEntryKey(best
) = newkey
;
8658 vmSwapObjectThreaded(key
,val
,best_db
);
8661 if (vmSwapObjectBlocking(key
,val
) == REDIS_OK
) {
8662 dictGetEntryVal(best
) = NULL
;
8670 static int vmSwapOneObjectBlocking() {
8671 return vmSwapOneObject(0);
8674 static int vmSwapOneObjectThreaded() {
8675 return vmSwapOneObject(1);
8678 /* Return true if it's safe to swap out objects in a given moment.
8679 * Basically we don't want to swap objects out while there is a BGSAVE
8680 * or a BGAEOREWRITE running in backgroud. */
8681 static int vmCanSwapOut(void) {
8682 return (server
.bgsavechildpid
== -1 && server
.bgrewritechildpid
== -1);
8685 /* Delete a key if swapped. Returns 1 if the key was found, was swapped
8686 * and was deleted. Otherwise 0 is returned. */
8687 static int deleteIfSwapped(redisDb
*db
, robj
*key
) {
8691 if ((de
= dictFind(db
->dict
,key
)) == NULL
) return 0;
8692 foundkey
= dictGetEntryKey(de
);
8693 if (foundkey
->storage
== REDIS_VM_MEMORY
) return 0;
8698 /* =================== Virtual Memory - Threaded I/O ======================= */
8700 static void freeIOJob(iojob
*j
) {
8701 if ((j
->type
== REDIS_IOJOB_PREPARE_SWAP
||
8702 j
->type
== REDIS_IOJOB_DO_SWAP
||
8703 j
->type
== REDIS_IOJOB_LOAD
) && j
->val
!= NULL
)
8704 decrRefCount(j
->val
);
8705 /* We don't decrRefCount the j->key field as we did't incremented
8706 * the count creating IO Jobs. This is because the key field here is
8707 * just used as an indentifier and if a key is removed the Job should
8708 * never be touched again. */
8712 /* Every time a thread finished a Job, it writes a byte into the write side
8713 * of an unix pipe in order to "awake" the main thread, and this function
8715 static void vmThreadedIOCompletedJob(aeEventLoop
*el
, int fd
, void *privdata
,
8719 int retval
, processed
= 0, toprocess
= -1, trytoswap
= 1;
8721 REDIS_NOTUSED(mask
);
8722 REDIS_NOTUSED(privdata
);
8724 /* For every byte we read in the read side of the pipe, there is one
8725 * I/O job completed to process. */
8726 while((retval
= read(fd
,buf
,1)) == 1) {
8730 struct dictEntry
*de
;
8732 redisLog(REDIS_DEBUG
,"Processing I/O completed job");
8734 /* Get the processed element (the oldest one) */
8736 assert(listLength(server
.io_processed
) != 0);
8737 if (toprocess
== -1) {
8738 toprocess
= (listLength(server
.io_processed
)*REDIS_MAX_COMPLETED_JOBS_PROCESSED
)/100;
8739 if (toprocess
<= 0) toprocess
= 1;
8741 ln
= listFirst(server
.io_processed
);
8743 listDelNode(server
.io_processed
,ln
);
8745 /* If this job is marked as canceled, just ignore it */
8750 /* Post process it in the main thread, as there are things we
8751 * can do just here to avoid race conditions and/or invasive locks */
8752 redisLog(REDIS_DEBUG
,"Job %p type: %d, key at %p (%s) refcount: %d\n", (void*) j
, j
->type
, (void*)j
->key
, (char*)j
->key
->ptr
, j
->key
->refcount
);
8753 de
= dictFind(j
->db
->dict
,j
->key
);
8755 key
= dictGetEntryKey(de
);
8756 if (j
->type
== REDIS_IOJOB_LOAD
) {
8759 /* Key loaded, bring it at home */
8760 key
->storage
= REDIS_VM_MEMORY
;
8761 key
->vm
.atime
= server
.unixtime
;
8762 vmMarkPagesFree(key
->vm
.page
,key
->vm
.usedpages
);
8763 redisLog(REDIS_DEBUG
, "VM: object %s loaded from disk (threaded)",
8764 (unsigned char*) key
->ptr
);
8765 server
.vm_stats_swapped_objects
--;
8766 server
.vm_stats_swapins
++;
8767 dictGetEntryVal(de
) = j
->val
;
8768 incrRefCount(j
->val
);
8771 /* Handle clients waiting for this key to be loaded. */
8772 handleClientsBlockedOnSwappedKey(db
,key
);
8773 } else if (j
->type
== REDIS_IOJOB_PREPARE_SWAP
) {
8774 /* Now we know the amount of pages required to swap this object.
8775 * Let's find some space for it, and queue this task again
8776 * rebranded as REDIS_IOJOB_DO_SWAP. */
8777 if (!vmCanSwapOut() ||
8778 vmFindContiguousPages(&j
->page
,j
->pages
) == REDIS_ERR
)
8780 /* Ooops... no space or we can't swap as there is
8781 * a fork()ed Redis trying to save stuff on disk. */
8783 key
->storage
= REDIS_VM_MEMORY
; /* undo operation */
8785 /* Note that we need to mark this pages as used now,
8786 * if the job will be canceled, we'll mark them as freed
8788 vmMarkPagesUsed(j
->page
,j
->pages
);
8789 j
->type
= REDIS_IOJOB_DO_SWAP
;
8794 } else if (j
->type
== REDIS_IOJOB_DO_SWAP
) {
8797 /* Key swapped. We can finally free some memory. */
8798 if (key
->storage
!= REDIS_VM_SWAPPING
) {
8799 printf("key->storage: %d\n",key
->storage
);
8800 printf("key->name: %s\n",(char*)key
->ptr
);
8801 printf("key->refcount: %d\n",key
->refcount
);
8802 printf("val: %p\n",(void*)j
->val
);
8803 printf("val->type: %d\n",j
->val
->type
);
8804 printf("val->ptr: %s\n",(char*)j
->val
->ptr
);
8806 redisAssert(key
->storage
== REDIS_VM_SWAPPING
);
8807 val
= dictGetEntryVal(de
);
8808 key
->vm
.page
= j
->page
;
8809 key
->vm
.usedpages
= j
->pages
;
8810 key
->storage
= REDIS_VM_SWAPPED
;
8811 key
->vtype
= j
->val
->type
;
8812 decrRefCount(val
); /* Deallocate the object from memory. */
8813 dictGetEntryVal(de
) = NULL
;
8814 redisLog(REDIS_DEBUG
,
8815 "VM: object %s swapped out at %lld (%lld pages) (threaded)",
8816 (unsigned char*) key
->ptr
,
8817 (unsigned long long) j
->page
, (unsigned long long) j
->pages
);
8818 server
.vm_stats_swapped_objects
++;
8819 server
.vm_stats_swapouts
++;
8821 /* Put a few more swap requests in queue if we are still
8823 if (trytoswap
&& vmCanSwapOut() &&
8824 zmalloc_used_memory() > server
.vm_max_memory
)
8829 more
= listLength(server
.io_newjobs
) <
8830 (unsigned) server
.vm_max_threads
;
8832 /* Don't waste CPU time if swappable objects are rare. */
8833 if (vmSwapOneObjectThreaded() == REDIS_ERR
) {
8841 if (processed
== toprocess
) return;
8843 if (retval
< 0 && errno
!= EAGAIN
) {
8844 redisLog(REDIS_WARNING
,
8845 "WARNING: read(2) error in vmThreadedIOCompletedJob() %s",
8850 static void lockThreadedIO(void) {
8851 pthread_mutex_lock(&server
.io_mutex
);
8854 static void unlockThreadedIO(void) {
8855 pthread_mutex_unlock(&server
.io_mutex
);
8858 /* Remove the specified object from the threaded I/O queue if still not
8859 * processed, otherwise make sure to flag it as canceled. */
8860 static void vmCancelThreadedIOJob(robj
*o
) {
8862 server
.io_newjobs
, /* 0 */
8863 server
.io_processing
, /* 1 */
8864 server
.io_processed
/* 2 */
8868 assert(o
->storage
== REDIS_VM_LOADING
|| o
->storage
== REDIS_VM_SWAPPING
);
8871 /* Search for a matching key in one of the queues */
8872 for (i
= 0; i
< 3; i
++) {
8876 listRewind(lists
[i
],&li
);
8877 while ((ln
= listNext(&li
)) != NULL
) {
8878 iojob
*job
= ln
->value
;
8880 if (job
->canceled
) continue; /* Skip this, already canceled. */
8881 if (job
->key
== o
) {
8882 redisLog(REDIS_DEBUG
,"*** CANCELED %p (%s) (type %d) (LIST ID %d)\n",
8883 (void*)job
, (char*)o
->ptr
, job
->type
, i
);
8884 /* Mark the pages as free since the swap didn't happened
8885 * or happened but is now discarded. */
8886 if (i
!= 1 && job
->type
== REDIS_IOJOB_DO_SWAP
)
8887 vmMarkPagesFree(job
->page
,job
->pages
);
8888 /* Cancel the job. It depends on the list the job is
8891 case 0: /* io_newjobs */
8892 /* If the job was yet not processed the best thing to do
8893 * is to remove it from the queue at all */
8895 listDelNode(lists
[i
],ln
);
8897 case 1: /* io_processing */
8898 /* Oh Shi- the thread is messing with the Job:
8900 * Probably it's accessing the object if this is a
8901 * PREPARE_SWAP or DO_SWAP job.
8902 * If it's a LOAD job it may be reading from disk and
8903 * if we don't wait for the job to terminate before to
8904 * cancel it, maybe in a few microseconds data can be
8905 * corrupted in this pages. So the short story is:
8907 * Better to wait for the job to move into the
8908 * next queue (processed)... */
8910 /* We try again and again until the job is completed. */
8912 /* But let's wait some time for the I/O thread
8913 * to finish with this job. After all this condition
8914 * should be very rare. */
8917 case 2: /* io_processed */
8918 /* The job was already processed, that's easy...
8919 * just mark it as canceled so that we'll ignore it
8920 * when processing completed jobs. */
8924 /* Finally we have to adjust the storage type of the object
8925 * in order to "UNDO" the operaiton. */
8926 if (o
->storage
== REDIS_VM_LOADING
)
8927 o
->storage
= REDIS_VM_SWAPPED
;
8928 else if (o
->storage
== REDIS_VM_SWAPPING
)
8929 o
->storage
= REDIS_VM_MEMORY
;
8936 assert(1 != 1); /* We should never reach this */
8939 static void *IOThreadEntryPoint(void *arg
) {
8944 pthread_detach(pthread_self());
8946 /* Get a new job to process */
8948 if (listLength(server
.io_newjobs
) == 0) {
8949 /* No new jobs in queue, exit. */
8950 redisLog(REDIS_DEBUG
,"Thread %ld exiting, nothing to do",
8951 (long) pthread_self());
8952 server
.io_active_threads
--;
8956 ln
= listFirst(server
.io_newjobs
);
8958 listDelNode(server
.io_newjobs
,ln
);
8959 /* Add the job in the processing queue */
8960 j
->thread
= pthread_self();
8961 listAddNodeTail(server
.io_processing
,j
);
8962 ln
= listLast(server
.io_processing
); /* We use ln later to remove it */
8964 redisLog(REDIS_DEBUG
,"Thread %ld got a new job (type %d): %p about key '%s'",
8965 (long) pthread_self(), j
->type
, (void*)j
, (char*)j
->key
->ptr
);
8967 /* Process the Job */
8968 if (j
->type
== REDIS_IOJOB_LOAD
) {
8969 j
->val
= vmReadObjectFromSwap(j
->page
,j
->key
->vtype
);
8970 } else if (j
->type
== REDIS_IOJOB_PREPARE_SWAP
) {
8971 FILE *fp
= fopen("/dev/null","w+");
8972 j
->pages
= rdbSavedObjectPages(j
->val
,fp
);
8974 } else if (j
->type
== REDIS_IOJOB_DO_SWAP
) {
8975 if (vmWriteObjectOnSwap(j
->val
,j
->page
) == REDIS_ERR
)
8979 /* Done: insert the job into the processed queue */
8980 redisLog(REDIS_DEBUG
,"Thread %ld completed the job: %p (key %s)",
8981 (long) pthread_self(), (void*)j
, (char*)j
->key
->ptr
);
8983 listDelNode(server
.io_processing
,ln
);
8984 listAddNodeTail(server
.io_processed
,j
);
8987 /* Signal the main thread there is new stuff to process */
8988 assert(write(server
.io_ready_pipe_write
,"x",1) == 1);
8990 return NULL
; /* never reached */
8993 static void spawnIOThread(void) {
8995 sigset_t mask
, omask
;
8999 sigaddset(&mask
,SIGCHLD
);
9000 sigaddset(&mask
,SIGHUP
);
9001 sigaddset(&mask
,SIGPIPE
);
9002 pthread_sigmask(SIG_SETMASK
, &mask
, &omask
);
9003 while ((err
= pthread_create(&thread
,&server
.io_threads_attr
,IOThreadEntryPoint
,NULL
)) != 0) {
9004 redisLog(REDIS_WARNING
,"Unable to spawn an I/O thread: %s",
9008 pthread_sigmask(SIG_SETMASK
, &omask
, NULL
);
9009 server
.io_active_threads
++;
9012 /* We need to wait for the last thread to exit before we are able to
9013 * fork() in order to BGSAVE or BGREWRITEAOF. */
9014 static void waitEmptyIOJobsQueue(void) {
9016 int io_processed_len
;
9019 if (listLength(server
.io_newjobs
) == 0 &&
9020 listLength(server
.io_processing
) == 0 &&
9021 server
.io_active_threads
== 0)
9026 /* While waiting for empty jobs queue condition we post-process some
9027 * finshed job, as I/O threads may be hanging trying to write against
9028 * the io_ready_pipe_write FD but there are so much pending jobs that
9030 io_processed_len
= listLength(server
.io_processed
);
9032 if (io_processed_len
) {
9033 vmThreadedIOCompletedJob(NULL
,server
.io_ready_pipe_read
,NULL
,0);
9034 usleep(1000); /* 1 millisecond */
9036 usleep(10000); /* 10 milliseconds */
9041 static void vmReopenSwapFile(void) {
9042 /* Note: we don't close the old one as we are in the child process
9043 * and don't want to mess at all with the original file object. */
9044 server
.vm_fp
= fopen(server
.vm_swap_file
,"r+b");
9045 if (server
.vm_fp
== NULL
) {
9046 redisLog(REDIS_WARNING
,"Can't re-open the VM swap file: %s. Exiting.",
9047 server
.vm_swap_file
);
9050 server
.vm_fd
= fileno(server
.vm_fp
);
9053 /* This function must be called while with threaded IO locked */
9054 static void queueIOJob(iojob
*j
) {
9055 redisLog(REDIS_DEBUG
,"Queued IO Job %p type %d about key '%s'\n",
9056 (void*)j
, j
->type
, (char*)j
->key
->ptr
);
9057 listAddNodeTail(server
.io_newjobs
,j
);
9058 if (server
.io_active_threads
< server
.vm_max_threads
)
9062 static int vmSwapObjectThreaded(robj
*key
, robj
*val
, redisDb
*db
) {
9065 assert(key
->storage
== REDIS_VM_MEMORY
);
9066 assert(key
->refcount
== 1);
9068 j
= zmalloc(sizeof(*j
));
9069 j
->type
= REDIS_IOJOB_PREPARE_SWAP
;
9075 j
->thread
= (pthread_t
) -1;
9076 key
->storage
= REDIS_VM_SWAPPING
;
9084 /* ============ Virtual Memory - Blocking clients on missing keys =========== */
9086 /* This function makes the clinet 'c' waiting for the key 'key' to be loaded.
9087 * If there is not already a job loading the key, it is craeted.
9088 * The key is added to the io_keys list in the client structure, and also
9089 * in the hash table mapping swapped keys to waiting clients, that is,
9090 * server.io_waited_keys. */
9091 static int waitForSwappedKey(redisClient
*c
, robj
*key
) {
9092 struct dictEntry
*de
;
9096 /* If the key does not exist or is already in RAM we don't need to
9097 * block the client at all. */
9098 de
= dictFind(c
->db
->dict
,key
);
9099 if (de
== NULL
) return 0;
9100 o
= dictGetEntryKey(de
);
9101 if (o
->storage
== REDIS_VM_MEMORY
) {
9103 } else if (o
->storage
== REDIS_VM_SWAPPING
) {
9104 /* We were swapping the key, undo it! */
9105 vmCancelThreadedIOJob(o
);
9109 /* OK: the key is either swapped, or being loaded just now. */
9111 /* Add the key to the list of keys this client is waiting for.
9112 * This maps clients to keys they are waiting for. */
9113 listAddNodeTail(c
->io_keys
,key
);
9116 /* Add the client to the swapped keys => clients waiting map. */
9117 de
= dictFind(c
->db
->io_keys
,key
);
9121 /* For every key we take a list of clients blocked for it */
9123 retval
= dictAdd(c
->db
->io_keys
,key
,l
);
9125 assert(retval
== DICT_OK
);
9127 l
= dictGetEntryVal(de
);
9129 listAddNodeTail(l
,c
);
9131 /* Are we already loading the key from disk? If not create a job */
9132 if (o
->storage
== REDIS_VM_SWAPPED
) {
9135 o
->storage
= REDIS_VM_LOADING
;
9136 j
= zmalloc(sizeof(*j
));
9137 j
->type
= REDIS_IOJOB_LOAD
;
9140 j
->key
->vtype
= o
->vtype
;
9141 j
->page
= o
->vm
.page
;
9144 j
->thread
= (pthread_t
) -1;
9152 /* Preload keys needed for the ZUNION and ZINTER commands. */
9153 static void zunionInterBlockClientOnSwappedKeys(redisClient
*c
) {
9155 num
= atoi(c
->argv
[2]->ptr
);
9156 for (i
= 0; i
< num
; i
++) {
9157 waitForSwappedKey(c
,c
->argv
[3+i
]);
9161 /* Is this client attempting to run a command against swapped keys?
9162 * If so, block it ASAP, load the keys in background, then resume it.
9164 * The important idea about this function is that it can fail! If keys will
9165 * still be swapped when the client is resumed, this key lookups will
9166 * just block loading keys from disk. In practical terms this should only
9167 * happen with SORT BY command or if there is a bug in this function.
9169 * Return 1 if the client is marked as blocked, 0 if the client can
9170 * continue as the keys it is going to access appear to be in memory. */
9171 static int blockClientOnSwappedKeys(struct redisCommand
*cmd
, redisClient
*c
) {
9174 if (cmd
->vm_preload_proc
!= NULL
) {
9175 cmd
->vm_preload_proc(c
);
9177 if (cmd
->vm_firstkey
== 0) return 0;
9178 last
= cmd
->vm_lastkey
;
9179 if (last
< 0) last
= c
->argc
+last
;
9180 for (j
= cmd
->vm_firstkey
; j
<= last
; j
+= cmd
->vm_keystep
)
9181 waitForSwappedKey(c
,c
->argv
[j
]);
9184 /* If the client was blocked for at least one key, mark it as blocked. */
9185 if (listLength(c
->io_keys
)) {
9186 c
->flags
|= REDIS_IO_WAIT
;
9187 aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
);
9188 server
.vm_blocked_clients
++;
9195 /* Remove the 'key' from the list of blocked keys for a given client.
9197 * The function returns 1 when there are no longer blocking keys after
9198 * the current one was removed (and the client can be unblocked). */
9199 static int dontWaitForSwappedKey(redisClient
*c
, robj
*key
) {
9203 struct dictEntry
*de
;
9205 /* Remove the key from the list of keys this client is waiting for. */
9206 listRewind(c
->io_keys
,&li
);
9207 while ((ln
= listNext(&li
)) != NULL
) {
9208 if (compareStringObjects(ln
->value
,key
) == 0) {
9209 listDelNode(c
->io_keys
,ln
);
9215 /* Remove the client form the key => waiting clients map. */
9216 de
= dictFind(c
->db
->io_keys
,key
);
9218 l
= dictGetEntryVal(de
);
9219 ln
= listSearchKey(l
,c
);
9222 if (listLength(l
) == 0)
9223 dictDelete(c
->db
->io_keys
,key
);
9225 return listLength(c
->io_keys
) == 0;
9228 static void handleClientsBlockedOnSwappedKey(redisDb
*db
, robj
*key
) {
9229 struct dictEntry
*de
;
9234 de
= dictFind(db
->io_keys
,key
);
9237 l
= dictGetEntryVal(de
);
9238 len
= listLength(l
);
9239 /* Note: we can't use something like while(listLength(l)) as the list
9240 * can be freed by the calling function when we remove the last element. */
9243 redisClient
*c
= ln
->value
;
9245 if (dontWaitForSwappedKey(c
,key
)) {
9246 /* Put the client in the list of clients ready to go as we
9247 * loaded all the keys about it. */
9248 listAddNodeTail(server
.io_ready_clients
,c
);
9253 /* =========================== Remote Configuration ========================= */
9255 static void configSetCommand(redisClient
*c
) {
9256 robj
*o
= getDecodedObject(c
->argv
[3]);
9257 if (!strcasecmp(c
->argv
[2]->ptr
,"dbfilename")) {
9258 zfree(server
.dbfilename
);
9259 server
.dbfilename
= zstrdup(o
->ptr
);
9260 } else if (!strcasecmp(c
->argv
[2]->ptr
,"requirepass")) {
9261 zfree(server
.requirepass
);
9262 server
.requirepass
= zstrdup(o
->ptr
);
9263 } else if (!strcasecmp(c
->argv
[2]->ptr
,"masterauth")) {
9264 zfree(server
.masterauth
);
9265 server
.masterauth
= zstrdup(o
->ptr
);
9266 } else if (!strcasecmp(c
->argv
[2]->ptr
,"maxmemory")) {
9267 server
.maxmemory
= strtoll(o
->ptr
, NULL
, 10);
9269 addReplySds(c
,sdscatprintf(sdsempty(),
9270 "-ERR not supported CONFIG parameter %s\r\n",
9271 (char*)c
->argv
[2]->ptr
));
9276 addReply(c
,shared
.ok
);
9279 static void configGetCommand(redisClient
*c
) {
9280 robj
*o
= getDecodedObject(c
->argv
[2]);
9281 robj
*lenobj
= createObject(REDIS_STRING
,NULL
);
9282 char *pattern
= o
->ptr
;
9286 decrRefCount(lenobj
);
9288 if (stringmatch(pattern
,"dbfilename",0)) {
9289 addReplyBulkCString(c
,"dbfilename");
9290 addReplyBulkCString(c
,server
.dbfilename
);
9293 if (stringmatch(pattern
,"requirepass",0)) {
9294 addReplyBulkCString(c
,"requirepass");
9295 addReplyBulkCString(c
,server
.requirepass
);
9298 if (stringmatch(pattern
,"masterauth",0)) {
9299 addReplyBulkCString(c
,"masterauth");
9300 addReplyBulkCString(c
,server
.masterauth
);
9303 if (stringmatch(pattern
,"maxmemory",0)) {
9306 snprintf(buf
,128,"%llu\n",server
.maxmemory
);
9307 addReplyBulkCString(c
,"maxmemory");
9308 addReplyBulkCString(c
,buf
);
9312 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%d\r\n",matches
*2);
9315 static void configCommand(redisClient
*c
) {
9316 if (!strcasecmp(c
->argv
[1]->ptr
,"set")) {
9317 if (c
->argc
!= 4) goto badarity
;
9318 configSetCommand(c
);
9319 } else if (!strcasecmp(c
->argv
[1]->ptr
,"get")) {
9320 if (c
->argc
!= 3) goto badarity
;
9321 configGetCommand(c
);
9322 } else if (!strcasecmp(c
->argv
[1]->ptr
,"resetstat")) {
9323 if (c
->argc
!= 2) goto badarity
;
9324 server
.stat_numcommands
= 0;
9325 server
.stat_numconnections
= 0;
9326 server
.stat_expiredkeys
= 0;
9327 server
.stat_starttime
= time(NULL
);
9328 addReply(c
,shared
.ok
);
9330 addReplySds(c
,sdscatprintf(sdsempty(),
9331 "-ERR CONFIG subcommand must be one of GET, SET, RESETSTAT\r\n"));
9336 addReplySds(c
,sdscatprintf(sdsempty(),
9337 "-ERR Wrong number of arguments for CONFIG %s\r\n",
9338 (char*) c
->argv
[1]->ptr
));
9341 /* =========================== Pubsub implementation ======================== */
9343 static void freePubsubPattern(void *p
) {
9344 pubsubPattern
*pat
= p
;
9346 decrRefCount(pat
->pattern
);
9350 static int listMatchPubsubPattern(void *a
, void *b
) {
9351 pubsubPattern
*pa
= a
, *pb
= b
;
9353 return (pa
->client
== pb
->client
) &&
9354 (compareStringObjects(pa
->pattern
,pb
->pattern
) == 0);
9357 /* Subscribe a client to a channel. Returns 1 if the operation succeeded, or
9358 * 0 if the client was already subscribed to that channel. */
9359 static int pubsubSubscribeChannel(redisClient
*c
, robj
*channel
) {
9360 struct dictEntry
*de
;
9361 list
*clients
= NULL
;
9364 /* Add the channel to the client -> channels hash table */
9365 if (dictAdd(c
->pubsub_channels
,channel
,NULL
) == DICT_OK
) {
9367 incrRefCount(channel
);
9368 /* Add the client to the channel -> list of clients hash table */
9369 de
= dictFind(server
.pubsub_channels
,channel
);
9371 clients
= listCreate();
9372 dictAdd(server
.pubsub_channels
,channel
,clients
);
9373 incrRefCount(channel
);
9375 clients
= dictGetEntryVal(de
);
9377 listAddNodeTail(clients
,c
);
9379 /* Notify the client */
9380 addReply(c
,shared
.mbulk3
);
9381 addReply(c
,shared
.subscribebulk
);
9382 addReplyBulk(c
,channel
);
9383 addReplyLong(c
,dictSize(c
->pubsub_channels
)+listLength(c
->pubsub_patterns
));
9387 /* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
9388 * 0 if the client was not subscribed to the specified channel. */
9389 static int pubsubUnsubscribeChannel(redisClient
*c
, robj
*channel
, int notify
) {
9390 struct dictEntry
*de
;
9395 /* Remove the channel from the client -> channels hash table */
9396 incrRefCount(channel
); /* channel may be just a pointer to the same object
9397 we have in the hash tables. Protect it... */
9398 if (dictDelete(c
->pubsub_channels
,channel
) == DICT_OK
) {
9400 /* Remove the client from the channel -> clients list hash table */
9401 de
= dictFind(server
.pubsub_channels
,channel
);
9403 clients
= dictGetEntryVal(de
);
9404 ln
= listSearchKey(clients
,c
);
9406 listDelNode(clients
,ln
);
9407 if (listLength(clients
) == 0) {
9408 /* Free the list and associated hash entry at all if this was
9409 * the latest client, so that it will be possible to abuse
9410 * Redis PUBSUB creating millions of channels. */
9411 dictDelete(server
.pubsub_channels
,channel
);
9414 /* Notify the client */
9416 addReply(c
,shared
.mbulk3
);
9417 addReply(c
,shared
.unsubscribebulk
);
9418 addReplyBulk(c
,channel
);
9419 addReplyLong(c
,dictSize(c
->pubsub_channels
)+
9420 listLength(c
->pubsub_patterns
));
9423 decrRefCount(channel
); /* it is finally safe to release it */
9427 /* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the clinet was already subscribed to that pattern. */
9428 static int pubsubSubscribePattern(redisClient
*c
, robj
*pattern
) {
9431 if (listSearchKey(c
->pubsub_patterns
,pattern
) == NULL
) {
9434 listAddNodeTail(c
->pubsub_patterns
,pattern
);
9435 incrRefCount(pattern
);
9436 pat
= zmalloc(sizeof(*pat
));
9437 pat
->pattern
= getDecodedObject(pattern
);
9439 listAddNodeTail(server
.pubsub_patterns
,pat
);
9441 /* Notify the client */
9442 addReply(c
,shared
.mbulk3
);
9443 addReply(c
,shared
.psubscribebulk
);
9444 addReplyBulk(c
,pattern
);
9445 addReplyLong(c
,dictSize(c
->pubsub_channels
)+listLength(c
->pubsub_patterns
));
9449 /* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
9450 * 0 if the client was not subscribed to the specified channel. */
9451 static int pubsubUnsubscribePattern(redisClient
*c
, robj
*pattern
, int notify
) {
9456 incrRefCount(pattern
); /* Protect the object. May be the same we remove */
9457 if ((ln
= listSearchKey(c
->pubsub_patterns
,pattern
)) != NULL
) {
9459 listDelNode(c
->pubsub_patterns
,ln
);
9461 pat
.pattern
= pattern
;
9462 ln
= listSearchKey(server
.pubsub_patterns
,&pat
);
9463 listDelNode(server
.pubsub_patterns
,ln
);
9465 /* Notify the client */
9467 addReply(c
,shared
.mbulk3
);
9468 addReply(c
,shared
.punsubscribebulk
);
9469 addReplyBulk(c
,pattern
);
9470 addReplyLong(c
,dictSize(c
->pubsub_channels
)+
9471 listLength(c
->pubsub_patterns
));
9473 decrRefCount(pattern
);
9477 /* Unsubscribe from all the channels. Return the number of channels the
9478 * client was subscribed from. */
9479 static int pubsubUnsubscribeAllChannels(redisClient
*c
, int notify
) {
9480 dictIterator
*di
= dictGetIterator(c
->pubsub_channels
);
9484 while((de
= dictNext(di
)) != NULL
) {
9485 robj
*channel
= dictGetEntryKey(de
);
9487 count
+= pubsubUnsubscribeChannel(c
,channel
,notify
);
9489 dictReleaseIterator(di
);
9493 /* Unsubscribe from all the patterns. Return the number of patterns the
9494 * client was subscribed from. */
9495 static int pubsubUnsubscribeAllPatterns(redisClient
*c
, int notify
) {
9500 listRewind(c
->pubsub_patterns
,&li
);
9501 while ((ln
= listNext(&li
)) != NULL
) {
9502 robj
*pattern
= ln
->value
;
9504 count
+= pubsubUnsubscribePattern(c
,pattern
,notify
);
9509 /* Publish a message */
9510 static int pubsubPublishMessage(robj
*channel
, robj
*message
) {
9512 struct dictEntry
*de
;
9516 /* Send to clients listening for that channel */
9517 de
= dictFind(server
.pubsub_channels
,channel
);
9519 list
*list
= dictGetEntryVal(de
);
9523 listRewind(list
,&li
);
9524 while ((ln
= listNext(&li
)) != NULL
) {
9525 redisClient
*c
= ln
->value
;
9527 addReply(c
,shared
.mbulk3
);
9528 addReply(c
,shared
.messagebulk
);
9529 addReplyBulk(c
,channel
);
9530 addReplyBulk(c
,message
);
9534 /* Send to clients listening to matching channels */
9535 if (listLength(server
.pubsub_patterns
)) {
9536 listRewind(server
.pubsub_patterns
,&li
);
9537 channel
= getDecodedObject(channel
);
9538 while ((ln
= listNext(&li
)) != NULL
) {
9539 pubsubPattern
*pat
= ln
->value
;
9541 if (stringmatchlen((char*)pat
->pattern
->ptr
,
9542 sdslen(pat
->pattern
->ptr
),
9543 (char*)channel
->ptr
,
9544 sdslen(channel
->ptr
),0)) {
9545 addReply(pat
->client
,shared
.mbulk3
);
9546 addReply(pat
->client
,shared
.messagebulk
);
9547 addReplyBulk(pat
->client
,channel
);
9548 addReplyBulk(pat
->client
,message
);
9552 decrRefCount(channel
);
9557 static void subscribeCommand(redisClient
*c
) {
9560 for (j
= 1; j
< c
->argc
; j
++)
9561 pubsubSubscribeChannel(c
,c
->argv
[j
]);
9564 static void unsubscribeCommand(redisClient
*c
) {
9566 pubsubUnsubscribeAllChannels(c
,1);
9571 for (j
= 1; j
< c
->argc
; j
++)
9572 pubsubUnsubscribeChannel(c
,c
->argv
[j
],1);
9576 static void psubscribeCommand(redisClient
*c
) {
9579 for (j
= 1; j
< c
->argc
; j
++)
9580 pubsubSubscribePattern(c
,c
->argv
[j
]);
9583 static void punsubscribeCommand(redisClient
*c
) {
9585 pubsubUnsubscribeAllPatterns(c
,1);
9590 for (j
= 1; j
< c
->argc
; j
++)
9591 pubsubUnsubscribePattern(c
,c
->argv
[j
],1);
9595 static void publishCommand(redisClient
*c
) {
9596 int receivers
= pubsubPublishMessage(c
->argv
[1],c
->argv
[2]);
9597 addReplyLong(c
,receivers
);
9600 /* ================================= Debugging ============================== */
9602 static void debugCommand(redisClient
*c
) {
9603 if (!strcasecmp(c
->argv
[1]->ptr
,"segfault")) {
9605 } else if (!strcasecmp(c
->argv
[1]->ptr
,"reload")) {
9606 if (rdbSave(server
.dbfilename
) != REDIS_OK
) {
9607 addReply(c
,shared
.err
);
9611 if (rdbLoad(server
.dbfilename
) != REDIS_OK
) {
9612 addReply(c
,shared
.err
);
9615 redisLog(REDIS_WARNING
,"DB reloaded by DEBUG RELOAD");
9616 addReply(c
,shared
.ok
);
9617 } else if (!strcasecmp(c
->argv
[1]->ptr
,"loadaof")) {
9619 if (loadAppendOnlyFile(server
.appendfilename
) != REDIS_OK
) {
9620 addReply(c
,shared
.err
);
9623 redisLog(REDIS_WARNING
,"Append Only File loaded by DEBUG LOADAOF");
9624 addReply(c
,shared
.ok
);
9625 } else if (!strcasecmp(c
->argv
[1]->ptr
,"object") && c
->argc
== 3) {
9626 dictEntry
*de
= dictFind(c
->db
->dict
,c
->argv
[2]);
9630 addReply(c
,shared
.nokeyerr
);
9633 key
= dictGetEntryKey(de
);
9634 val
= dictGetEntryVal(de
);
9635 if (!server
.vm_enabled
|| (key
->storage
== REDIS_VM_MEMORY
||
9636 key
->storage
== REDIS_VM_SWAPPING
)) {
9640 if (val
->encoding
< (sizeof(strencoding
)/sizeof(char*))) {
9641 strenc
= strencoding
[val
->encoding
];
9643 snprintf(buf
,64,"unknown encoding %d\n", val
->encoding
);
9646 addReplySds(c
,sdscatprintf(sdsempty(),
9647 "+Key at:%p refcount:%d, value at:%p refcount:%d "
9648 "encoding:%s serializedlength:%lld\r\n",
9649 (void*)key
, key
->refcount
, (void*)val
, val
->refcount
,
9650 strenc
, (long long) rdbSavedObjectLen(val
,NULL
)));
9652 addReplySds(c
,sdscatprintf(sdsempty(),
9653 "+Key at:%p refcount:%d, value swapped at: page %llu "
9654 "using %llu pages\r\n",
9655 (void*)key
, key
->refcount
, (unsigned long long) key
->vm
.page
,
9656 (unsigned long long) key
->vm
.usedpages
));
9658 } else if (!strcasecmp(c
->argv
[1]->ptr
,"swapin") && c
->argc
== 3) {
9659 lookupKeyRead(c
->db
,c
->argv
[2]);
9660 addReply(c
,shared
.ok
);
9661 } else if (!strcasecmp(c
->argv
[1]->ptr
,"swapout") && c
->argc
== 3) {
9662 dictEntry
*de
= dictFind(c
->db
->dict
,c
->argv
[2]);
9665 if (!server
.vm_enabled
) {
9666 addReplySds(c
,sdsnew("-ERR Virtual Memory is disabled\r\n"));
9670 addReply(c
,shared
.nokeyerr
);
9673 key
= dictGetEntryKey(de
);
9674 val
= dictGetEntryVal(de
);
9675 /* If the key is shared we want to create a copy */
9676 if (key
->refcount
> 1) {
9677 robj
*newkey
= dupStringObject(key
);
9679 key
= dictGetEntryKey(de
) = newkey
;
9682 if (key
->storage
!= REDIS_VM_MEMORY
) {
9683 addReplySds(c
,sdsnew("-ERR This key is not in memory\r\n"));
9684 } else if (vmSwapObjectBlocking(key
,val
) == REDIS_OK
) {
9685 dictGetEntryVal(de
) = NULL
;
9686 addReply(c
,shared
.ok
);
9688 addReply(c
,shared
.err
);
9691 addReplySds(c
,sdsnew(
9692 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPIN <key<|SWAPOUT <key>|RELOAD]\r\n"));
9696 static void _redisAssert(char *estr
, char *file
, int line
) {
9697 redisLog(REDIS_WARNING
,"=== ASSERTION FAILED ===");
9698 redisLog(REDIS_WARNING
,"==> %s:%d '%s' is not true\n",file
,line
,estr
);
9699 #ifdef HAVE_BACKTRACE
9700 redisLog(REDIS_WARNING
,"(forcing SIGSEGV in order to print the stack trace)");
9705 /* =================================== Main! ================================ */
9708 int linuxOvercommitMemoryValue(void) {
9709 FILE *fp
= fopen("/proc/sys/vm/overcommit_memory","r");
9713 if (fgets(buf
,64,fp
) == NULL
) {
9722 void linuxOvercommitMemoryWarning(void) {
9723 if (linuxOvercommitMemoryValue() == 0) {
9724 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.");
9727 #endif /* __linux__ */
9729 static void daemonize(void) {
9733 if (fork() != 0) exit(0); /* parent exits */
9734 setsid(); /* create a new session */
9736 /* Every output goes to /dev/null. If Redis is daemonized but
9737 * the 'logfile' is set to 'stdout' in the configuration file
9738 * it will not log at all. */
9739 if ((fd
= open("/dev/null", O_RDWR
, 0)) != -1) {
9740 dup2(fd
, STDIN_FILENO
);
9741 dup2(fd
, STDOUT_FILENO
);
9742 dup2(fd
, STDERR_FILENO
);
9743 if (fd
> STDERR_FILENO
) close(fd
);
9745 /* Try to write the pid file */
9746 fp
= fopen(server
.pidfile
,"w");
9748 fprintf(fp
,"%d\n",getpid());
9753 static void version() {
9754 printf("Redis server version %s\n", REDIS_VERSION
);
9758 static void usage() {
9759 fprintf(stderr
,"Usage: ./redis-server [/path/to/redis.conf]\n");
9760 fprintf(stderr
," ./redis-server - (read config from stdin)\n");
9764 int main(int argc
, char **argv
) {
9769 if (strcmp(argv
[1], "-v") == 0 ||
9770 strcmp(argv
[1], "--version") == 0) version();
9771 if (strcmp(argv
[1], "--help") == 0) usage();
9772 resetServerSaveParams();
9773 loadServerConfig(argv
[1]);
9774 } else if ((argc
> 2)) {
9777 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'");
9779 if (server
.daemonize
) daemonize();
9781 redisLog(REDIS_NOTICE
,"Server started, Redis version " REDIS_VERSION
);
9783 linuxOvercommitMemoryWarning();
9786 if (server
.appendonly
) {
9787 if (loadAppendOnlyFile(server
.appendfilename
) == REDIS_OK
)
9788 redisLog(REDIS_NOTICE
,"DB loaded from append only file: %ld seconds",time(NULL
)-start
);
9790 if (rdbLoad(server
.dbfilename
) == REDIS_OK
)
9791 redisLog(REDIS_NOTICE
,"DB loaded from disk: %ld seconds",time(NULL
)-start
);
9793 redisLog(REDIS_NOTICE
,"The server is now ready to accept connections on port %d", server
.port
);
9794 aeSetBeforeSleepProc(server
.el
,beforeSleep
);
9796 aeDeleteEventLoop(server
.el
);
9800 /* ============================= Backtrace support ========================= */
9802 #ifdef HAVE_BACKTRACE
9803 static char *findFuncName(void *pointer
, unsigned long *offset
);
9805 static void *getMcontextEip(ucontext_t
*uc
) {
9806 #if defined(__FreeBSD__)
9807 return (void*) uc
->uc_mcontext
.mc_eip
;
9808 #elif defined(__dietlibc__)
9809 return (void*) uc
->uc_mcontext
.eip
;
9810 #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
9812 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
9814 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
9816 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
9817 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
9818 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
9820 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
9822 #elif defined(__i386__) || defined(__X86_64__) || defined(__x86_64__)
9823 return (void*) uc
->uc_mcontext
.gregs
[REG_EIP
]; /* Linux 32/64 bit */
9824 #elif defined(__ia64__) /* Linux IA64 */
9825 return (void*) uc
->uc_mcontext
.sc_ip
;
9831 static void segvHandler(int sig
, siginfo_t
*info
, void *secret
) {
9833 char **messages
= NULL
;
9834 int i
, trace_size
= 0;
9835 unsigned long offset
=0;
9836 ucontext_t
*uc
= (ucontext_t
*) secret
;
9838 REDIS_NOTUSED(info
);
9840 redisLog(REDIS_WARNING
,
9841 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION
, sig
);
9842 infostring
= genRedisInfoString();
9843 redisLog(REDIS_WARNING
, "%s",infostring
);
9844 /* It's not safe to sdsfree() the returned string under memory
9845 * corruption conditions. Let it leak as we are going to abort */
9847 trace_size
= backtrace(trace
, 100);
9848 /* overwrite sigaction with caller's address */
9849 if (getMcontextEip(uc
) != NULL
) {
9850 trace
[1] = getMcontextEip(uc
);
9852 messages
= backtrace_symbols(trace
, trace_size
);
9854 for (i
=1; i
<trace_size
; ++i
) {
9855 char *fn
= findFuncName(trace
[i
], &offset
), *p
;
9857 p
= strchr(messages
[i
],'+');
9858 if (!fn
|| (p
&& ((unsigned long)strtol(p
+1,NULL
,10)) < offset
)) {
9859 redisLog(REDIS_WARNING
,"%s", messages
[i
]);
9861 redisLog(REDIS_WARNING
,"%d redis-server %p %s + %d", i
, trace
[i
], fn
, (unsigned int)offset
);
9864 /* free(messages); Don't call free() with possibly corrupted memory. */
9868 static void setupSigSegvAction(void) {
9869 struct sigaction act
;
9871 sigemptyset (&act
.sa_mask
);
9872 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
9873 * is used. Otherwise, sa_handler is used */
9874 act
.sa_flags
= SA_NODEFER
| SA_ONSTACK
| SA_RESETHAND
| SA_SIGINFO
;
9875 act
.sa_sigaction
= segvHandler
;
9876 sigaction (SIGSEGV
, &act
, NULL
);
9877 sigaction (SIGBUS
, &act
, NULL
);
9878 sigaction (SIGFPE
, &act
, NULL
);
9879 sigaction (SIGILL
, &act
, NULL
);
9880 sigaction (SIGBUS
, &act
, NULL
);
9884 #include "staticsymbols.h"
9885 /* This function try to convert a pointer into a function name. It's used in
9886 * oreder to provide a backtrace under segmentation fault that's able to
9887 * display functions declared as static (otherwise the backtrace is useless). */
9888 static char *findFuncName(void *pointer
, unsigned long *offset
){
9890 unsigned long off
, minoff
= 0;
9892 /* Try to match against the Symbol with the smallest offset */
9893 for (i
=0; symsTable
[i
].pointer
; i
++) {
9894 unsigned long lp
= (unsigned long) pointer
;
9896 if (lp
!= (unsigned long)-1 && lp
>= symsTable
[i
].pointer
) {
9897 off
=lp
-symsTable
[i
].pointer
;
9898 if (ret
< 0 || off
< minoff
) {
9904 if (ret
== -1) return NULL
;
9906 return symsTable
[ret
].name
;
9908 #else /* HAVE_BACKTRACE */
9909 static void setupSigSegvAction(void) {
9911 #endif /* HAVE_BACKTRACE */