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 static int serverCron(struct aeEventLoop
*eventLoop
, long long id
, void *clientData
) {
1298 int j
, loops
= server
.cronloops
++;
1299 REDIS_NOTUSED(eventLoop
);
1301 REDIS_NOTUSED(clientData
);
1303 /* We take a cached value of the unix time in the global state because
1304 * with virtual memory and aging there is to store the current time
1305 * in objects at every object access, and accuracy is not needed.
1306 * To access a global var is faster than calling time(NULL) */
1307 server
.unixtime
= time(NULL
);
1309 /* Show some info about non-empty databases */
1310 for (j
= 0; j
< server
.dbnum
; j
++) {
1311 long long size
, used
, vkeys
;
1313 size
= dictSlots(server
.db
[j
].dict
);
1314 used
= dictSize(server
.db
[j
].dict
);
1315 vkeys
= dictSize(server
.db
[j
].expires
);
1316 if (!(loops
% 50) && (used
|| vkeys
)) {
1317 redisLog(REDIS_VERBOSE
,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j
,used
,vkeys
,size
);
1318 /* dictPrintStats(server.dict); */
1322 /* We don't want to resize the hash tables while a bacground saving
1323 * is in progress: the saving child is created using fork() that is
1324 * implemented with a copy-on-write semantic in most modern systems, so
1325 * if we resize the HT while there is the saving child at work actually
1326 * a lot of memory movements in the parent will cause a lot of pages
1328 if (server
.bgsavechildpid
== -1 && !(loops
% 10)) tryResizeHashTables();
1330 /* Show information about connected clients */
1331 if (!(loops
% 50)) {
1332 redisLog(REDIS_VERBOSE
,"%d clients connected (%d slaves), %zu bytes in use, %d shared objects",
1333 listLength(server
.clients
)-listLength(server
.slaves
),
1334 listLength(server
.slaves
),
1335 zmalloc_used_memory(),
1336 dictSize(server
.sharingpool
));
1339 /* Close connections of timedout clients */
1340 if ((server
.maxidletime
&& !(loops
% 100)) || server
.blpop_blocked_clients
)
1341 closeTimedoutClients();
1343 /* Check if a background saving or AOF rewrite in progress terminated */
1344 if (server
.bgsavechildpid
!= -1 || server
.bgrewritechildpid
!= -1) {
1348 if ((pid
= wait3(&statloc
,WNOHANG
,NULL
)) != 0) {
1349 if (pid
== server
.bgsavechildpid
) {
1350 backgroundSaveDoneHandler(statloc
);
1352 backgroundRewriteDoneHandler(statloc
);
1356 /* If there is not a background saving in progress check if
1357 * we have to save now */
1358 time_t now
= time(NULL
);
1359 for (j
= 0; j
< server
.saveparamslen
; j
++) {
1360 struct saveparam
*sp
= server
.saveparams
+j
;
1362 if (server
.dirty
>= sp
->changes
&&
1363 now
-server
.lastsave
> sp
->seconds
) {
1364 redisLog(REDIS_NOTICE
,"%d changes in %d seconds. Saving...",
1365 sp
->changes
, sp
->seconds
);
1366 rdbSaveBackground(server
.dbfilename
);
1372 /* Try to expire a few timed out keys. The algorithm used is adaptive and
1373 * will use few CPU cycles if there are few expiring keys, otherwise
1374 * it will get more aggressive to avoid that too much memory is used by
1375 * keys that can be removed from the keyspace. */
1376 for (j
= 0; j
< server
.dbnum
; j
++) {
1378 redisDb
*db
= server
.db
+j
;
1380 /* Continue to expire if at the end of the cycle more than 25%
1381 * of the keys were expired. */
1383 long num
= dictSize(db
->expires
);
1384 time_t now
= time(NULL
);
1387 if (num
> REDIS_EXPIRELOOKUPS_PER_CRON
)
1388 num
= REDIS_EXPIRELOOKUPS_PER_CRON
;
1393 if ((de
= dictGetRandomKey(db
->expires
)) == NULL
) break;
1394 t
= (time_t) dictGetEntryVal(de
);
1396 deleteKey(db
,dictGetEntryKey(de
));
1398 server
.stat_expiredkeys
++;
1401 } while (expired
> REDIS_EXPIRELOOKUPS_PER_CRON
/4);
1404 /* Swap a few keys on disk if we are over the memory limit and VM
1405 * is enbled. Try to free objects from the free list first. */
1406 if (vmCanSwapOut()) {
1407 while (server
.vm_enabled
&& zmalloc_used_memory() >
1408 server
.vm_max_memory
)
1412 if (tryFreeOneObjectFromFreelist() == REDIS_OK
) continue;
1413 retval
= (server
.vm_max_threads
== 0) ?
1414 vmSwapOneObjectBlocking() :
1415 vmSwapOneObjectThreaded();
1416 if (retval
== REDIS_ERR
&& !(loops
% 300) &&
1417 zmalloc_used_memory() >
1418 (server
.vm_max_memory
+server
.vm_max_memory
/10))
1420 redisLog(REDIS_WARNING
,"WARNING: vm-max-memory limit exceeded by more than 10%% but unable to swap more objects out!");
1422 /* Note that when using threade I/O we free just one object,
1423 * because anyway when the I/O thread in charge to swap this
1424 * object out will finish, the handler of completed jobs
1425 * will try to swap more objects if we are still out of memory. */
1426 if (retval
== REDIS_ERR
|| server
.vm_max_threads
> 0) break;
1430 /* Check if we should connect to a MASTER */
1431 if (server
.replstate
== REDIS_REPL_CONNECT
&& !(loops
% 10)) {
1432 redisLog(REDIS_NOTICE
,"Connecting to MASTER...");
1433 if (syncWithMaster() == REDIS_OK
) {
1434 redisLog(REDIS_NOTICE
,"MASTER <-> SLAVE sync succeeded");
1440 /* This function gets called every time Redis is entering the
1441 * main loop of the event driven library, that is, before to sleep
1442 * for ready file descriptors. */
1443 static void beforeSleep(struct aeEventLoop
*eventLoop
) {
1444 REDIS_NOTUSED(eventLoop
);
1446 if (server
.vm_enabled
&& listLength(server
.io_ready_clients
)) {
1450 listRewind(server
.io_ready_clients
,&li
);
1451 while((ln
= listNext(&li
))) {
1452 redisClient
*c
= ln
->value
;
1453 struct redisCommand
*cmd
;
1455 /* Resume the client. */
1456 listDelNode(server
.io_ready_clients
,ln
);
1457 c
->flags
&= (~REDIS_IO_WAIT
);
1458 server
.vm_blocked_clients
--;
1459 aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
,
1460 readQueryFromClient
, c
);
1461 cmd
= lookupCommand(c
->argv
[0]->ptr
);
1462 assert(cmd
!= NULL
);
1465 /* There may be more data to process in the input buffer. */
1466 if (c
->querybuf
&& sdslen(c
->querybuf
) > 0)
1467 processInputBuffer(c
);
1472 static void createSharedObjects(void) {
1473 shared
.crlf
= createObject(REDIS_STRING
,sdsnew("\r\n"));
1474 shared
.ok
= createObject(REDIS_STRING
,sdsnew("+OK\r\n"));
1475 shared
.err
= createObject(REDIS_STRING
,sdsnew("-ERR\r\n"));
1476 shared
.emptybulk
= createObject(REDIS_STRING
,sdsnew("$0\r\n\r\n"));
1477 shared
.czero
= createObject(REDIS_STRING
,sdsnew(":0\r\n"));
1478 shared
.cone
= createObject(REDIS_STRING
,sdsnew(":1\r\n"));
1479 shared
.nullbulk
= createObject(REDIS_STRING
,sdsnew("$-1\r\n"));
1480 shared
.nullmultibulk
= createObject(REDIS_STRING
,sdsnew("*-1\r\n"));
1481 shared
.emptymultibulk
= createObject(REDIS_STRING
,sdsnew("*0\r\n"));
1482 shared
.pong
= createObject(REDIS_STRING
,sdsnew("+PONG\r\n"));
1483 shared
.queued
= createObject(REDIS_STRING
,sdsnew("+QUEUED\r\n"));
1484 shared
.wrongtypeerr
= createObject(REDIS_STRING
,sdsnew(
1485 "-ERR Operation against a key holding the wrong kind of value\r\n"));
1486 shared
.nokeyerr
= createObject(REDIS_STRING
,sdsnew(
1487 "-ERR no such key\r\n"));
1488 shared
.syntaxerr
= createObject(REDIS_STRING
,sdsnew(
1489 "-ERR syntax error\r\n"));
1490 shared
.sameobjecterr
= createObject(REDIS_STRING
,sdsnew(
1491 "-ERR source and destination objects are the same\r\n"));
1492 shared
.outofrangeerr
= createObject(REDIS_STRING
,sdsnew(
1493 "-ERR index out of range\r\n"));
1494 shared
.space
= createObject(REDIS_STRING
,sdsnew(" "));
1495 shared
.colon
= createObject(REDIS_STRING
,sdsnew(":"));
1496 shared
.plus
= createObject(REDIS_STRING
,sdsnew("+"));
1497 shared
.select0
= createStringObject("select 0\r\n",10);
1498 shared
.select1
= createStringObject("select 1\r\n",10);
1499 shared
.select2
= createStringObject("select 2\r\n",10);
1500 shared
.select3
= createStringObject("select 3\r\n",10);
1501 shared
.select4
= createStringObject("select 4\r\n",10);
1502 shared
.select5
= createStringObject("select 5\r\n",10);
1503 shared
.select6
= createStringObject("select 6\r\n",10);
1504 shared
.select7
= createStringObject("select 7\r\n",10);
1505 shared
.select8
= createStringObject("select 8\r\n",10);
1506 shared
.select9
= createStringObject("select 9\r\n",10);
1507 shared
.messagebulk
= createStringObject("$7\r\nmessage\r\n",13);
1508 shared
.subscribebulk
= createStringObject("$9\r\nsubscribe\r\n",15);
1509 shared
.unsubscribebulk
= createStringObject("$11\r\nunsubscribe\r\n",18);
1510 shared
.psubscribebulk
= createStringObject("$10\r\npsubscribe\r\n",17);
1511 shared
.punsubscribebulk
= createStringObject("$12\r\npunsubscribe\r\n",19);
1512 shared
.mbulk3
= createStringObject("*3\r\n",4);
1515 static void appendServerSaveParams(time_t seconds
, int changes
) {
1516 server
.saveparams
= zrealloc(server
.saveparams
,sizeof(struct saveparam
)*(server
.saveparamslen
+1));
1517 server
.saveparams
[server
.saveparamslen
].seconds
= seconds
;
1518 server
.saveparams
[server
.saveparamslen
].changes
= changes
;
1519 server
.saveparamslen
++;
1522 static void resetServerSaveParams() {
1523 zfree(server
.saveparams
);
1524 server
.saveparams
= NULL
;
1525 server
.saveparamslen
= 0;
1528 static void initServerConfig() {
1529 server
.dbnum
= REDIS_DEFAULT_DBNUM
;
1530 server
.port
= REDIS_SERVERPORT
;
1531 server
.verbosity
= REDIS_VERBOSE
;
1532 server
.maxidletime
= REDIS_MAXIDLETIME
;
1533 server
.saveparams
= NULL
;
1534 server
.logfile
= NULL
; /* NULL = log on standard output */
1535 server
.bindaddr
= NULL
;
1536 server
.glueoutputbuf
= 1;
1537 server
.daemonize
= 0;
1538 server
.appendonly
= 0;
1539 server
.appendfsync
= APPENDFSYNC_ALWAYS
;
1540 server
.lastfsync
= time(NULL
);
1541 server
.appendfd
= -1;
1542 server
.appendseldb
= -1; /* Make sure the first time will not match */
1543 server
.pidfile
= zstrdup("/var/run/redis.pid");
1544 server
.dbfilename
= zstrdup("dump.rdb");
1545 server
.appendfilename
= zstrdup("appendonly.aof");
1546 server
.requirepass
= NULL
;
1547 server
.shareobjects
= 0;
1548 server
.rdbcompression
= 1;
1549 server
.sharingpoolsize
= 1024;
1550 server
.maxclients
= 0;
1551 server
.blpop_blocked_clients
= 0;
1552 server
.maxmemory
= 0;
1553 server
.vm_enabled
= 0;
1554 server
.vm_swap_file
= zstrdup("/tmp/redis-%p.vm");
1555 server
.vm_page_size
= 256; /* 256 bytes per page */
1556 server
.vm_pages
= 1024*1024*100; /* 104 millions of pages */
1557 server
.vm_max_memory
= 1024LL*1024*1024*1; /* 1 GB of RAM */
1558 server
.vm_max_threads
= 4;
1559 server
.vm_blocked_clients
= 0;
1560 server
.hash_max_zipmap_entries
= REDIS_HASH_MAX_ZIPMAP_ENTRIES
;
1561 server
.hash_max_zipmap_value
= REDIS_HASH_MAX_ZIPMAP_VALUE
;
1563 resetServerSaveParams();
1565 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
1566 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
1567 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1568 /* Replication related */
1570 server
.masterauth
= NULL
;
1571 server
.masterhost
= NULL
;
1572 server
.masterport
= 6379;
1573 server
.master
= NULL
;
1574 server
.replstate
= REDIS_REPL_NONE
;
1576 /* Double constants initialization */
1578 R_PosInf
= 1.0/R_Zero
;
1579 R_NegInf
= -1.0/R_Zero
;
1580 R_Nan
= R_Zero
/R_Zero
;
1583 static void initServer() {
1586 signal(SIGHUP
, SIG_IGN
);
1587 signal(SIGPIPE
, SIG_IGN
);
1588 setupSigSegvAction();
1590 server
.devnull
= fopen("/dev/null","w");
1591 if (server
.devnull
== NULL
) {
1592 redisLog(REDIS_WARNING
, "Can't open /dev/null: %s", server
.neterr
);
1595 server
.clients
= listCreate();
1596 server
.slaves
= listCreate();
1597 server
.monitors
= listCreate();
1598 server
.objfreelist
= listCreate();
1599 createSharedObjects();
1600 server
.el
= aeCreateEventLoop();
1601 server
.db
= zmalloc(sizeof(redisDb
)*server
.dbnum
);
1602 server
.sharingpool
= dictCreate(&setDictType
,NULL
);
1603 server
.fd
= anetTcpServer(server
.neterr
, server
.port
, server
.bindaddr
);
1604 if (server
.fd
== -1) {
1605 redisLog(REDIS_WARNING
, "Opening TCP port: %s", server
.neterr
);
1608 for (j
= 0; j
< server
.dbnum
; j
++) {
1609 server
.db
[j
].dict
= dictCreate(&dbDictType
,NULL
);
1610 server
.db
[j
].expires
= dictCreate(&keyptrDictType
,NULL
);
1611 server
.db
[j
].blockingkeys
= dictCreate(&keylistDictType
,NULL
);
1612 if (server
.vm_enabled
)
1613 server
.db
[j
].io_keys
= dictCreate(&keylistDictType
,NULL
);
1614 server
.db
[j
].id
= j
;
1616 server
.pubsub_channels
= dictCreate(&keylistDictType
,NULL
);
1617 server
.pubsub_patterns
= listCreate();
1618 listSetFreeMethod(server
.pubsub_patterns
,freePubsubPattern
);
1619 listSetMatchMethod(server
.pubsub_patterns
,listMatchPubsubPattern
);
1620 server
.cronloops
= 0;
1621 server
.bgsavechildpid
= -1;
1622 server
.bgrewritechildpid
= -1;
1623 server
.bgrewritebuf
= sdsempty();
1624 server
.lastsave
= time(NULL
);
1626 server
.stat_numcommands
= 0;
1627 server
.stat_numconnections
= 0;
1628 server
.stat_expiredkeys
= 0;
1629 server
.stat_starttime
= time(NULL
);
1630 server
.unixtime
= time(NULL
);
1631 aeCreateTimeEvent(server
.el
, 1, serverCron
, NULL
, NULL
);
1632 if (aeCreateFileEvent(server
.el
, server
.fd
, AE_READABLE
,
1633 acceptHandler
, NULL
) == AE_ERR
) oom("creating file event");
1635 if (server
.appendonly
) {
1636 server
.appendfd
= open(server
.appendfilename
,O_WRONLY
|O_APPEND
|O_CREAT
,0644);
1637 if (server
.appendfd
== -1) {
1638 redisLog(REDIS_WARNING
, "Can't open the append-only file: %s",
1644 if (server
.vm_enabled
) vmInit();
1647 /* Empty the whole database */
1648 static long long emptyDb() {
1650 long long removed
= 0;
1652 for (j
= 0; j
< server
.dbnum
; j
++) {
1653 removed
+= dictSize(server
.db
[j
].dict
);
1654 dictEmpty(server
.db
[j
].dict
);
1655 dictEmpty(server
.db
[j
].expires
);
1660 static int yesnotoi(char *s
) {
1661 if (!strcasecmp(s
,"yes")) return 1;
1662 else if (!strcasecmp(s
,"no")) return 0;
1666 /* I agree, this is a very rudimental way to load a configuration...
1667 will improve later if the config gets more complex */
1668 static void loadServerConfig(char *filename
) {
1670 char buf
[REDIS_CONFIGLINE_MAX
+1], *err
= NULL
;
1673 char *errormsg
= "Fatal error, can't open config file '%s'";
1674 char *errorbuf
= zmalloc(sizeof(char)*(strlen(errormsg
)+strlen(filename
)));
1675 sprintf(errorbuf
, errormsg
, filename
);
1677 if (filename
[0] == '-' && filename
[1] == '\0')
1680 if ((fp
= fopen(filename
,"r")) == NULL
) {
1681 redisLog(REDIS_WARNING
, errorbuf
);
1686 while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) {
1692 line
= sdstrim(line
," \t\r\n");
1694 /* Skip comments and blank lines*/
1695 if (line
[0] == '#' || line
[0] == '\0') {
1700 /* Split into arguments */
1701 argv
= sdssplitlen(line
,sdslen(line
)," ",1,&argc
);
1702 sdstolower(argv
[0]);
1704 /* Execute config directives */
1705 if (!strcasecmp(argv
[0],"timeout") && argc
== 2) {
1706 server
.maxidletime
= atoi(argv
[1]);
1707 if (server
.maxidletime
< 0) {
1708 err
= "Invalid timeout value"; goto loaderr
;
1710 } else if (!strcasecmp(argv
[0],"port") && argc
== 2) {
1711 server
.port
= atoi(argv
[1]);
1712 if (server
.port
< 1 || server
.port
> 65535) {
1713 err
= "Invalid port"; goto loaderr
;
1715 } else if (!strcasecmp(argv
[0],"bind") && argc
== 2) {
1716 server
.bindaddr
= zstrdup(argv
[1]);
1717 } else if (!strcasecmp(argv
[0],"save") && argc
== 3) {
1718 int seconds
= atoi(argv
[1]);
1719 int changes
= atoi(argv
[2]);
1720 if (seconds
< 1 || changes
< 0) {
1721 err
= "Invalid save parameters"; goto loaderr
;
1723 appendServerSaveParams(seconds
,changes
);
1724 } else if (!strcasecmp(argv
[0],"dir") && argc
== 2) {
1725 if (chdir(argv
[1]) == -1) {
1726 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s",
1727 argv
[1], strerror(errno
));
1730 } else if (!strcasecmp(argv
[0],"loglevel") && argc
== 2) {
1731 if (!strcasecmp(argv
[1],"debug")) server
.verbosity
= REDIS_DEBUG
;
1732 else if (!strcasecmp(argv
[1],"verbose")) server
.verbosity
= REDIS_VERBOSE
;
1733 else if (!strcasecmp(argv
[1],"notice")) server
.verbosity
= REDIS_NOTICE
;
1734 else if (!strcasecmp(argv
[1],"warning")) server
.verbosity
= REDIS_WARNING
;
1736 err
= "Invalid log level. Must be one of debug, notice, warning";
1739 } else if (!strcasecmp(argv
[0],"logfile") && argc
== 2) {
1742 server
.logfile
= zstrdup(argv
[1]);
1743 if (!strcasecmp(server
.logfile
,"stdout")) {
1744 zfree(server
.logfile
);
1745 server
.logfile
= NULL
;
1747 if (server
.logfile
) {
1748 /* Test if we are able to open the file. The server will not
1749 * be able to abort just for this problem later... */
1750 logfp
= fopen(server
.logfile
,"a");
1751 if (logfp
== NULL
) {
1752 err
= sdscatprintf(sdsempty(),
1753 "Can't open the log file: %s", strerror(errno
));
1758 } else if (!strcasecmp(argv
[0],"databases") && argc
== 2) {
1759 server
.dbnum
= atoi(argv
[1]);
1760 if (server
.dbnum
< 1) {
1761 err
= "Invalid number of databases"; goto loaderr
;
1763 } else if (!strcasecmp(argv
[0],"include") && argc
== 2) {
1764 loadServerConfig(argv
[1]);
1765 } else if (!strcasecmp(argv
[0],"maxclients") && argc
== 2) {
1766 server
.maxclients
= atoi(argv
[1]);
1767 } else if (!strcasecmp(argv
[0],"maxmemory") && argc
== 2) {
1768 server
.maxmemory
= strtoll(argv
[1], NULL
, 10);
1769 } else if (!strcasecmp(argv
[0],"slaveof") && argc
== 3) {
1770 server
.masterhost
= sdsnew(argv
[1]);
1771 server
.masterport
= atoi(argv
[2]);
1772 server
.replstate
= REDIS_REPL_CONNECT
;
1773 } else if (!strcasecmp(argv
[0],"masterauth") && argc
== 2) {
1774 server
.masterauth
= zstrdup(argv
[1]);
1775 } else if (!strcasecmp(argv
[0],"glueoutputbuf") && argc
== 2) {
1776 if ((server
.glueoutputbuf
= yesnotoi(argv
[1])) == -1) {
1777 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1779 } else if (!strcasecmp(argv
[0],"shareobjects") && argc
== 2) {
1780 if ((server
.shareobjects
= yesnotoi(argv
[1])) == -1) {
1781 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1783 } else if (!strcasecmp(argv
[0],"rdbcompression") && argc
== 2) {
1784 if ((server
.rdbcompression
= yesnotoi(argv
[1])) == -1) {
1785 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1787 } else if (!strcasecmp(argv
[0],"shareobjectspoolsize") && argc
== 2) {
1788 server
.sharingpoolsize
= atoi(argv
[1]);
1789 if (server
.sharingpoolsize
< 1) {
1790 err
= "invalid object sharing pool size"; goto loaderr
;
1792 } else if (!strcasecmp(argv
[0],"daemonize") && argc
== 2) {
1793 if ((server
.daemonize
= yesnotoi(argv
[1])) == -1) {
1794 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1796 } else if (!strcasecmp(argv
[0],"appendonly") && argc
== 2) {
1797 if ((server
.appendonly
= yesnotoi(argv
[1])) == -1) {
1798 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1800 } else if (!strcasecmp(argv
[0],"appendfsync") && argc
== 2) {
1801 if (!strcasecmp(argv
[1],"no")) {
1802 server
.appendfsync
= APPENDFSYNC_NO
;
1803 } else if (!strcasecmp(argv
[1],"always")) {
1804 server
.appendfsync
= APPENDFSYNC_ALWAYS
;
1805 } else if (!strcasecmp(argv
[1],"everysec")) {
1806 server
.appendfsync
= APPENDFSYNC_EVERYSEC
;
1808 err
= "argument must be 'no', 'always' or 'everysec'";
1811 } else if (!strcasecmp(argv
[0],"requirepass") && argc
== 2) {
1812 server
.requirepass
= zstrdup(argv
[1]);
1813 } else if (!strcasecmp(argv
[0],"pidfile") && argc
== 2) {
1814 zfree(server
.pidfile
);
1815 server
.pidfile
= zstrdup(argv
[1]);
1816 } else if (!strcasecmp(argv
[0],"dbfilename") && argc
== 2) {
1817 zfree(server
.dbfilename
);
1818 server
.dbfilename
= zstrdup(argv
[1]);
1819 } else if (!strcasecmp(argv
[0],"vm-enabled") && argc
== 2) {
1820 if ((server
.vm_enabled
= yesnotoi(argv
[1])) == -1) {
1821 err
= "argument must be 'yes' or 'no'"; goto loaderr
;
1823 } else if (!strcasecmp(argv
[0],"vm-swap-file") && argc
== 2) {
1824 zfree(server
.vm_swap_file
);
1825 server
.vm_swap_file
= zstrdup(argv
[1]);
1826 } else if (!strcasecmp(argv
[0],"vm-max-memory") && argc
== 2) {
1827 server
.vm_max_memory
= strtoll(argv
[1], NULL
, 10);
1828 } else if (!strcasecmp(argv
[0],"vm-page-size") && argc
== 2) {
1829 server
.vm_page_size
= strtoll(argv
[1], NULL
, 10);
1830 } else if (!strcasecmp(argv
[0],"vm-pages") && argc
== 2) {
1831 server
.vm_pages
= strtoll(argv
[1], NULL
, 10);
1832 } else if (!strcasecmp(argv
[0],"vm-max-threads") && argc
== 2) {
1833 server
.vm_max_threads
= strtoll(argv
[1], NULL
, 10);
1834 } else if (!strcasecmp(argv
[0],"hash-max-zipmap-entries") && argc
== 2){
1835 server
.hash_max_zipmap_entries
= strtol(argv
[1], NULL
, 10);
1836 } else if (!strcasecmp(argv
[0],"hash-max-zipmap-value") && argc
== 2){
1837 server
.hash_max_zipmap_value
= strtol(argv
[1], NULL
, 10);
1838 } else if (!strcasecmp(argv
[0],"vm-max-threads") && argc
== 2) {
1839 server
.vm_max_threads
= strtoll(argv
[1], NULL
, 10);
1841 err
= "Bad directive or wrong number of arguments"; goto loaderr
;
1843 for (j
= 0; j
< argc
; j
++)
1848 if (fp
!= stdin
) fclose(fp
);
1852 fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n");
1853 fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
);
1854 fprintf(stderr
, ">>> '%s'\n", line
);
1855 fprintf(stderr
, "%s\n", err
);
1859 static void freeClientArgv(redisClient
*c
) {
1862 for (j
= 0; j
< c
->argc
; j
++)
1863 decrRefCount(c
->argv
[j
]);
1864 for (j
= 0; j
< c
->mbargc
; j
++)
1865 decrRefCount(c
->mbargv
[j
]);
1870 static void freeClient(redisClient
*c
) {
1873 /* Note that if the client we are freeing is blocked into a blocking
1874 * call, we have to set querybuf to NULL *before* to call
1875 * unblockClientWaitingData() to avoid processInputBuffer() will get
1876 * called. Also it is important to remove the file events after
1877 * this, because this call adds the READABLE event. */
1878 sdsfree(c
->querybuf
);
1880 if (c
->flags
& REDIS_BLOCKED
)
1881 unblockClientWaitingData(c
);
1883 /* Unsubscribe from all the pubsub channels */
1884 pubsubUnsubscribeAllChannels(c
,0);
1885 pubsubUnsubscribeAllPatterns(c
,0);
1886 dictRelease(c
->pubsub_channels
);
1887 listRelease(c
->pubsub_patterns
);
1888 /* Obvious cleanup */
1889 aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
);
1890 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
1891 listRelease(c
->reply
);
1894 /* Remove from the list of clients */
1895 ln
= listSearchKey(server
.clients
,c
);
1896 redisAssert(ln
!= NULL
);
1897 listDelNode(server
.clients
,ln
);
1898 /* Remove from the list of clients waiting for swapped keys */
1899 if (c
->flags
& REDIS_IO_WAIT
&& listLength(c
->io_keys
) == 0) {
1900 ln
= listSearchKey(server
.io_ready_clients
,c
);
1902 listDelNode(server
.io_ready_clients
,ln
);
1903 server
.vm_blocked_clients
--;
1906 while (server
.vm_enabled
&& listLength(c
->io_keys
)) {
1907 ln
= listFirst(c
->io_keys
);
1908 dontWaitForSwappedKey(c
,ln
->value
);
1910 listRelease(c
->io_keys
);
1911 /* Master/slave cleanup */
1912 if (c
->flags
& REDIS_SLAVE
) {
1913 if (c
->replstate
== REDIS_REPL_SEND_BULK
&& c
->repldbfd
!= -1)
1915 list
*l
= (c
->flags
& REDIS_MONITOR
) ? server
.monitors
: server
.slaves
;
1916 ln
= listSearchKey(l
,c
);
1917 redisAssert(ln
!= NULL
);
1920 if (c
->flags
& REDIS_MASTER
) {
1921 server
.master
= NULL
;
1922 server
.replstate
= REDIS_REPL_CONNECT
;
1924 /* Release memory */
1927 freeClientMultiState(c
);
1931 #define GLUEREPLY_UP_TO (1024)
1932 static void glueReplyBuffersIfNeeded(redisClient
*c
) {
1934 char buf
[GLUEREPLY_UP_TO
];
1939 listRewind(c
->reply
,&li
);
1940 while((ln
= listNext(&li
))) {
1944 objlen
= sdslen(o
->ptr
);
1945 if (copylen
+ objlen
<= GLUEREPLY_UP_TO
) {
1946 memcpy(buf
+copylen
,o
->ptr
,objlen
);
1948 listDelNode(c
->reply
,ln
);
1950 if (copylen
== 0) return;
1954 /* Now the output buffer is empty, add the new single element */
1955 o
= createObject(REDIS_STRING
,sdsnewlen(buf
,copylen
));
1956 listAddNodeHead(c
->reply
,o
);
1959 static void sendReplyToClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
1960 redisClient
*c
= privdata
;
1961 int nwritten
= 0, totwritten
= 0, objlen
;
1964 REDIS_NOTUSED(mask
);
1966 /* Use writev() if we have enough buffers to send */
1967 if (!server
.glueoutputbuf
&&
1968 listLength(c
->reply
) > REDIS_WRITEV_THRESHOLD
&&
1969 !(c
->flags
& REDIS_MASTER
))
1971 sendReplyToClientWritev(el
, fd
, privdata
, mask
);
1975 while(listLength(c
->reply
)) {
1976 if (server
.glueoutputbuf
&& listLength(c
->reply
) > 1)
1977 glueReplyBuffersIfNeeded(c
);
1979 o
= listNodeValue(listFirst(c
->reply
));
1980 objlen
= sdslen(o
->ptr
);
1983 listDelNode(c
->reply
,listFirst(c
->reply
));
1987 if (c
->flags
& REDIS_MASTER
) {
1988 /* Don't reply to a master */
1989 nwritten
= objlen
- c
->sentlen
;
1991 nwritten
= write(fd
, ((char*)o
->ptr
)+c
->sentlen
, objlen
- c
->sentlen
);
1992 if (nwritten
<= 0) break;
1994 c
->sentlen
+= nwritten
;
1995 totwritten
+= nwritten
;
1996 /* If we fully sent the object on head go to the next one */
1997 if (c
->sentlen
== objlen
) {
1998 listDelNode(c
->reply
,listFirst(c
->reply
));
2001 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
2002 * bytes, in a single threaded server it's a good idea to serve
2003 * other clients as well, even if a very large request comes from
2004 * super fast link that is always able to accept data (in real world
2005 * scenario think about 'KEYS *' against the loopback interfae) */
2006 if (totwritten
> REDIS_MAX_WRITE_PER_EVENT
) break;
2008 if (nwritten
== -1) {
2009 if (errno
== EAGAIN
) {
2012 redisLog(REDIS_VERBOSE
,
2013 "Error writing to client: %s", strerror(errno
));
2018 if (totwritten
> 0) c
->lastinteraction
= time(NULL
);
2019 if (listLength(c
->reply
) == 0) {
2021 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
2025 static void sendReplyToClientWritev(aeEventLoop
*el
, int fd
, void *privdata
, int mask
)
2027 redisClient
*c
= privdata
;
2028 int nwritten
= 0, totwritten
= 0, objlen
, willwrite
;
2030 struct iovec iov
[REDIS_WRITEV_IOVEC_COUNT
];
2031 int offset
, ion
= 0;
2033 REDIS_NOTUSED(mask
);
2036 while (listLength(c
->reply
)) {
2037 offset
= c
->sentlen
;
2041 /* fill-in the iov[] array */
2042 for(node
= listFirst(c
->reply
); node
; node
= listNextNode(node
)) {
2043 o
= listNodeValue(node
);
2044 objlen
= sdslen(o
->ptr
);
2046 if (totwritten
+ objlen
- offset
> REDIS_MAX_WRITE_PER_EVENT
)
2049 if(ion
== REDIS_WRITEV_IOVEC_COUNT
)
2050 break; /* no more iovecs */
2052 iov
[ion
].iov_base
= ((char*)o
->ptr
) + offset
;
2053 iov
[ion
].iov_len
= objlen
- offset
;
2054 willwrite
+= objlen
- offset
;
2055 offset
= 0; /* just for the first item */
2062 /* write all collected blocks at once */
2063 if((nwritten
= writev(fd
, iov
, ion
)) < 0) {
2064 if (errno
!= EAGAIN
) {
2065 redisLog(REDIS_VERBOSE
,
2066 "Error writing to client: %s", strerror(errno
));
2073 totwritten
+= nwritten
;
2074 offset
= c
->sentlen
;
2076 /* remove written robjs from c->reply */
2077 while (nwritten
&& listLength(c
->reply
)) {
2078 o
= listNodeValue(listFirst(c
->reply
));
2079 objlen
= sdslen(o
->ptr
);
2081 if(nwritten
>= objlen
- offset
) {
2082 listDelNode(c
->reply
, listFirst(c
->reply
));
2083 nwritten
-= objlen
- offset
;
2087 c
->sentlen
+= nwritten
;
2095 c
->lastinteraction
= time(NULL
);
2097 if (listLength(c
->reply
) == 0) {
2099 aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
);
2103 static struct redisCommand
*lookupCommand(char *name
) {
2105 while(cmdTable
[j
].name
!= NULL
) {
2106 if (!strcasecmp(name
,cmdTable
[j
].name
)) return &cmdTable
[j
];
2112 /* resetClient prepare the client to process the next command */
2113 static void resetClient(redisClient
*c
) {
2119 /* Call() is the core of Redis execution of a command */
2120 static void call(redisClient
*c
, struct redisCommand
*cmd
) {
2123 dirty
= server
.dirty
;
2125 dirty
= server
.dirty
-dirty
;
2127 if (server
.appendonly
&& dirty
)
2128 feedAppendOnlyFile(cmd
,c
->db
->id
,c
->argv
,c
->argc
);
2129 if ((dirty
|| cmd
->flags
& REDIS_CMD_FORCE_REPLICATION
) &&
2130 listLength(server
.slaves
))
2131 replicationFeedSlaves(server
.slaves
,c
->db
->id
,c
->argv
,c
->argc
);
2132 if (listLength(server
.monitors
))
2133 replicationFeedSlaves(server
.monitors
,c
->db
->id
,c
->argv
,c
->argc
);
2134 server
.stat_numcommands
++;
2137 /* If this function gets called we already read a whole
2138 * command, argments are in the client argv/argc fields.
2139 * processCommand() execute the command or prepare the
2140 * server for a bulk read from the client.
2142 * If 1 is returned the client is still alive and valid and
2143 * and other operations can be performed by the caller. Otherwise
2144 * if 0 is returned the client was destroied (i.e. after QUIT). */
2145 static int processCommand(redisClient
*c
) {
2146 struct redisCommand
*cmd
;
2148 /* Free some memory if needed (maxmemory setting) */
2149 if (server
.maxmemory
) freeMemoryIfNeeded();
2151 /* Handle the multi bulk command type. This is an alternative protocol
2152 * supported by Redis in order to receive commands that are composed of
2153 * multiple binary-safe "bulk" arguments. The latency of processing is
2154 * a bit higher but this allows things like multi-sets, so if this
2155 * protocol is used only for MSET and similar commands this is a big win. */
2156 if (c
->multibulk
== 0 && c
->argc
== 1 && ((char*)(c
->argv
[0]->ptr
))[0] == '*') {
2157 c
->multibulk
= atoi(((char*)c
->argv
[0]->ptr
)+1);
2158 if (c
->multibulk
<= 0) {
2162 decrRefCount(c
->argv
[c
->argc
-1]);
2166 } else if (c
->multibulk
) {
2167 if (c
->bulklen
== -1) {
2168 if (((char*)c
->argv
[0]->ptr
)[0] != '$') {
2169 addReplySds(c
,sdsnew("-ERR multi bulk protocol error\r\n"));
2173 int bulklen
= atoi(((char*)c
->argv
[0]->ptr
)+1);
2174 decrRefCount(c
->argv
[0]);
2175 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
2177 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
2182 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
2186 c
->mbargv
= zrealloc(c
->mbargv
,(sizeof(robj
*))*(c
->mbargc
+1));
2187 c
->mbargv
[c
->mbargc
] = c
->argv
[0];
2191 if (c
->multibulk
== 0) {
2195 /* Here we need to swap the multi-bulk argc/argv with the
2196 * normal argc/argv of the client structure. */
2198 c
->argv
= c
->mbargv
;
2199 c
->mbargv
= auxargv
;
2202 c
->argc
= c
->mbargc
;
2203 c
->mbargc
= auxargc
;
2205 /* We need to set bulklen to something different than -1
2206 * in order for the code below to process the command without
2207 * to try to read the last argument of a bulk command as
2208 * a special argument. */
2210 /* continue below and process the command */
2217 /* -- end of multi bulk commands processing -- */
2219 /* The QUIT command is handled as a special case. Normal command
2220 * procs are unable to close the client connection safely */
2221 if (!strcasecmp(c
->argv
[0]->ptr
,"quit")) {
2226 /* Now lookup the command and check ASAP about trivial error conditions
2227 * such wrong arity, bad command name and so forth. */
2228 cmd
= lookupCommand(c
->argv
[0]->ptr
);
2231 sdscatprintf(sdsempty(), "-ERR unknown command '%s'\r\n",
2232 (char*)c
->argv
[0]->ptr
));
2235 } else if ((cmd
->arity
> 0 && cmd
->arity
!= c
->argc
) ||
2236 (c
->argc
< -cmd
->arity
)) {
2238 sdscatprintf(sdsempty(),
2239 "-ERR wrong number of arguments for '%s' command\r\n",
2243 } else if (cmd
->flags
& REDIS_CMD_BULK
&& c
->bulklen
== -1) {
2244 /* This is a bulk command, we have to read the last argument yet. */
2245 int bulklen
= atoi(c
->argv
[c
->argc
-1]->ptr
);
2247 decrRefCount(c
->argv
[c
->argc
-1]);
2248 if (bulklen
< 0 || bulklen
> 1024*1024*1024) {
2250 addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n"));
2255 c
->bulklen
= bulklen
+2; /* add two bytes for CR+LF */
2256 /* It is possible that the bulk read is already in the
2257 * buffer. Check this condition and handle it accordingly.
2258 * This is just a fast path, alternative to call processInputBuffer().
2259 * It's a good idea since the code is small and this condition
2260 * happens most of the times. */
2261 if ((signed)sdslen(c
->querybuf
) >= c
->bulklen
) {
2262 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
2264 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
2266 /* Otherwise return... there is to read the last argument
2267 * from the socket. */
2271 /* Let's try to share objects on the command arguments vector */
2272 if (server
.shareobjects
) {
2274 for(j
= 1; j
< c
->argc
; j
++)
2275 c
->argv
[j
] = tryObjectSharing(c
->argv
[j
]);
2277 /* Let's try to encode the bulk object to save space. */
2278 if (cmd
->flags
& REDIS_CMD_BULK
)
2279 tryObjectEncoding(c
->argv
[c
->argc
-1]);
2281 /* Check if the user is authenticated */
2282 if (server
.requirepass
&& !c
->authenticated
&& cmd
->proc
!= authCommand
) {
2283 addReplySds(c
,sdsnew("-ERR operation not permitted\r\n"));
2288 /* Handle the maxmemory directive */
2289 if (server
.maxmemory
&& (cmd
->flags
& REDIS_CMD_DENYOOM
) &&
2290 zmalloc_used_memory() > server
.maxmemory
)
2292 addReplySds(c
,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
2297 /* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
2298 if (dictSize(c
->pubsub_channels
) > 0 &&
2299 cmd
->proc
!= subscribeCommand
&& cmd
->proc
!= unsubscribeCommand
&&
2300 cmd
->proc
!= psubscribeCommand
&& cmd
->proc
!= punsubscribeCommand
) {
2301 addReplySds(c
,sdsnew("-ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context\r\n"));
2306 /* Exec the command */
2307 if (c
->flags
& REDIS_MULTI
&& cmd
->proc
!= execCommand
&& cmd
->proc
!= discardCommand
) {
2308 queueMultiCommand(c
,cmd
);
2309 addReply(c
,shared
.queued
);
2311 if (server
.vm_enabled
&& server
.vm_max_threads
> 0 &&
2312 blockClientOnSwappedKeys(cmd
,c
)) return 1;
2316 /* Prepare the client for the next command */
2321 static void replicationFeedSlaves(list
*slaves
, int dictid
, robj
**argv
, int argc
) {
2326 /* We need 1+(ARGS*3) objects since commands are using the new protocol
2327 * and we one 1 object for the first "*<count>\r\n" multibulk count, then
2328 * for every additional object we have "$<count>\r\n" + object + "\r\n". */
2329 robj
*static_outv
[REDIS_STATIC_ARGS
*3+1];
2332 if (argc
<= REDIS_STATIC_ARGS
) {
2335 outv
= zmalloc(sizeof(robj
*)*(argc
*3+1));
2338 lenobj
= createObject(REDIS_STRING
,
2339 sdscatprintf(sdsempty(), "*%d\r\n", argc
));
2340 lenobj
->refcount
= 0;
2341 outv
[outc
++] = lenobj
;
2342 for (j
= 0; j
< argc
; j
++) {
2343 lenobj
= createObject(REDIS_STRING
,
2344 sdscatprintf(sdsempty(),"$%lu\r\n",
2345 (unsigned long) stringObjectLen(argv
[j
])));
2346 lenobj
->refcount
= 0;
2347 outv
[outc
++] = lenobj
;
2348 outv
[outc
++] = argv
[j
];
2349 outv
[outc
++] = shared
.crlf
;
2352 /* Increment all the refcounts at start and decrement at end in order to
2353 * be sure to free objects if there is no slave in a replication state
2354 * able to be feed with commands */
2355 for (j
= 0; j
< outc
; j
++) incrRefCount(outv
[j
]);
2356 listRewind(slaves
,&li
);
2357 while((ln
= listNext(&li
))) {
2358 redisClient
*slave
= ln
->value
;
2360 /* Don't feed slaves that are still waiting for BGSAVE to start */
2361 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) continue;
2363 /* Feed all the other slaves, MONITORs and so on */
2364 if (slave
->slaveseldb
!= dictid
) {
2368 case 0: selectcmd
= shared
.select0
; break;
2369 case 1: selectcmd
= shared
.select1
; break;
2370 case 2: selectcmd
= shared
.select2
; break;
2371 case 3: selectcmd
= shared
.select3
; break;
2372 case 4: selectcmd
= shared
.select4
; break;
2373 case 5: selectcmd
= shared
.select5
; break;
2374 case 6: selectcmd
= shared
.select6
; break;
2375 case 7: selectcmd
= shared
.select7
; break;
2376 case 8: selectcmd
= shared
.select8
; break;
2377 case 9: selectcmd
= shared
.select9
; break;
2379 selectcmd
= createObject(REDIS_STRING
,
2380 sdscatprintf(sdsempty(),"select %d\r\n",dictid
));
2381 selectcmd
->refcount
= 0;
2384 addReply(slave
,selectcmd
);
2385 slave
->slaveseldb
= dictid
;
2387 for (j
= 0; j
< outc
; j
++) addReply(slave
,outv
[j
]);
2389 for (j
= 0; j
< outc
; j
++) decrRefCount(outv
[j
]);
2390 if (outv
!= static_outv
) zfree(outv
);
2393 static void processInputBuffer(redisClient
*c
) {
2395 /* Before to process the input buffer, make sure the client is not
2396 * waitig for a blocking operation such as BLPOP. Note that the first
2397 * iteration the client is never blocked, otherwise the processInputBuffer
2398 * would not be called at all, but after the execution of the first commands
2399 * in the input buffer the client may be blocked, and the "goto again"
2400 * will try to reiterate. The following line will make it return asap. */
2401 if (c
->flags
& REDIS_BLOCKED
|| c
->flags
& REDIS_IO_WAIT
) return;
2402 if (c
->bulklen
== -1) {
2403 /* Read the first line of the query */
2404 char *p
= strchr(c
->querybuf
,'\n');
2411 query
= c
->querybuf
;
2412 c
->querybuf
= sdsempty();
2413 querylen
= 1+(p
-(query
));
2414 if (sdslen(query
) > querylen
) {
2415 /* leave data after the first line of the query in the buffer */
2416 c
->querybuf
= sdscatlen(c
->querybuf
,query
+querylen
,sdslen(query
)-querylen
);
2418 *p
= '\0'; /* remove "\n" */
2419 if (*(p
-1) == '\r') *(p
-1) = '\0'; /* and "\r" if any */
2420 sdsupdatelen(query
);
2422 /* Now we can split the query in arguments */
2423 argv
= sdssplitlen(query
,sdslen(query
)," ",1,&argc
);
2426 if (c
->argv
) zfree(c
->argv
);
2427 c
->argv
= zmalloc(sizeof(robj
*)*argc
);
2429 for (j
= 0; j
< argc
; j
++) {
2430 if (sdslen(argv
[j
])) {
2431 c
->argv
[c
->argc
] = createObject(REDIS_STRING
,argv
[j
]);
2439 /* Execute the command. If the client is still valid
2440 * after processCommand() return and there is something
2441 * on the query buffer try to process the next command. */
2442 if (processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
2444 /* Nothing to process, argc == 0. Just process the query
2445 * buffer if it's not empty or return to the caller */
2446 if (sdslen(c
->querybuf
)) goto again
;
2449 } else if (sdslen(c
->querybuf
) >= REDIS_REQUEST_MAX_SIZE
) {
2450 redisLog(REDIS_VERBOSE
, "Client protocol error");
2455 /* Bulk read handling. Note that if we are at this point
2456 the client already sent a command terminated with a newline,
2457 we are reading the bulk data that is actually the last
2458 argument of the command. */
2459 int qbl
= sdslen(c
->querybuf
);
2461 if (c
->bulklen
<= qbl
) {
2462 /* Copy everything but the final CRLF as final argument */
2463 c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2);
2465 c
->querybuf
= sdsrange(c
->querybuf
,c
->bulklen
,-1);
2466 /* Process the command. If the client is still valid after
2467 * the processing and there is more data in the buffer
2468 * try to parse it. */
2469 if (processCommand(c
) && sdslen(c
->querybuf
)) goto again
;
2475 static void readQueryFromClient(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
2476 redisClient
*c
= (redisClient
*) privdata
;
2477 char buf
[REDIS_IOBUF_LEN
];
2480 REDIS_NOTUSED(mask
);
2482 nread
= read(fd
, buf
, REDIS_IOBUF_LEN
);
2484 if (errno
== EAGAIN
) {
2487 redisLog(REDIS_VERBOSE
, "Reading from client: %s",strerror(errno
));
2491 } else if (nread
== 0) {
2492 redisLog(REDIS_VERBOSE
, "Client closed connection");
2497 c
->querybuf
= sdscatlen(c
->querybuf
, buf
, nread
);
2498 c
->lastinteraction
= time(NULL
);
2502 processInputBuffer(c
);
2505 static int selectDb(redisClient
*c
, int id
) {
2506 if (id
< 0 || id
>= server
.dbnum
)
2508 c
->db
= &server
.db
[id
];
2512 static void *dupClientReplyValue(void *o
) {
2513 incrRefCount((robj
*)o
);
2517 static int listMatchObjects(void *a
, void *b
) {
2518 return compareStringObjects(a
,b
) == 0;
2521 static redisClient
*createClient(int fd
) {
2522 redisClient
*c
= zmalloc(sizeof(*c
));
2524 anetNonBlock(NULL
,fd
);
2525 anetTcpNoDelay(NULL
,fd
);
2526 if (!c
) return NULL
;
2529 c
->querybuf
= sdsempty();
2538 c
->lastinteraction
= time(NULL
);
2539 c
->authenticated
= 0;
2540 c
->replstate
= REDIS_REPL_NONE
;
2541 c
->reply
= listCreate();
2542 listSetFreeMethod(c
->reply
,decrRefCount
);
2543 listSetDupMethod(c
->reply
,dupClientReplyValue
);
2544 c
->blockingkeys
= NULL
;
2545 c
->blockingkeysnum
= 0;
2546 c
->io_keys
= listCreate();
2547 listSetFreeMethod(c
->io_keys
,decrRefCount
);
2548 c
->pubsub_channels
= dictCreate(&setDictType
,NULL
);
2549 c
->pubsub_patterns
= listCreate();
2550 listSetFreeMethod(c
->pubsub_patterns
,decrRefCount
);
2551 listSetMatchMethod(c
->pubsub_patterns
,listMatchObjects
);
2552 if (aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
,
2553 readQueryFromClient
, c
) == AE_ERR
) {
2557 listAddNodeTail(server
.clients
,c
);
2558 initClientMultiState(c
);
2562 static void addReply(redisClient
*c
, robj
*obj
) {
2563 if (listLength(c
->reply
) == 0 &&
2564 (c
->replstate
== REDIS_REPL_NONE
||
2565 c
->replstate
== REDIS_REPL_ONLINE
) &&
2566 aeCreateFileEvent(server
.el
, c
->fd
, AE_WRITABLE
,
2567 sendReplyToClient
, c
) == AE_ERR
) return;
2569 if (server
.vm_enabled
&& obj
->storage
!= REDIS_VM_MEMORY
) {
2570 obj
= dupStringObject(obj
);
2571 obj
->refcount
= 0; /* getDecodedObject() will increment the refcount */
2573 listAddNodeTail(c
->reply
,getDecodedObject(obj
));
2576 static void addReplySds(redisClient
*c
, sds s
) {
2577 robj
*o
= createObject(REDIS_STRING
,s
);
2582 static void addReplyDouble(redisClient
*c
, double d
) {
2585 snprintf(buf
,sizeof(buf
),"%.17g",d
);
2586 addReplySds(c
,sdscatprintf(sdsempty(),"$%lu\r\n%s\r\n",
2587 (unsigned long) strlen(buf
),buf
));
2590 static void addReplyLong(redisClient
*c
, long l
) {
2595 addReply(c
,shared
.czero
);
2597 } else if (l
== 1) {
2598 addReply(c
,shared
.cone
);
2601 len
= snprintf(buf
,sizeof(buf
),":%ld\r\n",l
);
2602 addReplySds(c
,sdsnewlen(buf
,len
));
2605 static void addReplyUlong(redisClient
*c
, unsigned long ul
) {
2610 addReply(c
,shared
.czero
);
2612 } else if (ul
== 1) {
2613 addReply(c
,shared
.cone
);
2616 len
= snprintf(buf
,sizeof(buf
),":%lu\r\n",ul
);
2617 addReplySds(c
,sdsnewlen(buf
,len
));
2620 static void addReplyBulkLen(redisClient
*c
, robj
*obj
) {
2623 if (obj
->encoding
== REDIS_ENCODING_RAW
) {
2624 len
= sdslen(obj
->ptr
);
2626 long n
= (long)obj
->ptr
;
2628 /* Compute how many bytes will take this integer as a radix 10 string */
2634 while((n
= n
/10) != 0) {
2638 addReplySds(c
,sdscatprintf(sdsempty(),"$%lu\r\n",(unsigned long)len
));
2641 static void addReplyBulk(redisClient
*c
, robj
*obj
) {
2642 addReplyBulkLen(c
,obj
);
2644 addReply(c
,shared
.crlf
);
2647 /* In the CONFIG command we need to add vanilla C string as bulk replies */
2648 static void addReplyBulkCString(redisClient
*c
, char *s
) {
2650 addReply(c
,shared
.nullbulk
);
2652 robj
*o
= createStringObject(s
,strlen(s
));
2658 static void acceptHandler(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
2663 REDIS_NOTUSED(mask
);
2664 REDIS_NOTUSED(privdata
);
2666 cfd
= anetAccept(server
.neterr
, fd
, cip
, &cport
);
2667 if (cfd
== AE_ERR
) {
2668 redisLog(REDIS_VERBOSE
,"Accepting client connection: %s", server
.neterr
);
2671 redisLog(REDIS_VERBOSE
,"Accepted %s:%d", cip
, cport
);
2672 if ((c
= createClient(cfd
)) == NULL
) {
2673 redisLog(REDIS_WARNING
,"Error allocating resoures for the client");
2674 close(cfd
); /* May be already closed, just ingore errors */
2677 /* If maxclient directive is set and this is one client more... close the
2678 * connection. Note that we create the client instead to check before
2679 * for this condition, since now the socket is already set in nonblocking
2680 * mode and we can send an error for free using the Kernel I/O */
2681 if (server
.maxclients
&& listLength(server
.clients
) > server
.maxclients
) {
2682 char *err
= "-ERR max number of clients reached\r\n";
2684 /* That's a best effort error message, don't check write errors */
2685 if (write(c
->fd
,err
,strlen(err
)) == -1) {
2686 /* Nothing to do, Just to avoid the warning... */
2691 server
.stat_numconnections
++;
2694 /* ======================= Redis objects implementation ===================== */
2696 static robj
*createObject(int type
, void *ptr
) {
2699 if (server
.vm_enabled
) pthread_mutex_lock(&server
.obj_freelist_mutex
);
2700 if (listLength(server
.objfreelist
)) {
2701 listNode
*head
= listFirst(server
.objfreelist
);
2702 o
= listNodeValue(head
);
2703 listDelNode(server
.objfreelist
,head
);
2704 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
2706 if (server
.vm_enabled
) {
2707 pthread_mutex_unlock(&server
.obj_freelist_mutex
);
2708 o
= zmalloc(sizeof(*o
));
2710 o
= zmalloc(sizeof(*o
)-sizeof(struct redisObjectVM
));
2714 o
->encoding
= REDIS_ENCODING_RAW
;
2717 if (server
.vm_enabled
) {
2718 /* Note that this code may run in the context of an I/O thread
2719 * and accessing to server.unixtime in theory is an error
2720 * (no locks). But in practice this is safe, and even if we read
2721 * garbage Redis will not fail, as it's just a statistical info */
2722 o
->vm
.atime
= server
.unixtime
;
2723 o
->storage
= REDIS_VM_MEMORY
;
2728 static robj
*createStringObject(char *ptr
, size_t len
) {
2729 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
2732 static robj
*dupStringObject(robj
*o
) {
2733 assert(o
->encoding
== REDIS_ENCODING_RAW
);
2734 return createStringObject(o
->ptr
,sdslen(o
->ptr
));
2737 static robj
*createListObject(void) {
2738 list
*l
= listCreate();
2740 listSetFreeMethod(l
,decrRefCount
);
2741 return createObject(REDIS_LIST
,l
);
2744 static robj
*createSetObject(void) {
2745 dict
*d
= dictCreate(&setDictType
,NULL
);
2746 return createObject(REDIS_SET
,d
);
2749 static robj
*createHashObject(void) {
2750 /* All the Hashes start as zipmaps. Will be automatically converted
2751 * into hash tables if there are enough elements or big elements
2753 unsigned char *zm
= zipmapNew();
2754 robj
*o
= createObject(REDIS_HASH
,zm
);
2755 o
->encoding
= REDIS_ENCODING_ZIPMAP
;
2759 static robj
*createZsetObject(void) {
2760 zset
*zs
= zmalloc(sizeof(*zs
));
2762 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
2763 zs
->zsl
= zslCreate();
2764 return createObject(REDIS_ZSET
,zs
);
2767 static void freeStringObject(robj
*o
) {
2768 if (o
->encoding
== REDIS_ENCODING_RAW
) {
2773 static void freeListObject(robj
*o
) {
2774 listRelease((list
*) o
->ptr
);
2777 static void freeSetObject(robj
*o
) {
2778 dictRelease((dict
*) o
->ptr
);
2781 static void freeZsetObject(robj
*o
) {
2784 dictRelease(zs
->dict
);
2789 static void freeHashObject(robj
*o
) {
2790 switch (o
->encoding
) {
2791 case REDIS_ENCODING_HT
:
2792 dictRelease((dict
*) o
->ptr
);
2794 case REDIS_ENCODING_ZIPMAP
:
2803 static void incrRefCount(robj
*o
) {
2804 redisAssert(!server
.vm_enabled
|| o
->storage
== REDIS_VM_MEMORY
);
2808 static void decrRefCount(void *obj
) {
2811 /* Object is a key of a swapped out value, or in the process of being
2813 if (server
.vm_enabled
&&
2814 (o
->storage
== REDIS_VM_SWAPPED
|| o
->storage
== REDIS_VM_LOADING
))
2816 if (o
->storage
== REDIS_VM_SWAPPED
|| o
->storage
== REDIS_VM_LOADING
) {
2817 redisAssert(o
->refcount
== 1);
2819 if (o
->storage
== REDIS_VM_LOADING
) vmCancelThreadedIOJob(obj
);
2820 redisAssert(o
->type
== REDIS_STRING
);
2821 freeStringObject(o
);
2822 vmMarkPagesFree(o
->vm
.page
,o
->vm
.usedpages
);
2823 pthread_mutex_lock(&server
.obj_freelist_mutex
);
2824 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
2825 !listAddNodeHead(server
.objfreelist
,o
))
2827 pthread_mutex_unlock(&server
.obj_freelist_mutex
);
2828 server
.vm_stats_swapped_objects
--;
2831 /* Object is in memory, or in the process of being swapped out. */
2832 if (--(o
->refcount
) == 0) {
2833 if (server
.vm_enabled
&& o
->storage
== REDIS_VM_SWAPPING
)
2834 vmCancelThreadedIOJob(obj
);
2836 case REDIS_STRING
: freeStringObject(o
); break;
2837 case REDIS_LIST
: freeListObject(o
); break;
2838 case REDIS_SET
: freeSetObject(o
); break;
2839 case REDIS_ZSET
: freeZsetObject(o
); break;
2840 case REDIS_HASH
: freeHashObject(o
); break;
2841 default: redisAssert(0); break;
2843 if (server
.vm_enabled
) pthread_mutex_lock(&server
.obj_freelist_mutex
);
2844 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
2845 !listAddNodeHead(server
.objfreelist
,o
))
2847 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
2851 static robj
*lookupKey(redisDb
*db
, robj
*key
) {
2852 dictEntry
*de
= dictFind(db
->dict
,key
);
2854 robj
*key
= dictGetEntryKey(de
);
2855 robj
*val
= dictGetEntryVal(de
);
2857 if (server
.vm_enabled
) {
2858 if (key
->storage
== REDIS_VM_MEMORY
||
2859 key
->storage
== REDIS_VM_SWAPPING
)
2861 /* If we were swapping the object out, stop it, this key
2863 if (key
->storage
== REDIS_VM_SWAPPING
)
2864 vmCancelThreadedIOJob(key
);
2865 /* Update the access time of the key for the aging algorithm. */
2866 key
->vm
.atime
= server
.unixtime
;
2868 int notify
= (key
->storage
== REDIS_VM_LOADING
);
2870 /* Our value was swapped on disk. Bring it at home. */
2871 redisAssert(val
== NULL
);
2872 val
= vmLoadObject(key
);
2873 dictGetEntryVal(de
) = val
;
2875 /* Clients blocked by the VM subsystem may be waiting for
2877 if (notify
) handleClientsBlockedOnSwappedKey(db
,key
);
2886 static robj
*lookupKeyRead(redisDb
*db
, robj
*key
) {
2887 expireIfNeeded(db
,key
);
2888 return lookupKey(db
,key
);
2891 static robj
*lookupKeyWrite(redisDb
*db
, robj
*key
) {
2892 deleteIfVolatile(db
,key
);
2893 return lookupKey(db
,key
);
2896 static robj
*lookupKeyReadOrReply(redisClient
*c
, robj
*key
, robj
*reply
) {
2897 robj
*o
= lookupKeyRead(c
->db
, key
);
2898 if (!o
) addReply(c
,reply
);
2902 static robj
*lookupKeyWriteOrReply(redisClient
*c
, robj
*key
, robj
*reply
) {
2903 robj
*o
= lookupKeyWrite(c
->db
, key
);
2904 if (!o
) addReply(c
,reply
);
2908 static int checkType(redisClient
*c
, robj
*o
, int type
) {
2909 if (o
->type
!= type
) {
2910 addReply(c
,shared
.wrongtypeerr
);
2916 static int deleteKey(redisDb
*db
, robj
*key
) {
2919 /* We need to protect key from destruction: after the first dictDelete()
2920 * it may happen that 'key' is no longer valid if we don't increment
2921 * it's count. This may happen when we get the object reference directly
2922 * from the hash table with dictRandomKey() or dict iterators */
2924 if (dictSize(db
->expires
)) dictDelete(db
->expires
,key
);
2925 retval
= dictDelete(db
->dict
,key
);
2928 return retval
== DICT_OK
;
2931 /* Try to share an object against the shared objects pool */
2932 static robj
*tryObjectSharing(robj
*o
) {
2933 struct dictEntry
*de
;
2936 if (o
== NULL
|| server
.shareobjects
== 0) return o
;
2938 redisAssert(o
->type
== REDIS_STRING
);
2939 de
= dictFind(server
.sharingpool
,o
);
2941 robj
*shared
= dictGetEntryKey(de
);
2943 c
= ((unsigned long) dictGetEntryVal(de
))+1;
2944 dictGetEntryVal(de
) = (void*) c
;
2945 incrRefCount(shared
);
2949 /* Here we are using a stream algorihtm: Every time an object is
2950 * shared we increment its count, everytime there is a miss we
2951 * recrement the counter of a random object. If this object reaches
2952 * zero we remove the object and put the current object instead. */
2953 if (dictSize(server
.sharingpool
) >=
2954 server
.sharingpoolsize
) {
2955 de
= dictGetRandomKey(server
.sharingpool
);
2956 redisAssert(de
!= NULL
);
2957 c
= ((unsigned long) dictGetEntryVal(de
))-1;
2958 dictGetEntryVal(de
) = (void*) c
;
2960 dictDelete(server
.sharingpool
,de
->key
);
2963 c
= 0; /* If the pool is empty we want to add this object */
2968 retval
= dictAdd(server
.sharingpool
,o
,(void*)1);
2969 redisAssert(retval
== DICT_OK
);
2976 /* Check if the nul-terminated string 's' can be represented by a long
2977 * (that is, is a number that fits into long without any other space or
2978 * character before or after the digits).
2980 * If so, the function returns REDIS_OK and *longval is set to the value
2981 * of the number. Otherwise REDIS_ERR is returned */
2982 static int isStringRepresentableAsLong(sds s
, long *longval
) {
2983 char buf
[32], *endptr
;
2987 value
= strtol(s
, &endptr
, 10);
2988 if (endptr
[0] != '\0') return REDIS_ERR
;
2989 slen
= snprintf(buf
,32,"%ld",value
);
2991 /* If the number converted back into a string is not identical
2992 * then it's not possible to encode the string as integer */
2993 if (sdslen(s
) != (unsigned)slen
|| memcmp(buf
,s
,slen
)) return REDIS_ERR
;
2994 if (longval
) *longval
= value
;
2998 /* Try to encode a string object in order to save space */
2999 static int tryObjectEncoding(robj
*o
) {
3003 if (o
->encoding
!= REDIS_ENCODING_RAW
)
3004 return REDIS_ERR
; /* Already encoded */
3006 /* It's not save to encode shared objects: shared objects can be shared
3007 * everywhere in the "object space" of Redis. Encoded objects can only
3008 * appear as "values" (and not, for instance, as keys) */
3009 if (o
->refcount
> 1) return REDIS_ERR
;
3011 /* Currently we try to encode only strings */
3012 redisAssert(o
->type
== REDIS_STRING
);
3014 /* Check if we can represent this string as a long integer */
3015 if (isStringRepresentableAsLong(s
,&value
) == REDIS_ERR
) return REDIS_ERR
;
3017 /* Ok, this object can be encoded */
3018 o
->encoding
= REDIS_ENCODING_INT
;
3020 o
->ptr
= (void*) value
;
3024 /* Get a decoded version of an encoded object (returned as a new object).
3025 * If the object is already raw-encoded just increment the ref count. */
3026 static robj
*getDecodedObject(robj
*o
) {
3029 if (o
->encoding
== REDIS_ENCODING_RAW
) {
3033 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
3036 snprintf(buf
,32,"%ld",(long)o
->ptr
);
3037 dec
= createStringObject(buf
,strlen(buf
));
3040 redisAssert(1 != 1);
3044 /* Compare two string objects via strcmp() or alike.
3045 * Note that the objects may be integer-encoded. In such a case we
3046 * use snprintf() to get a string representation of the numbers on the stack
3047 * and compare the strings, it's much faster than calling getDecodedObject().
3049 * Important note: if objects are not integer encoded, but binary-safe strings,
3050 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
3052 static int compareStringObjects(robj
*a
, robj
*b
) {
3053 redisAssert(a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
3054 char bufa
[128], bufb
[128], *astr
, *bstr
;
3057 if (a
== b
) return 0;
3058 if (a
->encoding
!= REDIS_ENCODING_RAW
) {
3059 snprintf(bufa
,sizeof(bufa
),"%ld",(long) a
->ptr
);
3065 if (b
->encoding
!= REDIS_ENCODING_RAW
) {
3066 snprintf(bufb
,sizeof(bufb
),"%ld",(long) b
->ptr
);
3072 return bothsds
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
);
3075 static size_t stringObjectLen(robj
*o
) {
3076 redisAssert(o
->type
== REDIS_STRING
);
3077 if (o
->encoding
== REDIS_ENCODING_RAW
) {
3078 return sdslen(o
->ptr
);
3082 return snprintf(buf
,32,"%ld",(long)o
->ptr
);
3086 /*============================ RDB saving/loading =========================== */
3088 static int rdbSaveType(FILE *fp
, unsigned char type
) {
3089 if (fwrite(&type
,1,1,fp
) == 0) return -1;
3093 static int rdbSaveTime(FILE *fp
, time_t t
) {
3094 int32_t t32
= (int32_t) t
;
3095 if (fwrite(&t32
,4,1,fp
) == 0) return -1;
3099 /* check rdbLoadLen() comments for more info */
3100 static int rdbSaveLen(FILE *fp
, uint32_t len
) {
3101 unsigned char buf
[2];
3104 /* Save a 6 bit len */
3105 buf
[0] = (len
&0xFF)|(REDIS_RDB_6BITLEN
<<6);
3106 if (fwrite(buf
,1,1,fp
) == 0) return -1;
3107 } else if (len
< (1<<14)) {
3108 /* Save a 14 bit len */
3109 buf
[0] = ((len
>>8)&0xFF)|(REDIS_RDB_14BITLEN
<<6);
3111 if (fwrite(buf
,2,1,fp
) == 0) return -1;
3113 /* Save a 32 bit len */
3114 buf
[0] = (REDIS_RDB_32BITLEN
<<6);
3115 if (fwrite(buf
,1,1,fp
) == 0) return -1;
3117 if (fwrite(&len
,4,1,fp
) == 0) return -1;
3122 /* String objects in the form "2391" "-100" without any space and with a
3123 * range of values that can fit in an 8, 16 or 32 bit signed value can be
3124 * encoded as integers to save space */
3125 static int rdbTryIntegerEncoding(char *s
, size_t len
, unsigned char *enc
) {
3127 char *endptr
, buf
[32];
3129 /* Check if it's possible to encode this value as a number */
3130 value
= strtoll(s
, &endptr
, 10);
3131 if (endptr
[0] != '\0') return 0;
3132 snprintf(buf
,32,"%lld",value
);
3134 /* If the number converted back into a string is not identical
3135 * then it's not possible to encode the string as integer */
3136 if (strlen(buf
) != len
|| memcmp(buf
,s
,len
)) return 0;
3138 /* Finally check if it fits in our ranges */
3139 if (value
>= -(1<<7) && value
<= (1<<7)-1) {
3140 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT8
;
3141 enc
[1] = value
&0xFF;
3143 } else if (value
>= -(1<<15) && value
<= (1<<15)-1) {
3144 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT16
;
3145 enc
[1] = value
&0xFF;
3146 enc
[2] = (value
>>8)&0xFF;
3148 } else if (value
>= -((long long)1<<31) && value
<= ((long long)1<<31)-1) {
3149 enc
[0] = (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_INT32
;
3150 enc
[1] = value
&0xFF;
3151 enc
[2] = (value
>>8)&0xFF;
3152 enc
[3] = (value
>>16)&0xFF;
3153 enc
[4] = (value
>>24)&0xFF;
3160 static int rdbSaveLzfStringObject(FILE *fp
, unsigned char *s
, size_t len
) {
3161 size_t comprlen
, outlen
;
3165 /* We require at least four bytes compression for this to be worth it */
3166 if (len
<= 4) return 0;
3168 if ((out
= zmalloc(outlen
+1)) == NULL
) return 0;
3169 comprlen
= lzf_compress(s
, len
, out
, outlen
);
3170 if (comprlen
== 0) {
3174 /* Data compressed! Let's save it on disk */
3175 byte
= (REDIS_RDB_ENCVAL
<<6)|REDIS_RDB_ENC_LZF
;
3176 if (fwrite(&byte
,1,1,fp
) == 0) goto writeerr
;
3177 if (rdbSaveLen(fp
,comprlen
) == -1) goto writeerr
;
3178 if (rdbSaveLen(fp
,len
) == -1) goto writeerr
;
3179 if (fwrite(out
,comprlen
,1,fp
) == 0) goto writeerr
;
3188 /* Save a string objet as [len][data] on disk. If the object is a string
3189 * representation of an integer value we try to safe it in a special form */
3190 static int rdbSaveRawString(FILE *fp
, unsigned char *s
, size_t len
) {
3193 /* Try integer encoding */
3195 unsigned char buf
[5];
3196 if ((enclen
= rdbTryIntegerEncoding((char*)s
,len
,buf
)) > 0) {
3197 if (fwrite(buf
,enclen
,1,fp
) == 0) return -1;
3202 /* Try LZF compression - under 20 bytes it's unable to compress even
3203 * aaaaaaaaaaaaaaaaaa so skip it */
3204 if (server
.rdbcompression
&& len
> 20) {
3207 retval
= rdbSaveLzfStringObject(fp
,s
,len
);
3208 if (retval
== -1) return -1;
3209 if (retval
> 0) return 0;
3210 /* retval == 0 means data can't be compressed, save the old way */
3213 /* Store verbatim */
3214 if (rdbSaveLen(fp
,len
) == -1) return -1;
3215 if (len
&& fwrite(s
,len
,1,fp
) == 0) return -1;
3219 /* Like rdbSaveStringObjectRaw() but handle encoded objects */
3220 static int rdbSaveStringObject(FILE *fp
, robj
*obj
) {
3223 /* Avoid incr/decr ref count business when possible.
3224 * This plays well with copy-on-write given that we are probably
3225 * in a child process (BGSAVE). Also this makes sure key objects
3226 * of swapped objects are not incRefCount-ed (an assert does not allow
3227 * this in order to avoid bugs) */
3228 if (obj
->encoding
!= REDIS_ENCODING_RAW
) {
3229 obj
= getDecodedObject(obj
);
3230 retval
= rdbSaveRawString(fp
,obj
->ptr
,sdslen(obj
->ptr
));
3233 retval
= rdbSaveRawString(fp
,obj
->ptr
,sdslen(obj
->ptr
));
3238 /* Save a double value. Doubles are saved as strings prefixed by an unsigned
3239 * 8 bit integer specifing the length of the representation.
3240 * This 8 bit integer has special values in order to specify the following
3246 static int rdbSaveDoubleValue(FILE *fp
, double val
) {
3247 unsigned char buf
[128];
3253 } else if (!isfinite(val
)) {
3255 buf
[0] = (val
< 0) ? 255 : 254;
3257 snprintf((char*)buf
+1,sizeof(buf
)-1,"%.17g",val
);
3258 buf
[0] = strlen((char*)buf
+1);
3261 if (fwrite(buf
,len
,1,fp
) == 0) return -1;
3265 /* Save a Redis object. */
3266 static int rdbSaveObject(FILE *fp
, robj
*o
) {
3267 if (o
->type
== REDIS_STRING
) {
3268 /* Save a string value */
3269 if (rdbSaveStringObject(fp
,o
) == -1) return -1;
3270 } else if (o
->type
== REDIS_LIST
) {
3271 /* Save a list value */
3272 list
*list
= o
->ptr
;
3276 if (rdbSaveLen(fp
,listLength(list
)) == -1) return -1;
3277 listRewind(list
,&li
);
3278 while((ln
= listNext(&li
))) {
3279 robj
*eleobj
= listNodeValue(ln
);
3281 if (rdbSaveStringObject(fp
,eleobj
) == -1) return -1;
3283 } else if (o
->type
== REDIS_SET
) {
3284 /* Save a set value */
3286 dictIterator
*di
= dictGetIterator(set
);
3289 if (rdbSaveLen(fp
,dictSize(set
)) == -1) return -1;
3290 while((de
= dictNext(di
)) != NULL
) {
3291 robj
*eleobj
= dictGetEntryKey(de
);
3293 if (rdbSaveStringObject(fp
,eleobj
) == -1) return -1;
3295 dictReleaseIterator(di
);
3296 } else if (o
->type
== REDIS_ZSET
) {
3297 /* Save a set value */
3299 dictIterator
*di
= dictGetIterator(zs
->dict
);
3302 if (rdbSaveLen(fp
,dictSize(zs
->dict
)) == -1) return -1;
3303 while((de
= dictNext(di
)) != NULL
) {
3304 robj
*eleobj
= dictGetEntryKey(de
);
3305 double *score
= dictGetEntryVal(de
);
3307 if (rdbSaveStringObject(fp
,eleobj
) == -1) return -1;
3308 if (rdbSaveDoubleValue(fp
,*score
) == -1) return -1;
3310 dictReleaseIterator(di
);
3311 } else if (o
->type
== REDIS_HASH
) {
3312 /* Save a hash value */
3313 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
3314 unsigned char *p
= zipmapRewind(o
->ptr
);
3315 unsigned int count
= zipmapLen(o
->ptr
);
3316 unsigned char *key
, *val
;
3317 unsigned int klen
, vlen
;
3319 if (rdbSaveLen(fp
,count
) == -1) return -1;
3320 while((p
= zipmapNext(p
,&key
,&klen
,&val
,&vlen
)) != NULL
) {
3321 if (rdbSaveRawString(fp
,key
,klen
) == -1) return -1;
3322 if (rdbSaveRawString(fp
,val
,vlen
) == -1) return -1;
3325 dictIterator
*di
= dictGetIterator(o
->ptr
);
3328 if (rdbSaveLen(fp
,dictSize((dict
*)o
->ptr
)) == -1) return -1;
3329 while((de
= dictNext(di
)) != NULL
) {
3330 robj
*key
= dictGetEntryKey(de
);
3331 robj
*val
= dictGetEntryVal(de
);
3333 if (rdbSaveStringObject(fp
,key
) == -1) return -1;
3334 if (rdbSaveStringObject(fp
,val
) == -1) return -1;
3336 dictReleaseIterator(di
);
3344 /* Return the length the object will have on disk if saved with
3345 * the rdbSaveObject() function. Currently we use a trick to get
3346 * this length with very little changes to the code. In the future
3347 * we could switch to a faster solution. */
3348 static off_t
rdbSavedObjectLen(robj
*o
, FILE *fp
) {
3349 if (fp
== NULL
) fp
= server
.devnull
;
3351 assert(rdbSaveObject(fp
,o
) != 1);
3355 /* Return the number of pages required to save this object in the swap file */
3356 static off_t
rdbSavedObjectPages(robj
*o
, FILE *fp
) {
3357 off_t bytes
= rdbSavedObjectLen(o
,fp
);
3359 return (bytes
+(server
.vm_page_size
-1))/server
.vm_page_size
;
3362 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
3363 static int rdbSave(char *filename
) {
3364 dictIterator
*di
= NULL
;
3369 time_t now
= time(NULL
);
3371 /* Wait for I/O therads to terminate, just in case this is a
3372 * foreground-saving, to avoid seeking the swap file descriptor at the
3374 if (server
.vm_enabled
)
3375 waitEmptyIOJobsQueue();
3377 snprintf(tmpfile
,256,"temp-%d.rdb", (int) getpid());
3378 fp
= fopen(tmpfile
,"w");
3380 redisLog(REDIS_WARNING
, "Failed saving the DB: %s", strerror(errno
));
3383 if (fwrite("REDIS0001",9,1,fp
) == 0) goto werr
;
3384 for (j
= 0; j
< server
.dbnum
; j
++) {
3385 redisDb
*db
= server
.db
+j
;
3387 if (dictSize(d
) == 0) continue;
3388 di
= dictGetIterator(d
);
3394 /* Write the SELECT DB opcode */
3395 if (rdbSaveType(fp
,REDIS_SELECTDB
) == -1) goto werr
;
3396 if (rdbSaveLen(fp
,j
) == -1) goto werr
;
3398 /* Iterate this DB writing every entry */
3399 while((de
= dictNext(di
)) != NULL
) {
3400 robj
*key
= dictGetEntryKey(de
);
3401 robj
*o
= dictGetEntryVal(de
);
3402 time_t expiretime
= getExpire(db
,key
);
3404 /* Save the expire time */
3405 if (expiretime
!= -1) {
3406 /* If this key is already expired skip it */
3407 if (expiretime
< now
) continue;
3408 if (rdbSaveType(fp
,REDIS_EXPIRETIME
) == -1) goto werr
;
3409 if (rdbSaveTime(fp
,expiretime
) == -1) goto werr
;
3411 /* Save the key and associated value. This requires special
3412 * handling if the value is swapped out. */
3413 if (!server
.vm_enabled
|| key
->storage
== REDIS_VM_MEMORY
||
3414 key
->storage
== REDIS_VM_SWAPPING
) {
3415 /* Save type, key, value */
3416 if (rdbSaveType(fp
,o
->type
) == -1) goto werr
;
3417 if (rdbSaveStringObject(fp
,key
) == -1) goto werr
;
3418 if (rdbSaveObject(fp
,o
) == -1) goto werr
;
3420 /* REDIS_VM_SWAPPED or REDIS_VM_LOADING */
3422 /* Get a preview of the object in memory */
3423 po
= vmPreviewObject(key
);
3424 /* Save type, key, value */
3425 if (rdbSaveType(fp
,key
->vtype
) == -1) goto werr
;
3426 if (rdbSaveStringObject(fp
,key
) == -1) goto werr
;
3427 if (rdbSaveObject(fp
,po
) == -1) goto werr
;
3428 /* Remove the loaded object from memory */
3432 dictReleaseIterator(di
);
3435 if (rdbSaveType(fp
,REDIS_EOF
) == -1) goto werr
;
3437 /* Make sure data will not remain on the OS's output buffers */
3442 /* Use RENAME to make sure the DB file is changed atomically only
3443 * if the generate DB file is ok. */
3444 if (rename(tmpfile
,filename
) == -1) {
3445 redisLog(REDIS_WARNING
,"Error moving temp DB file on the final destination: %s", strerror(errno
));
3449 redisLog(REDIS_NOTICE
,"DB saved on disk");
3451 server
.lastsave
= time(NULL
);
3457 redisLog(REDIS_WARNING
,"Write error saving DB on disk: %s", strerror(errno
));
3458 if (di
) dictReleaseIterator(di
);
3462 static int rdbSaveBackground(char *filename
) {
3465 if (server
.bgsavechildpid
!= -1) return REDIS_ERR
;
3466 if (server
.vm_enabled
) waitEmptyIOJobsQueue();
3467 if ((childpid
= fork()) == 0) {
3469 if (server
.vm_enabled
) vmReopenSwapFile();
3471 if (rdbSave(filename
) == REDIS_OK
) {
3478 if (childpid
== -1) {
3479 redisLog(REDIS_WARNING
,"Can't save in background: fork: %s",
3483 redisLog(REDIS_NOTICE
,"Background saving started by pid %d",childpid
);
3484 server
.bgsavechildpid
= childpid
;
3487 return REDIS_OK
; /* unreached */
3490 static void rdbRemoveTempFile(pid_t childpid
) {
3493 snprintf(tmpfile
,256,"temp-%d.rdb", (int) childpid
);
3497 static int rdbLoadType(FILE *fp
) {
3499 if (fread(&type
,1,1,fp
) == 0) return -1;
3503 static time_t rdbLoadTime(FILE *fp
) {
3505 if (fread(&t32
,4,1,fp
) == 0) return -1;
3506 return (time_t) t32
;
3509 /* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
3510 * of this file for a description of how this are stored on disk.
3512 * isencoded is set to 1 if the readed length is not actually a length but
3513 * an "encoding type", check the above comments for more info */
3514 static uint32_t rdbLoadLen(FILE *fp
, int *isencoded
) {
3515 unsigned char buf
[2];
3519 if (isencoded
) *isencoded
= 0;
3520 if (fread(buf
,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
3521 type
= (buf
[0]&0xC0)>>6;
3522 if (type
== REDIS_RDB_6BITLEN
) {
3523 /* Read a 6 bit len */
3525 } else if (type
== REDIS_RDB_ENCVAL
) {
3526 /* Read a 6 bit len encoding type */
3527 if (isencoded
) *isencoded
= 1;
3529 } else if (type
== REDIS_RDB_14BITLEN
) {
3530 /* Read a 14 bit len */
3531 if (fread(buf
+1,1,1,fp
) == 0) return REDIS_RDB_LENERR
;
3532 return ((buf
[0]&0x3F)<<8)|buf
[1];
3534 /* Read a 32 bit len */
3535 if (fread(&len
,4,1,fp
) == 0) return REDIS_RDB_LENERR
;
3540 static robj
*rdbLoadIntegerObject(FILE *fp
, int enctype
) {
3541 unsigned char enc
[4];
3544 if (enctype
== REDIS_RDB_ENC_INT8
) {
3545 if (fread(enc
,1,1,fp
) == 0) return NULL
;
3546 val
= (signed char)enc
[0];
3547 } else if (enctype
== REDIS_RDB_ENC_INT16
) {
3549 if (fread(enc
,2,1,fp
) == 0) return NULL
;
3550 v
= enc
[0]|(enc
[1]<<8);
3552 } else if (enctype
== REDIS_RDB_ENC_INT32
) {
3554 if (fread(enc
,4,1,fp
) == 0) return NULL
;
3555 v
= enc
[0]|(enc
[1]<<8)|(enc
[2]<<16)|(enc
[3]<<24);
3558 val
= 0; /* anti-warning */
3561 return createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",val
));
3564 static robj
*rdbLoadLzfStringObject(FILE*fp
) {
3565 unsigned int len
, clen
;
3566 unsigned char *c
= NULL
;
3569 if ((clen
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3570 if ((len
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3571 if ((c
= zmalloc(clen
)) == NULL
) goto err
;
3572 if ((val
= sdsnewlen(NULL
,len
)) == NULL
) goto err
;
3573 if (fread(c
,clen
,1,fp
) == 0) goto err
;
3574 if (lzf_decompress(c
,clen
,val
,len
) == 0) goto err
;
3576 return createObject(REDIS_STRING
,val
);
3583 static robj
*rdbLoadStringObject(FILE*fp
) {
3588 len
= rdbLoadLen(fp
,&isencoded
);
3591 case REDIS_RDB_ENC_INT8
:
3592 case REDIS_RDB_ENC_INT16
:
3593 case REDIS_RDB_ENC_INT32
:
3594 return tryObjectSharing(rdbLoadIntegerObject(fp
,len
));
3595 case REDIS_RDB_ENC_LZF
:
3596 return tryObjectSharing(rdbLoadLzfStringObject(fp
));
3602 if (len
== REDIS_RDB_LENERR
) return NULL
;
3603 val
= sdsnewlen(NULL
,len
);
3604 if (len
&& fread(val
,len
,1,fp
) == 0) {
3608 return tryObjectSharing(createObject(REDIS_STRING
,val
));
3611 /* For information about double serialization check rdbSaveDoubleValue() */
3612 static int rdbLoadDoubleValue(FILE *fp
, double *val
) {
3616 if (fread(&len
,1,1,fp
) == 0) return -1;
3618 case 255: *val
= R_NegInf
; return 0;
3619 case 254: *val
= R_PosInf
; return 0;
3620 case 253: *val
= R_Nan
; return 0;
3622 if (fread(buf
,len
,1,fp
) == 0) return -1;
3624 sscanf(buf
, "%lg", val
);
3629 /* Load a Redis object of the specified type from the specified file.
3630 * On success a newly allocated object is returned, otherwise NULL. */
3631 static robj
*rdbLoadObject(int type
, FILE *fp
) {
3634 redisLog(REDIS_DEBUG
,"LOADING OBJECT %d (at %d)\n",type
,ftell(fp
));
3635 if (type
== REDIS_STRING
) {
3636 /* Read string value */
3637 if ((o
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3638 tryObjectEncoding(o
);
3639 } else if (type
== REDIS_LIST
|| type
== REDIS_SET
) {
3640 /* Read list/set value */
3643 if ((listlen
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3644 o
= (type
== REDIS_LIST
) ? createListObject() : createSetObject();
3645 /* It's faster to expand the dict to the right size asap in order
3646 * to avoid rehashing */
3647 if (type
== REDIS_SET
&& listlen
> DICT_HT_INITIAL_SIZE
)
3648 dictExpand(o
->ptr
,listlen
);
3649 /* Load every single element of the list/set */
3653 if ((ele
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3654 tryObjectEncoding(ele
);
3655 if (type
== REDIS_LIST
) {
3656 listAddNodeTail((list
*)o
->ptr
,ele
);
3658 dictAdd((dict
*)o
->ptr
,ele
,NULL
);
3661 } else if (type
== REDIS_ZSET
) {
3662 /* Read list/set value */
3666 if ((zsetlen
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3667 o
= createZsetObject();
3669 /* Load every single element of the list/set */
3672 double *score
= zmalloc(sizeof(double));
3674 if ((ele
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3675 tryObjectEncoding(ele
);
3676 if (rdbLoadDoubleValue(fp
,score
) == -1) return NULL
;
3677 dictAdd(zs
->dict
,ele
,score
);
3678 zslInsert(zs
->zsl
,*score
,ele
);
3679 incrRefCount(ele
); /* added to skiplist */
3681 } else if (type
== REDIS_HASH
) {
3684 if ((hashlen
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
) return NULL
;
3685 o
= createHashObject();
3686 /* Too many entries? Use an hash table. */
3687 if (hashlen
> server
.hash_max_zipmap_entries
)
3688 convertToRealHash(o
);
3689 /* Load every key/value, then set it into the zipmap or hash
3690 * table, as needed. */
3694 if ((key
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3695 if ((val
= rdbLoadStringObject(fp
)) == NULL
) return NULL
;
3696 /* If we are using a zipmap and there are too big values
3697 * the object is converted to real hash table encoding. */
3698 if (o
->encoding
!= REDIS_ENCODING_HT
&&
3699 (sdslen(key
->ptr
) > server
.hash_max_zipmap_value
||
3700 sdslen(val
->ptr
) > server
.hash_max_zipmap_value
))
3702 convertToRealHash(o
);
3705 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
3706 unsigned char *zm
= o
->ptr
;
3708 zm
= zipmapSet(zm
,key
->ptr
,sdslen(key
->ptr
),
3709 val
->ptr
,sdslen(val
->ptr
),NULL
);
3714 tryObjectEncoding(key
);
3715 tryObjectEncoding(val
);
3716 dictAdd((dict
*)o
->ptr
,key
,val
);
3725 static int rdbLoad(char *filename
) {
3727 robj
*keyobj
= NULL
;
3729 int type
, retval
, rdbver
;
3730 dict
*d
= server
.db
[0].dict
;
3731 redisDb
*db
= server
.db
+0;
3733 time_t expiretime
= -1, now
= time(NULL
);
3734 long long loadedkeys
= 0;
3736 fp
= fopen(filename
,"r");
3737 if (!fp
) return REDIS_ERR
;
3738 if (fread(buf
,9,1,fp
) == 0) goto eoferr
;
3740 if (memcmp(buf
,"REDIS",5) != 0) {
3742 redisLog(REDIS_WARNING
,"Wrong signature trying to load DB from file");
3745 rdbver
= atoi(buf
+5);
3748 redisLog(REDIS_WARNING
,"Can't handle RDB format version %d",rdbver
);
3755 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
3756 if (type
== REDIS_EXPIRETIME
) {
3757 if ((expiretime
= rdbLoadTime(fp
)) == -1) goto eoferr
;
3758 /* We read the time so we need to read the object type again */
3759 if ((type
= rdbLoadType(fp
)) == -1) goto eoferr
;
3761 if (type
== REDIS_EOF
) break;
3762 /* Handle SELECT DB opcode as a special case */
3763 if (type
== REDIS_SELECTDB
) {
3764 if ((dbid
= rdbLoadLen(fp
,NULL
)) == REDIS_RDB_LENERR
)
3766 if (dbid
>= (unsigned)server
.dbnum
) {
3767 redisLog(REDIS_WARNING
,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server
.dbnum
);
3770 db
= server
.db
+dbid
;
3775 if ((keyobj
= rdbLoadStringObject(fp
)) == NULL
) goto eoferr
;
3777 if ((o
= rdbLoadObject(type
,fp
)) == NULL
) goto eoferr
;
3778 /* Add the new object in the hash table */
3779 retval
= dictAdd(d
,keyobj
,o
);
3780 if (retval
== DICT_ERR
) {
3781 redisLog(REDIS_WARNING
,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj
->ptr
);
3784 /* Set the expire time if needed */
3785 if (expiretime
!= -1) {
3786 setExpire(db
,keyobj
,expiretime
);
3787 /* Delete this key if already expired */
3788 if (expiretime
< now
) deleteKey(db
,keyobj
);
3792 /* Handle swapping while loading big datasets when VM is on */
3794 if (server
.vm_enabled
&& (loadedkeys
% 5000) == 0) {
3795 while (zmalloc_used_memory() > server
.vm_max_memory
) {
3796 if (vmSwapOneObjectBlocking() == REDIS_ERR
) break;
3803 eoferr
: /* unexpected end of file is handled here with a fatal exit */
3804 if (keyobj
) decrRefCount(keyobj
);
3805 redisLog(REDIS_WARNING
,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
3807 return REDIS_ERR
; /* Just to avoid warning */
3810 /*================================== Commands =============================== */
3812 static void authCommand(redisClient
*c
) {
3813 if (!server
.requirepass
|| !strcmp(c
->argv
[1]->ptr
, server
.requirepass
)) {
3814 c
->authenticated
= 1;
3815 addReply(c
,shared
.ok
);
3817 c
->authenticated
= 0;
3818 addReplySds(c
,sdscatprintf(sdsempty(),"-ERR invalid password\r\n"));
3822 static void pingCommand(redisClient
*c
) {
3823 addReply(c
,shared
.pong
);
3826 static void echoCommand(redisClient
*c
) {
3827 addReplyBulk(c
,c
->argv
[1]);
3830 /*=================================== Strings =============================== */
3832 static void setGenericCommand(redisClient
*c
, int nx
) {
3835 if (nx
) deleteIfVolatile(c
->db
,c
->argv
[1]);
3836 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
3837 if (retval
== DICT_ERR
) {
3839 /* If the key is about a swapped value, we want a new key object
3840 * to overwrite the old. So we delete the old key in the database.
3841 * This will also make sure that swap pages about the old object
3842 * will be marked as free. */
3843 if (server
.vm_enabled
&& deleteIfSwapped(c
->db
,c
->argv
[1]))
3844 incrRefCount(c
->argv
[1]);
3845 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
3846 incrRefCount(c
->argv
[2]);
3848 addReply(c
,shared
.czero
);
3852 incrRefCount(c
->argv
[1]);
3853 incrRefCount(c
->argv
[2]);
3856 removeExpire(c
->db
,c
->argv
[1]);
3857 addReply(c
, nx
? shared
.cone
: shared
.ok
);
3860 static void setCommand(redisClient
*c
) {
3861 setGenericCommand(c
,0);
3864 static void setnxCommand(redisClient
*c
) {
3865 setGenericCommand(c
,1);
3868 static int getGenericCommand(redisClient
*c
) {
3871 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
)
3874 if (o
->type
!= REDIS_STRING
) {
3875 addReply(c
,shared
.wrongtypeerr
);
3883 static void getCommand(redisClient
*c
) {
3884 getGenericCommand(c
);
3887 static void getsetCommand(redisClient
*c
) {
3888 if (getGenericCommand(c
) == REDIS_ERR
) return;
3889 if (dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]) == DICT_ERR
) {
3890 dictReplace(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
3892 incrRefCount(c
->argv
[1]);
3894 incrRefCount(c
->argv
[2]);
3896 removeExpire(c
->db
,c
->argv
[1]);
3899 static void mgetCommand(redisClient
*c
) {
3902 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",c
->argc
-1));
3903 for (j
= 1; j
< c
->argc
; j
++) {
3904 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
3906 addReply(c
,shared
.nullbulk
);
3908 if (o
->type
!= REDIS_STRING
) {
3909 addReply(c
,shared
.nullbulk
);
3917 static void msetGenericCommand(redisClient
*c
, int nx
) {
3918 int j
, busykeys
= 0;
3920 if ((c
->argc
% 2) == 0) {
3921 addReplySds(c
,sdsnew("-ERR wrong number of arguments for MSET\r\n"));
3924 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
3925 * set nothing at all if at least one already key exists. */
3927 for (j
= 1; j
< c
->argc
; j
+= 2) {
3928 if (lookupKeyWrite(c
->db
,c
->argv
[j
]) != NULL
) {
3934 addReply(c
, shared
.czero
);
3938 for (j
= 1; j
< c
->argc
; j
+= 2) {
3941 tryObjectEncoding(c
->argv
[j
+1]);
3942 retval
= dictAdd(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
3943 if (retval
== DICT_ERR
) {
3944 dictReplace(c
->db
->dict
,c
->argv
[j
],c
->argv
[j
+1]);
3945 incrRefCount(c
->argv
[j
+1]);
3947 incrRefCount(c
->argv
[j
]);
3948 incrRefCount(c
->argv
[j
+1]);
3950 removeExpire(c
->db
,c
->argv
[j
]);
3952 server
.dirty
+= (c
->argc
-1)/2;
3953 addReply(c
, nx
? shared
.cone
: shared
.ok
);
3956 static void msetCommand(redisClient
*c
) {
3957 msetGenericCommand(c
,0);
3960 static void msetnxCommand(redisClient
*c
) {
3961 msetGenericCommand(c
,1);
3964 static void incrDecrCommand(redisClient
*c
, long long incr
) {
3969 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
3973 if (o
->type
!= REDIS_STRING
) {
3978 if (o
->encoding
== REDIS_ENCODING_RAW
)
3979 value
= strtoll(o
->ptr
, &eptr
, 10);
3980 else if (o
->encoding
== REDIS_ENCODING_INT
)
3981 value
= (long)o
->ptr
;
3983 redisAssert(1 != 1);
3988 o
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",value
));
3989 tryObjectEncoding(o
);
3990 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],o
);
3991 if (retval
== DICT_ERR
) {
3992 dictReplace(c
->db
->dict
,c
->argv
[1],o
);
3993 removeExpire(c
->db
,c
->argv
[1]);
3995 incrRefCount(c
->argv
[1]);
3998 addReply(c
,shared
.colon
);
4000 addReply(c
,shared
.crlf
);
4003 static void incrCommand(redisClient
*c
) {
4004 incrDecrCommand(c
,1);
4007 static void decrCommand(redisClient
*c
) {
4008 incrDecrCommand(c
,-1);
4011 static void incrbyCommand(redisClient
*c
) {
4012 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
4013 incrDecrCommand(c
,incr
);
4016 static void decrbyCommand(redisClient
*c
) {
4017 long long incr
= strtoll(c
->argv
[2]->ptr
, NULL
, 10);
4018 incrDecrCommand(c
,-incr
);
4021 static void appendCommand(redisClient
*c
) {
4026 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4028 /* Create the key */
4029 retval
= dictAdd(c
->db
->dict
,c
->argv
[1],c
->argv
[2]);
4030 incrRefCount(c
->argv
[1]);
4031 incrRefCount(c
->argv
[2]);
4032 totlen
= stringObjectLen(c
->argv
[2]);
4036 de
= dictFind(c
->db
->dict
,c
->argv
[1]);
4039 o
= dictGetEntryVal(de
);
4040 if (o
->type
!= REDIS_STRING
) {
4041 addReply(c
,shared
.wrongtypeerr
);
4044 /* If the object is specially encoded or shared we have to make
4046 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
4047 robj
*decoded
= getDecodedObject(o
);
4049 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
4050 decrRefCount(decoded
);
4051 dictReplace(c
->db
->dict
,c
->argv
[1],o
);
4054 if (c
->argv
[2]->encoding
== REDIS_ENCODING_RAW
) {
4055 o
->ptr
= sdscatlen(o
->ptr
,
4056 c
->argv
[2]->ptr
, sdslen(c
->argv
[2]->ptr
));
4058 o
->ptr
= sdscatprintf(o
->ptr
, "%ld",
4059 (unsigned long) c
->argv
[2]->ptr
);
4061 totlen
= sdslen(o
->ptr
);
4064 addReplySds(c
,sdscatprintf(sdsempty(),":%lu\r\n",(unsigned long)totlen
));
4067 static void substrCommand(redisClient
*c
) {
4069 long start
= atoi(c
->argv
[2]->ptr
);
4070 long end
= atoi(c
->argv
[3]->ptr
);
4071 size_t rangelen
, strlen
;
4074 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4075 checkType(c
,o
,REDIS_STRING
)) return;
4077 o
= getDecodedObject(o
);
4078 strlen
= sdslen(o
->ptr
);
4080 /* convert negative indexes */
4081 if (start
< 0) start
= strlen
+start
;
4082 if (end
< 0) end
= strlen
+end
;
4083 if (start
< 0) start
= 0;
4084 if (end
< 0) end
= 0;
4086 /* indexes sanity checks */
4087 if (start
> end
|| (size_t)start
>= strlen
) {
4088 /* Out of range start or start > end result in null reply */
4089 addReply(c
,shared
.nullbulk
);
4093 if ((size_t)end
>= strlen
) end
= strlen
-1;
4094 rangelen
= (end
-start
)+1;
4096 /* Return the result */
4097 addReplySds(c
,sdscatprintf(sdsempty(),"$%zu\r\n",rangelen
));
4098 range
= sdsnewlen((char*)o
->ptr
+start
,rangelen
);
4099 addReplySds(c
,range
);
4100 addReply(c
,shared
.crlf
);
4104 /* ========================= Type agnostic commands ========================= */
4106 static void delCommand(redisClient
*c
) {
4109 for (j
= 1; j
< c
->argc
; j
++) {
4110 if (deleteKey(c
->db
,c
->argv
[j
])) {
4115 addReplyLong(c
,deleted
);
4118 static void existsCommand(redisClient
*c
) {
4119 addReply(c
,lookupKeyRead(c
->db
,c
->argv
[1]) ? shared
.cone
: shared
.czero
);
4122 static void selectCommand(redisClient
*c
) {
4123 int id
= atoi(c
->argv
[1]->ptr
);
4125 if (selectDb(c
,id
) == REDIS_ERR
) {
4126 addReplySds(c
,sdsnew("-ERR invalid DB index\r\n"));
4128 addReply(c
,shared
.ok
);
4132 static void randomkeyCommand(redisClient
*c
) {
4136 de
= dictGetRandomKey(c
->db
->dict
);
4137 if (!de
|| expireIfNeeded(c
->db
,dictGetEntryKey(de
)) == 0) break;
4140 addReply(c
,shared
.plus
);
4141 addReply(c
,shared
.crlf
);
4143 addReply(c
,shared
.plus
);
4144 addReply(c
,dictGetEntryKey(de
));
4145 addReply(c
,shared
.crlf
);
4149 static void keysCommand(redisClient
*c
) {
4152 sds pattern
= c
->argv
[1]->ptr
;
4153 int plen
= sdslen(pattern
);
4154 unsigned long numkeys
= 0;
4155 robj
*lenobj
= createObject(REDIS_STRING
,NULL
);
4157 di
= dictGetIterator(c
->db
->dict
);
4159 decrRefCount(lenobj
);
4160 while((de
= dictNext(di
)) != NULL
) {
4161 robj
*keyobj
= dictGetEntryKey(de
);
4163 sds key
= keyobj
->ptr
;
4164 if ((pattern
[0] == '*' && pattern
[1] == '\0') ||
4165 stringmatchlen(pattern
,plen
,key
,sdslen(key
),0)) {
4166 if (expireIfNeeded(c
->db
,keyobj
) == 0) {
4167 addReplyBulk(c
,keyobj
);
4172 dictReleaseIterator(di
);
4173 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%lu\r\n",numkeys
);
4176 static void dbsizeCommand(redisClient
*c
) {
4178 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c
->db
->dict
)));
4181 static void lastsaveCommand(redisClient
*c
) {
4183 sdscatprintf(sdsempty(),":%lu\r\n",server
.lastsave
));
4186 static void typeCommand(redisClient
*c
) {
4190 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
4195 case REDIS_STRING
: type
= "+string"; break;
4196 case REDIS_LIST
: type
= "+list"; break;
4197 case REDIS_SET
: type
= "+set"; break;
4198 case REDIS_ZSET
: type
= "+zset"; break;
4199 case REDIS_HASH
: type
= "+hash"; break;
4200 default: type
= "+unknown"; break;
4203 addReplySds(c
,sdsnew(type
));
4204 addReply(c
,shared
.crlf
);
4207 static void saveCommand(redisClient
*c
) {
4208 if (server
.bgsavechildpid
!= -1) {
4209 addReplySds(c
,sdsnew("-ERR background save in progress\r\n"));
4212 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
4213 addReply(c
,shared
.ok
);
4215 addReply(c
,shared
.err
);
4219 static void bgsaveCommand(redisClient
*c
) {
4220 if (server
.bgsavechildpid
!= -1) {
4221 addReplySds(c
,sdsnew("-ERR background save already in progress\r\n"));
4224 if (rdbSaveBackground(server
.dbfilename
) == REDIS_OK
) {
4225 char *status
= "+Background saving started\r\n";
4226 addReplySds(c
,sdsnew(status
));
4228 addReply(c
,shared
.err
);
4232 static void shutdownCommand(redisClient
*c
) {
4233 redisLog(REDIS_WARNING
,"User requested shutdown, saving DB...");
4234 /* Kill the saving child if there is a background saving in progress.
4235 We want to avoid race conditions, for instance our saving child may
4236 overwrite the synchronous saving did by SHUTDOWN. */
4237 if (server
.bgsavechildpid
!= -1) {
4238 redisLog(REDIS_WARNING
,"There is a live saving child. Killing it!");
4239 kill(server
.bgsavechildpid
,SIGKILL
);
4240 rdbRemoveTempFile(server
.bgsavechildpid
);
4242 if (server
.appendonly
) {
4243 /* Append only file: fsync() the AOF and exit */
4244 fsync(server
.appendfd
);
4245 if (server
.vm_enabled
) unlink(server
.vm_swap_file
);
4248 /* Snapshotting. Perform a SYNC SAVE and exit */
4249 if (rdbSave(server
.dbfilename
) == REDIS_OK
) {
4250 if (server
.daemonize
)
4251 unlink(server
.pidfile
);
4252 redisLog(REDIS_WARNING
,"%zu bytes used at exit",zmalloc_used_memory());
4253 redisLog(REDIS_WARNING
,"Server exit now, bye bye...");
4254 if (server
.vm_enabled
) unlink(server
.vm_swap_file
);
4257 /* Ooops.. error saving! The best we can do is to continue
4258 * operating. Note that if there was a background saving process,
4259 * in the next cron() Redis will be notified that the background
4260 * saving aborted, handling special stuff like slaves pending for
4261 * synchronization... */
4262 redisLog(REDIS_WARNING
,"Error trying to save the DB, can't exit");
4264 sdsnew("-ERR can't quit, problems saving the DB\r\n"));
4269 static void renameGenericCommand(redisClient
*c
, int nx
) {
4272 /* To use the same key as src and dst is probably an error */
4273 if (sdscmp(c
->argv
[1]->ptr
,c
->argv
[2]->ptr
) == 0) {
4274 addReply(c
,shared
.sameobjecterr
);
4278 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.nokeyerr
)) == NULL
)
4282 deleteIfVolatile(c
->db
,c
->argv
[2]);
4283 if (dictAdd(c
->db
->dict
,c
->argv
[2],o
) == DICT_ERR
) {
4286 addReply(c
,shared
.czero
);
4289 dictReplace(c
->db
->dict
,c
->argv
[2],o
);
4291 incrRefCount(c
->argv
[2]);
4293 deleteKey(c
->db
,c
->argv
[1]);
4295 addReply(c
,nx
? shared
.cone
: shared
.ok
);
4298 static void renameCommand(redisClient
*c
) {
4299 renameGenericCommand(c
,0);
4302 static void renamenxCommand(redisClient
*c
) {
4303 renameGenericCommand(c
,1);
4306 static void moveCommand(redisClient
*c
) {
4311 /* Obtain source and target DB pointers */
4314 if (selectDb(c
,atoi(c
->argv
[2]->ptr
)) == REDIS_ERR
) {
4315 addReply(c
,shared
.outofrangeerr
);
4319 selectDb(c
,srcid
); /* Back to the source DB */
4321 /* If the user is moving using as target the same
4322 * DB as the source DB it is probably an error. */
4324 addReply(c
,shared
.sameobjecterr
);
4328 /* Check if the element exists and get a reference */
4329 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4331 addReply(c
,shared
.czero
);
4335 /* Try to add the element to the target DB */
4336 deleteIfVolatile(dst
,c
->argv
[1]);
4337 if (dictAdd(dst
->dict
,c
->argv
[1],o
) == DICT_ERR
) {
4338 addReply(c
,shared
.czero
);
4341 incrRefCount(c
->argv
[1]);
4344 /* OK! key moved, free the entry in the source DB */
4345 deleteKey(src
,c
->argv
[1]);
4347 addReply(c
,shared
.cone
);
4350 /* =================================== Lists ================================ */
4351 static void pushGenericCommand(redisClient
*c
, int where
) {
4355 lobj
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4357 if (handleClientsWaitingListPush(c
,c
->argv
[1],c
->argv
[2])) {
4358 addReply(c
,shared
.cone
);
4361 lobj
= createListObject();
4363 if (where
== REDIS_HEAD
) {
4364 listAddNodeHead(list
,c
->argv
[2]);
4366 listAddNodeTail(list
,c
->argv
[2]);
4368 dictAdd(c
->db
->dict
,c
->argv
[1],lobj
);
4369 incrRefCount(c
->argv
[1]);
4370 incrRefCount(c
->argv
[2]);
4372 if (lobj
->type
!= REDIS_LIST
) {
4373 addReply(c
,shared
.wrongtypeerr
);
4376 if (handleClientsWaitingListPush(c
,c
->argv
[1],c
->argv
[2])) {
4377 addReply(c
,shared
.cone
);
4381 if (where
== REDIS_HEAD
) {
4382 listAddNodeHead(list
,c
->argv
[2]);
4384 listAddNodeTail(list
,c
->argv
[2]);
4386 incrRefCount(c
->argv
[2]);
4389 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",listLength(list
)));
4392 static void lpushCommand(redisClient
*c
) {
4393 pushGenericCommand(c
,REDIS_HEAD
);
4396 static void rpushCommand(redisClient
*c
) {
4397 pushGenericCommand(c
,REDIS_TAIL
);
4400 static void llenCommand(redisClient
*c
) {
4404 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
4405 checkType(c
,o
,REDIS_LIST
)) return;
4408 addReplyUlong(c
,listLength(l
));
4411 static void lindexCommand(redisClient
*c
) {
4413 int index
= atoi(c
->argv
[2]->ptr
);
4417 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4418 checkType(c
,o
,REDIS_LIST
)) return;
4421 ln
= listIndex(list
, index
);
4423 addReply(c
,shared
.nullbulk
);
4425 robj
*ele
= listNodeValue(ln
);
4426 addReplyBulk(c
,ele
);
4430 static void lsetCommand(redisClient
*c
) {
4432 int index
= atoi(c
->argv
[2]->ptr
);
4436 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.nokeyerr
)) == NULL
||
4437 checkType(c
,o
,REDIS_LIST
)) return;
4440 ln
= listIndex(list
, index
);
4442 addReply(c
,shared
.outofrangeerr
);
4444 robj
*ele
= listNodeValue(ln
);
4447 listNodeValue(ln
) = c
->argv
[3];
4448 incrRefCount(c
->argv
[3]);
4449 addReply(c
,shared
.ok
);
4454 static void popGenericCommand(redisClient
*c
, int where
) {
4459 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4460 checkType(c
,o
,REDIS_LIST
)) return;
4463 if (where
== REDIS_HEAD
)
4464 ln
= listFirst(list
);
4466 ln
= listLast(list
);
4469 addReply(c
,shared
.nullbulk
);
4471 robj
*ele
= listNodeValue(ln
);
4472 addReplyBulk(c
,ele
);
4473 listDelNode(list
,ln
);
4474 if (listLength(list
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4479 static void lpopCommand(redisClient
*c
) {
4480 popGenericCommand(c
,REDIS_HEAD
);
4483 static void rpopCommand(redisClient
*c
) {
4484 popGenericCommand(c
,REDIS_TAIL
);
4487 static void lrangeCommand(redisClient
*c
) {
4489 int start
= atoi(c
->argv
[2]->ptr
);
4490 int end
= atoi(c
->argv
[3]->ptr
);
4497 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullmultibulk
)) == NULL
||
4498 checkType(c
,o
,REDIS_LIST
)) return;
4500 llen
= listLength(list
);
4502 /* convert negative indexes */
4503 if (start
< 0) start
= llen
+start
;
4504 if (end
< 0) end
= llen
+end
;
4505 if (start
< 0) start
= 0;
4506 if (end
< 0) end
= 0;
4508 /* indexes sanity checks */
4509 if (start
> end
|| start
>= llen
) {
4510 /* Out of range start or start > end result in empty list */
4511 addReply(c
,shared
.emptymultibulk
);
4514 if (end
>= llen
) end
= llen
-1;
4515 rangelen
= (end
-start
)+1;
4517 /* Return the result in form of a multi-bulk reply */
4518 ln
= listIndex(list
, start
);
4519 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",rangelen
));
4520 for (j
= 0; j
< rangelen
; j
++) {
4521 ele
= listNodeValue(ln
);
4522 addReplyBulk(c
,ele
);
4527 static void ltrimCommand(redisClient
*c
) {
4529 int start
= atoi(c
->argv
[2]->ptr
);
4530 int end
= atoi(c
->argv
[3]->ptr
);
4532 int j
, ltrim
, rtrim
;
4536 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.ok
)) == NULL
||
4537 checkType(c
,o
,REDIS_LIST
)) return;
4539 llen
= listLength(list
);
4541 /* convert negative indexes */
4542 if (start
< 0) start
= llen
+start
;
4543 if (end
< 0) end
= llen
+end
;
4544 if (start
< 0) start
= 0;
4545 if (end
< 0) end
= 0;
4547 /* indexes sanity checks */
4548 if (start
> end
|| start
>= llen
) {
4549 /* Out of range start or start > end result in empty list */
4553 if (end
>= llen
) end
= llen
-1;
4558 /* Remove list elements to perform the trim */
4559 for (j
= 0; j
< ltrim
; j
++) {
4560 ln
= listFirst(list
);
4561 listDelNode(list
,ln
);
4563 for (j
= 0; j
< rtrim
; j
++) {
4564 ln
= listLast(list
);
4565 listDelNode(list
,ln
);
4567 if (listLength(list
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4569 addReply(c
,shared
.ok
);
4572 static void lremCommand(redisClient
*c
) {
4575 listNode
*ln
, *next
;
4576 int toremove
= atoi(c
->argv
[2]->ptr
);
4580 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
4581 checkType(c
,o
,REDIS_LIST
)) return;
4585 toremove
= -toremove
;
4588 ln
= fromtail
? list
->tail
: list
->head
;
4590 robj
*ele
= listNodeValue(ln
);
4592 next
= fromtail
? ln
->prev
: ln
->next
;
4593 if (compareStringObjects(ele
,c
->argv
[3]) == 0) {
4594 listDelNode(list
,ln
);
4597 if (toremove
&& removed
== toremove
) break;
4601 if (listLength(list
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4602 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",removed
));
4605 /* This is the semantic of this command:
4606 * RPOPLPUSH srclist dstlist:
4607 * IF LLEN(srclist) > 0
4608 * element = RPOP srclist
4609 * LPUSH dstlist element
4616 * The idea is to be able to get an element from a list in a reliable way
4617 * since the element is not just returned but pushed against another list
4618 * as well. This command was originally proposed by Ezra Zygmuntowicz.
4620 static void rpoplpushcommand(redisClient
*c
) {
4625 if ((sobj
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4626 checkType(c
,sobj
,REDIS_LIST
)) return;
4627 srclist
= sobj
->ptr
;
4628 ln
= listLast(srclist
);
4631 addReply(c
,shared
.nullbulk
);
4633 robj
*dobj
= lookupKeyWrite(c
->db
,c
->argv
[2]);
4634 robj
*ele
= listNodeValue(ln
);
4637 if (dobj
&& dobj
->type
!= REDIS_LIST
) {
4638 addReply(c
,shared
.wrongtypeerr
);
4642 /* Add the element to the target list (unless it's directly
4643 * passed to some BLPOP-ing client */
4644 if (!handleClientsWaitingListPush(c
,c
->argv
[2],ele
)) {
4646 /* Create the list if the key does not exist */
4647 dobj
= createListObject();
4648 dictAdd(c
->db
->dict
,c
->argv
[2],dobj
);
4649 incrRefCount(c
->argv
[2]);
4651 dstlist
= dobj
->ptr
;
4652 listAddNodeHead(dstlist
,ele
);
4656 /* Send the element to the client as reply as well */
4657 addReplyBulk(c
,ele
);
4659 /* Finally remove the element from the source list */
4660 listDelNode(srclist
,ln
);
4661 if (listLength(srclist
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4666 /* ==================================== Sets ================================ */
4668 static void saddCommand(redisClient
*c
) {
4671 set
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4673 set
= createSetObject();
4674 dictAdd(c
->db
->dict
,c
->argv
[1],set
);
4675 incrRefCount(c
->argv
[1]);
4677 if (set
->type
!= REDIS_SET
) {
4678 addReply(c
,shared
.wrongtypeerr
);
4682 if (dictAdd(set
->ptr
,c
->argv
[2],NULL
) == DICT_OK
) {
4683 incrRefCount(c
->argv
[2]);
4685 addReply(c
,shared
.cone
);
4687 addReply(c
,shared
.czero
);
4691 static void sremCommand(redisClient
*c
) {
4694 if ((set
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
4695 checkType(c
,set
,REDIS_SET
)) return;
4697 if (dictDelete(set
->ptr
,c
->argv
[2]) == DICT_OK
) {
4699 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
4700 if (dictSize((dict
*)set
->ptr
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4701 addReply(c
,shared
.cone
);
4703 addReply(c
,shared
.czero
);
4707 static void smoveCommand(redisClient
*c
) {
4708 robj
*srcset
, *dstset
;
4710 srcset
= lookupKeyWrite(c
->db
,c
->argv
[1]);
4711 dstset
= lookupKeyWrite(c
->db
,c
->argv
[2]);
4713 /* If the source key does not exist return 0, if it's of the wrong type
4715 if (srcset
== NULL
|| srcset
->type
!= REDIS_SET
) {
4716 addReply(c
, srcset
? shared
.wrongtypeerr
: shared
.czero
);
4719 /* Error if the destination key is not a set as well */
4720 if (dstset
&& dstset
->type
!= REDIS_SET
) {
4721 addReply(c
,shared
.wrongtypeerr
);
4724 /* Remove the element from the source set */
4725 if (dictDelete(srcset
->ptr
,c
->argv
[3]) == DICT_ERR
) {
4726 /* Key not found in the src set! return zero */
4727 addReply(c
,shared
.czero
);
4730 if (dictSize((dict
*)srcset
->ptr
) == 0 && srcset
!= dstset
)
4731 deleteKey(c
->db
,c
->argv
[1]);
4733 /* Add the element to the destination set */
4735 dstset
= createSetObject();
4736 dictAdd(c
->db
->dict
,c
->argv
[2],dstset
);
4737 incrRefCount(c
->argv
[2]);
4739 if (dictAdd(dstset
->ptr
,c
->argv
[3],NULL
) == DICT_OK
)
4740 incrRefCount(c
->argv
[3]);
4741 addReply(c
,shared
.cone
);
4744 static void sismemberCommand(redisClient
*c
) {
4747 if ((set
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
4748 checkType(c
,set
,REDIS_SET
)) return;
4750 if (dictFind(set
->ptr
,c
->argv
[2]))
4751 addReply(c
,shared
.cone
);
4753 addReply(c
,shared
.czero
);
4756 static void scardCommand(redisClient
*c
) {
4760 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
4761 checkType(c
,o
,REDIS_SET
)) return;
4764 addReplyUlong(c
,dictSize(s
));
4767 static void spopCommand(redisClient
*c
) {
4771 if ((set
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4772 checkType(c
,set
,REDIS_SET
)) return;
4774 de
= dictGetRandomKey(set
->ptr
);
4776 addReply(c
,shared
.nullbulk
);
4778 robj
*ele
= dictGetEntryKey(de
);
4780 addReplyBulk(c
,ele
);
4781 dictDelete(set
->ptr
,ele
);
4782 if (htNeedsResize(set
->ptr
)) dictResize(set
->ptr
);
4783 if (dictSize((dict
*)set
->ptr
) == 0) deleteKey(c
->db
,c
->argv
[1]);
4788 static void srandmemberCommand(redisClient
*c
) {
4792 if ((set
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
4793 checkType(c
,set
,REDIS_SET
)) return;
4795 de
= dictGetRandomKey(set
->ptr
);
4797 addReply(c
,shared
.nullbulk
);
4799 robj
*ele
= dictGetEntryKey(de
);
4801 addReplyBulk(c
,ele
);
4805 static int qsortCompareSetsByCardinality(const void *s1
, const void *s2
) {
4806 dict
**d1
= (void*) s1
, **d2
= (void*) s2
;
4808 return dictSize(*d1
)-dictSize(*d2
);
4811 static void sinterGenericCommand(redisClient
*c
, robj
**setskeys
, unsigned long setsnum
, robj
*dstkey
) {
4812 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
4815 robj
*lenobj
= NULL
, *dstset
= NULL
;
4816 unsigned long j
, cardinality
= 0;
4818 for (j
= 0; j
< setsnum
; j
++) {
4822 lookupKeyWrite(c
->db
,setskeys
[j
]) :
4823 lookupKeyRead(c
->db
,setskeys
[j
]);
4827 if (deleteKey(c
->db
,dstkey
))
4829 addReply(c
,shared
.czero
);
4831 addReply(c
,shared
.nullmultibulk
);
4835 if (setobj
->type
!= REDIS_SET
) {
4837 addReply(c
,shared
.wrongtypeerr
);
4840 dv
[j
] = setobj
->ptr
;
4842 /* Sort sets from the smallest to largest, this will improve our
4843 * algorithm's performace */
4844 qsort(dv
,setsnum
,sizeof(dict
*),qsortCompareSetsByCardinality
);
4846 /* The first thing we should output is the total number of elements...
4847 * since this is a multi-bulk write, but at this stage we don't know
4848 * the intersection set size, so we use a trick, append an empty object
4849 * to the output list and save the pointer to later modify it with the
4852 lenobj
= createObject(REDIS_STRING
,NULL
);
4854 decrRefCount(lenobj
);
4856 /* If we have a target key where to store the resulting set
4857 * create this key with an empty set inside */
4858 dstset
= createSetObject();
4861 /* Iterate all the elements of the first (smallest) set, and test
4862 * the element against all the other sets, if at least one set does
4863 * not include the element it is discarded */
4864 di
= dictGetIterator(dv
[0]);
4866 while((de
= dictNext(di
)) != NULL
) {
4869 for (j
= 1; j
< setsnum
; j
++)
4870 if (dictFind(dv
[j
],dictGetEntryKey(de
)) == NULL
) break;
4872 continue; /* at least one set does not contain the member */
4873 ele
= dictGetEntryKey(de
);
4875 addReplyBulk(c
,ele
);
4878 dictAdd(dstset
->ptr
,ele
,NULL
);
4882 dictReleaseIterator(di
);
4885 /* Store the resulting set into the target, if the intersection
4886 * is not an empty set. */
4887 deleteKey(c
->db
,dstkey
);
4888 if (dictSize((dict
*)dstset
->ptr
) > 0) {
4889 dictAdd(c
->db
->dict
,dstkey
,dstset
);
4890 incrRefCount(dstkey
);
4891 addReplyLong(c
,dictSize((dict
*)dstset
->ptr
));
4893 decrRefCount(dstset
);
4894 addReply(c
,shared
.czero
);
4898 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%lu\r\n",cardinality
);
4903 static void sinterCommand(redisClient
*c
) {
4904 sinterGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
);
4907 static void sinterstoreCommand(redisClient
*c
) {
4908 sinterGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1]);
4911 #define REDIS_OP_UNION 0
4912 #define REDIS_OP_DIFF 1
4913 #define REDIS_OP_INTER 2
4915 static void sunionDiffGenericCommand(redisClient
*c
, robj
**setskeys
, int setsnum
, robj
*dstkey
, int op
) {
4916 dict
**dv
= zmalloc(sizeof(dict
*)*setsnum
);
4919 robj
*dstset
= NULL
;
4920 int j
, cardinality
= 0;
4922 for (j
= 0; j
< setsnum
; j
++) {
4926 lookupKeyWrite(c
->db
,setskeys
[j
]) :
4927 lookupKeyRead(c
->db
,setskeys
[j
]);
4932 if (setobj
->type
!= REDIS_SET
) {
4934 addReply(c
,shared
.wrongtypeerr
);
4937 dv
[j
] = setobj
->ptr
;
4940 /* We need a temp set object to store our union. If the dstkey
4941 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
4942 * this set object will be the resulting object to set into the target key*/
4943 dstset
= createSetObject();
4945 /* Iterate all the elements of all the sets, add every element a single
4946 * time to the result set */
4947 for (j
= 0; j
< setsnum
; j
++) {
4948 if (op
== REDIS_OP_DIFF
&& j
== 0 && !dv
[j
]) break; /* result set is empty */
4949 if (!dv
[j
]) continue; /* non existing keys are like empty sets */
4951 di
= dictGetIterator(dv
[j
]);
4953 while((de
= dictNext(di
)) != NULL
) {
4956 /* dictAdd will not add the same element multiple times */
4957 ele
= dictGetEntryKey(de
);
4958 if (op
== REDIS_OP_UNION
|| j
== 0) {
4959 if (dictAdd(dstset
->ptr
,ele
,NULL
) == DICT_OK
) {
4963 } else if (op
== REDIS_OP_DIFF
) {
4964 if (dictDelete(dstset
->ptr
,ele
) == DICT_OK
) {
4969 dictReleaseIterator(di
);
4971 /* result set is empty? Exit asap. */
4972 if (op
== REDIS_OP_DIFF
&& cardinality
== 0) break;
4975 /* Output the content of the resulting set, if not in STORE mode */
4977 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",cardinality
));
4978 di
= dictGetIterator(dstset
->ptr
);
4979 while((de
= dictNext(di
)) != NULL
) {
4982 ele
= dictGetEntryKey(de
);
4983 addReplyBulk(c
,ele
);
4985 dictReleaseIterator(di
);
4986 decrRefCount(dstset
);
4988 /* If we have a target key where to store the resulting set
4989 * create this key with the result set inside */
4990 deleteKey(c
->db
,dstkey
);
4991 if (dictSize((dict
*)dstset
->ptr
) > 0) {
4992 dictAdd(c
->db
->dict
,dstkey
,dstset
);
4993 incrRefCount(dstkey
);
4994 addReplyLong(c
,dictSize((dict
*)dstset
->ptr
));
4996 decrRefCount(dstset
);
4997 addReply(c
,shared
.czero
);
5004 static void sunionCommand(redisClient
*c
) {
5005 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_UNION
);
5008 static void sunionstoreCommand(redisClient
*c
) {
5009 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_UNION
);
5012 static void sdiffCommand(redisClient
*c
) {
5013 sunionDiffGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
,REDIS_OP_DIFF
);
5016 static void sdiffstoreCommand(redisClient
*c
) {
5017 sunionDiffGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1],REDIS_OP_DIFF
);
5020 /* ==================================== ZSets =============================== */
5022 /* ZSETs are ordered sets using two data structures to hold the same elements
5023 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
5026 * The elements are added to an hash table mapping Redis objects to scores.
5027 * At the same time the elements are added to a skip list mapping scores
5028 * to Redis objects (so objects are sorted by scores in this "view"). */
5030 /* This skiplist implementation is almost a C translation of the original
5031 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
5032 * Alternative to Balanced Trees", modified in three ways:
5033 * a) this implementation allows for repeated values.
5034 * b) the comparison is not just by key (our 'score') but by satellite data.
5035 * c) there is a back pointer, so it's a doubly linked list with the back
5036 * pointers being only at "level 1". This allows to traverse the list
5037 * from tail to head, useful for ZREVRANGE. */
5039 static zskiplistNode
*zslCreateNode(int level
, double score
, robj
*obj
) {
5040 zskiplistNode
*zn
= zmalloc(sizeof(*zn
));
5042 zn
->forward
= zmalloc(sizeof(zskiplistNode
*) * level
);
5044 zn
->span
= zmalloc(sizeof(unsigned int) * (level
- 1));
5050 static zskiplist
*zslCreate(void) {
5054 zsl
= zmalloc(sizeof(*zsl
));
5057 zsl
->header
= zslCreateNode(ZSKIPLIST_MAXLEVEL
,0,NULL
);
5058 for (j
= 0; j
< ZSKIPLIST_MAXLEVEL
; j
++) {
5059 zsl
->header
->forward
[j
] = NULL
;
5061 /* span has space for ZSKIPLIST_MAXLEVEL-1 elements */
5062 if (j
< ZSKIPLIST_MAXLEVEL
-1)
5063 zsl
->header
->span
[j
] = 0;
5065 zsl
->header
->backward
= NULL
;
5070 static void zslFreeNode(zskiplistNode
*node
) {
5071 decrRefCount(node
->obj
);
5072 zfree(node
->forward
);
5077 static void zslFree(zskiplist
*zsl
) {
5078 zskiplistNode
*node
= zsl
->header
->forward
[0], *next
;
5080 zfree(zsl
->header
->forward
);
5081 zfree(zsl
->header
->span
);
5084 next
= node
->forward
[0];
5091 static int zslRandomLevel(void) {
5093 while ((random()&0xFFFF) < (ZSKIPLIST_P
* 0xFFFF))
5098 static void zslInsert(zskiplist
*zsl
, double score
, robj
*obj
) {
5099 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
5100 unsigned int rank
[ZSKIPLIST_MAXLEVEL
];
5104 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5105 /* store rank that is crossed to reach the insert position */
5106 rank
[i
] = i
== (zsl
->level
-1) ? 0 : rank
[i
+1];
5108 while (x
->forward
[i
] &&
5109 (x
->forward
[i
]->score
< score
||
5110 (x
->forward
[i
]->score
== score
&&
5111 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0))) {
5112 rank
[i
] += i
> 0 ? x
->span
[i
-1] : 1;
5117 /* we assume the key is not already inside, since we allow duplicated
5118 * scores, and the re-insertion of score and redis object should never
5119 * happpen since the caller of zslInsert() should test in the hash table
5120 * if the element is already inside or not. */
5121 level
= zslRandomLevel();
5122 if (level
> zsl
->level
) {
5123 for (i
= zsl
->level
; i
< level
; i
++) {
5125 update
[i
] = zsl
->header
;
5126 update
[i
]->span
[i
-1] = zsl
->length
;
5130 x
= zslCreateNode(level
,score
,obj
);
5131 for (i
= 0; i
< level
; i
++) {
5132 x
->forward
[i
] = update
[i
]->forward
[i
];
5133 update
[i
]->forward
[i
] = x
;
5135 /* update span covered by update[i] as x is inserted here */
5137 x
->span
[i
-1] = update
[i
]->span
[i
-1] - (rank
[0] - rank
[i
]);
5138 update
[i
]->span
[i
-1] = (rank
[0] - rank
[i
]) + 1;
5142 /* increment span for untouched levels */
5143 for (i
= level
; i
< zsl
->level
; i
++) {
5144 update
[i
]->span
[i
-1]++;
5147 x
->backward
= (update
[0] == zsl
->header
) ? NULL
: update
[0];
5149 x
->forward
[0]->backward
= x
;
5155 /* Internal function used by zslDelete, zslDeleteByScore and zslDeleteByRank */
5156 void zslDeleteNode(zskiplist
*zsl
, zskiplistNode
*x
, zskiplistNode
**update
) {
5158 for (i
= 0; i
< zsl
->level
; i
++) {
5159 if (update
[i
]->forward
[i
] == x
) {
5161 update
[i
]->span
[i
-1] += x
->span
[i
-1] - 1;
5163 update
[i
]->forward
[i
] = x
->forward
[i
];
5165 /* invariant: i > 0, because update[0]->forward[0]
5166 * is always equal to x */
5167 update
[i
]->span
[i
-1] -= 1;
5170 if (x
->forward
[0]) {
5171 x
->forward
[0]->backward
= x
->backward
;
5173 zsl
->tail
= x
->backward
;
5175 while(zsl
->level
> 1 && zsl
->header
->forward
[zsl
->level
-1] == NULL
)
5180 /* Delete an element with matching score/object from the skiplist. */
5181 static int zslDelete(zskiplist
*zsl
, double score
, robj
*obj
) {
5182 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
5186 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5187 while (x
->forward
[i
] &&
5188 (x
->forward
[i
]->score
< score
||
5189 (x
->forward
[i
]->score
== score
&&
5190 compareStringObjects(x
->forward
[i
]->obj
,obj
) < 0)))
5194 /* We may have multiple elements with the same score, what we need
5195 * is to find the element with both the right score and object. */
5197 if (x
&& score
== x
->score
&& compareStringObjects(x
->obj
,obj
) == 0) {
5198 zslDeleteNode(zsl
, x
, update
);
5202 return 0; /* not found */
5204 return 0; /* not found */
5207 /* Delete all the elements with score between min and max from the skiplist.
5208 * Min and mx are inclusive, so a score >= min || score <= max is deleted.
5209 * Note that this function takes the reference to the hash table view of the
5210 * sorted set, in order to remove the elements from the hash table too. */
5211 static unsigned long zslDeleteRangeByScore(zskiplist
*zsl
, double min
, double max
, dict
*dict
) {
5212 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
5213 unsigned long removed
= 0;
5217 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5218 while (x
->forward
[i
] && x
->forward
[i
]->score
< min
)
5222 /* We may have multiple elements with the same score, what we need
5223 * is to find the element with both the right score and object. */
5225 while (x
&& x
->score
<= max
) {
5226 zskiplistNode
*next
= x
->forward
[0];
5227 zslDeleteNode(zsl
, x
, update
);
5228 dictDelete(dict
,x
->obj
);
5233 return removed
; /* not found */
5236 /* Delete all the elements with rank between start and end from the skiplist.
5237 * Start and end are inclusive. Note that start and end need to be 1-based */
5238 static unsigned long zslDeleteRangeByRank(zskiplist
*zsl
, unsigned int start
, unsigned int end
, dict
*dict
) {
5239 zskiplistNode
*update
[ZSKIPLIST_MAXLEVEL
], *x
;
5240 unsigned long traversed
= 0, removed
= 0;
5244 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5245 while (x
->forward
[i
] && (traversed
+ (i
> 0 ? x
->span
[i
-1] : 1)) < start
) {
5246 traversed
+= i
> 0 ? x
->span
[i
-1] : 1;
5254 while (x
&& traversed
<= end
) {
5255 zskiplistNode
*next
= x
->forward
[0];
5256 zslDeleteNode(zsl
, x
, update
);
5257 dictDelete(dict
,x
->obj
);
5266 /* Find the first node having a score equal or greater than the specified one.
5267 * Returns NULL if there is no match. */
5268 static zskiplistNode
*zslFirstWithScore(zskiplist
*zsl
, double score
) {
5273 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5274 while (x
->forward
[i
] && x
->forward
[i
]->score
< score
)
5277 /* We may have multiple elements with the same score, what we need
5278 * is to find the element with both the right score and object. */
5279 return x
->forward
[0];
5282 /* Find the rank for an element by both score and key.
5283 * Returns 0 when the element cannot be found, rank otherwise.
5284 * Note that the rank is 1-based due to the span of zsl->header to the
5286 static unsigned long zslGetRank(zskiplist
*zsl
, double score
, robj
*o
) {
5288 unsigned long rank
= 0;
5292 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5293 while (x
->forward
[i
] &&
5294 (x
->forward
[i
]->score
< score
||
5295 (x
->forward
[i
]->score
== score
&&
5296 compareStringObjects(x
->forward
[i
]->obj
,o
) <= 0))) {
5297 rank
+= i
> 0 ? x
->span
[i
-1] : 1;
5301 /* x might be equal to zsl->header, so test if obj is non-NULL */
5302 if (x
->obj
&& compareStringObjects(x
->obj
,o
) == 0) {
5309 /* Finds an element by its rank. The rank argument needs to be 1-based. */
5310 zskiplistNode
* zslGetElementByRank(zskiplist
*zsl
, unsigned long rank
) {
5312 unsigned long traversed
= 0;
5316 for (i
= zsl
->level
-1; i
>= 0; i
--) {
5317 while (x
->forward
[i
] && (traversed
+ (i
>0 ? x
->span
[i
-1] : 1)) <= rank
)
5319 traversed
+= i
> 0 ? x
->span
[i
-1] : 1;
5322 if (traversed
== rank
) {
5329 /* The actual Z-commands implementations */
5331 /* This generic command implements both ZADD and ZINCRBY.
5332 * scoreval is the score if the operation is a ZADD (doincrement == 0) or
5333 * the increment if the operation is a ZINCRBY (doincrement == 1). */
5334 static void zaddGenericCommand(redisClient
*c
, robj
*key
, robj
*ele
, double scoreval
, int doincrement
) {
5339 zsetobj
= lookupKeyWrite(c
->db
,key
);
5340 if (zsetobj
== NULL
) {
5341 zsetobj
= createZsetObject();
5342 dictAdd(c
->db
->dict
,key
,zsetobj
);
5345 if (zsetobj
->type
!= REDIS_ZSET
) {
5346 addReply(c
,shared
.wrongtypeerr
);
5352 /* Ok now since we implement both ZADD and ZINCRBY here the code
5353 * needs to handle the two different conditions. It's all about setting
5354 * '*score', that is, the new score to set, to the right value. */
5355 score
= zmalloc(sizeof(double));
5359 /* Read the old score. If the element was not present starts from 0 */
5360 de
= dictFind(zs
->dict
,ele
);
5362 double *oldscore
= dictGetEntryVal(de
);
5363 *score
= *oldscore
+ scoreval
;
5371 /* What follows is a simple remove and re-insert operation that is common
5372 * to both ZADD and ZINCRBY... */
5373 if (dictAdd(zs
->dict
,ele
,score
) == DICT_OK
) {
5374 /* case 1: New element */
5375 incrRefCount(ele
); /* added to hash */
5376 zslInsert(zs
->zsl
,*score
,ele
);
5377 incrRefCount(ele
); /* added to skiplist */
5380 addReplyDouble(c
,*score
);
5382 addReply(c
,shared
.cone
);
5387 /* case 2: Score update operation */
5388 de
= dictFind(zs
->dict
,ele
);
5389 redisAssert(de
!= NULL
);
5390 oldscore
= dictGetEntryVal(de
);
5391 if (*score
!= *oldscore
) {
5394 /* Remove and insert the element in the skip list with new score */
5395 deleted
= zslDelete(zs
->zsl
,*oldscore
,ele
);
5396 redisAssert(deleted
!= 0);
5397 zslInsert(zs
->zsl
,*score
,ele
);
5399 /* Update the score in the hash table */
5400 dictReplace(zs
->dict
,ele
,score
);
5406 addReplyDouble(c
,*score
);
5408 addReply(c
,shared
.czero
);
5412 static void zaddCommand(redisClient
*c
) {
5415 scoreval
= strtod(c
->argv
[2]->ptr
,NULL
);
5416 zaddGenericCommand(c
,c
->argv
[1],c
->argv
[3],scoreval
,0);
5419 static void zincrbyCommand(redisClient
*c
) {
5422 scoreval
= strtod(c
->argv
[2]->ptr
,NULL
);
5423 zaddGenericCommand(c
,c
->argv
[1],c
->argv
[3],scoreval
,1);
5426 static void zremCommand(redisClient
*c
) {
5433 if ((zsetobj
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
5434 checkType(c
,zsetobj
,REDIS_ZSET
)) return;
5437 de
= dictFind(zs
->dict
,c
->argv
[2]);
5439 addReply(c
,shared
.czero
);
5442 /* Delete from the skiplist */
5443 oldscore
= dictGetEntryVal(de
);
5444 deleted
= zslDelete(zs
->zsl
,*oldscore
,c
->argv
[2]);
5445 redisAssert(deleted
!= 0);
5447 /* Delete from the hash table */
5448 dictDelete(zs
->dict
,c
->argv
[2]);
5449 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
5450 if (dictSize(zs
->dict
) == 0) deleteKey(c
->db
,c
->argv
[1]);
5452 addReply(c
,shared
.cone
);
5455 static void zremrangebyscoreCommand(redisClient
*c
) {
5456 double min
= strtod(c
->argv
[2]->ptr
,NULL
);
5457 double max
= strtod(c
->argv
[3]->ptr
,NULL
);
5462 if ((zsetobj
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
5463 checkType(c
,zsetobj
,REDIS_ZSET
)) return;
5466 deleted
= zslDeleteRangeByScore(zs
->zsl
,min
,max
,zs
->dict
);
5467 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
5468 if (dictSize(zs
->dict
) == 0) deleteKey(c
->db
,c
->argv
[1]);
5469 server
.dirty
+= deleted
;
5470 addReplyLong(c
,deleted
);
5473 static void zremrangebyrankCommand(redisClient
*c
) {
5474 int start
= atoi(c
->argv
[2]->ptr
);
5475 int end
= atoi(c
->argv
[3]->ptr
);
5481 if ((zsetobj
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
5482 checkType(c
,zsetobj
,REDIS_ZSET
)) return;
5484 llen
= zs
->zsl
->length
;
5486 /* convert negative indexes */
5487 if (start
< 0) start
= llen
+start
;
5488 if (end
< 0) end
= llen
+end
;
5489 if (start
< 0) start
= 0;
5490 if (end
< 0) end
= 0;
5492 /* indexes sanity checks */
5493 if (start
> end
|| start
>= llen
) {
5494 addReply(c
,shared
.czero
);
5497 if (end
>= llen
) end
= llen
-1;
5499 /* increment start and end because zsl*Rank functions
5500 * use 1-based rank */
5501 deleted
= zslDeleteRangeByRank(zs
->zsl
,start
+1,end
+1,zs
->dict
);
5502 if (htNeedsResize(zs
->dict
)) dictResize(zs
->dict
);
5503 if (dictSize(zs
->dict
) == 0) deleteKey(c
->db
,c
->argv
[1]);
5504 server
.dirty
+= deleted
;
5505 addReplyLong(c
, deleted
);
5513 static int qsortCompareZsetopsrcByCardinality(const void *s1
, const void *s2
) {
5514 zsetopsrc
*d1
= (void*) s1
, *d2
= (void*) s2
;
5515 unsigned long size1
, size2
;
5516 size1
= d1
->dict
? dictSize(d1
->dict
) : 0;
5517 size2
= d2
->dict
? dictSize(d2
->dict
) : 0;
5518 return size1
- size2
;
5521 #define REDIS_AGGR_SUM 1
5522 #define REDIS_AGGR_MIN 2
5523 #define REDIS_AGGR_MAX 3
5525 inline static void zunionInterAggregate(double *target
, double val
, int aggregate
) {
5526 if (aggregate
== REDIS_AGGR_SUM
) {
5527 *target
= *target
+ val
;
5528 } else if (aggregate
== REDIS_AGGR_MIN
) {
5529 *target
= val
< *target
? val
: *target
;
5530 } else if (aggregate
== REDIS_AGGR_MAX
) {
5531 *target
= val
> *target
? val
: *target
;
5534 redisAssert(0 != 0);
5538 static void zunionInterGenericCommand(redisClient
*c
, robj
*dstkey
, int op
) {
5540 int aggregate
= REDIS_AGGR_SUM
;
5547 /* expect zsetnum input keys to be given */
5548 zsetnum
= atoi(c
->argv
[2]->ptr
);
5550 addReplySds(c
,sdsnew("-ERR at least 1 input key is needed for ZUNION/ZINTER\r\n"));
5554 /* test if the expected number of keys would overflow */
5555 if (3+zsetnum
> c
->argc
) {
5556 addReply(c
,shared
.syntaxerr
);
5560 /* read keys to be used for input */
5561 src
= zmalloc(sizeof(zsetopsrc
) * zsetnum
);
5562 for (i
= 0, j
= 3; i
< zsetnum
; i
++, j
++) {
5563 robj
*zsetobj
= lookupKeyWrite(c
->db
,c
->argv
[j
]);
5567 if (zsetobj
->type
!= REDIS_ZSET
) {
5569 addReply(c
,shared
.wrongtypeerr
);
5572 src
[i
].dict
= ((zset
*)zsetobj
->ptr
)->dict
;
5575 /* default all weights to 1 */
5576 src
[i
].weight
= 1.0;
5579 /* parse optional extra arguments */
5581 int remaining
= c
->argc
- j
;
5584 if (remaining
>= (zsetnum
+ 1) && !strcasecmp(c
->argv
[j
]->ptr
,"weights")) {
5586 for (i
= 0; i
< zsetnum
; i
++, j
++, remaining
--) {
5587 src
[i
].weight
= strtod(c
->argv
[j
]->ptr
, NULL
);
5589 } else if (remaining
>= 2 && !strcasecmp(c
->argv
[j
]->ptr
,"aggregate")) {
5591 if (!strcasecmp(c
->argv
[j
]->ptr
,"sum")) {
5592 aggregate
= REDIS_AGGR_SUM
;
5593 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"min")) {
5594 aggregate
= REDIS_AGGR_MIN
;
5595 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"max")) {
5596 aggregate
= REDIS_AGGR_MAX
;
5599 addReply(c
,shared
.syntaxerr
);
5605 addReply(c
,shared
.syntaxerr
);
5611 /* sort sets from the smallest to largest, this will improve our
5612 * algorithm's performance */
5613 qsort(src
,zsetnum
,sizeof(zsetopsrc
), qsortCompareZsetopsrcByCardinality
);
5615 dstobj
= createZsetObject();
5616 dstzset
= dstobj
->ptr
;
5618 if (op
== REDIS_OP_INTER
) {
5619 /* skip going over all entries if the smallest zset is NULL or empty */
5620 if (src
[0].dict
&& dictSize(src
[0].dict
) > 0) {
5621 /* precondition: as src[0].dict is non-empty and the zsets are ordered
5622 * from small to large, all src[i > 0].dict are non-empty too */
5623 di
= dictGetIterator(src
[0].dict
);
5624 while((de
= dictNext(di
)) != NULL
) {
5625 double *score
= zmalloc(sizeof(double)), value
;
5626 *score
= src
[0].weight
* (*(double*)dictGetEntryVal(de
));
5628 for (j
= 1; j
< zsetnum
; j
++) {
5629 dictEntry
*other
= dictFind(src
[j
].dict
,dictGetEntryKey(de
));
5631 value
= src
[j
].weight
* (*(double*)dictGetEntryVal(other
));
5632 zunionInterAggregate(score
, value
, aggregate
);
5638 /* skip entry when not present in every source dict */
5642 robj
*o
= dictGetEntryKey(de
);
5643 dictAdd(dstzset
->dict
,o
,score
);
5644 incrRefCount(o
); /* added to dictionary */
5645 zslInsert(dstzset
->zsl
,*score
,o
);
5646 incrRefCount(o
); /* added to skiplist */
5649 dictReleaseIterator(di
);
5651 } else if (op
== REDIS_OP_UNION
) {
5652 for (i
= 0; i
< zsetnum
; i
++) {
5653 if (!src
[i
].dict
) continue;
5655 di
= dictGetIterator(src
[i
].dict
);
5656 while((de
= dictNext(di
)) != NULL
) {
5657 /* skip key when already processed */
5658 if (dictFind(dstzset
->dict
,dictGetEntryKey(de
)) != NULL
) continue;
5660 double *score
= zmalloc(sizeof(double)), value
;
5661 *score
= src
[i
].weight
* (*(double*)dictGetEntryVal(de
));
5663 /* because the zsets are sorted by size, its only possible
5664 * for sets at larger indices to hold this entry */
5665 for (j
= (i
+1); j
< zsetnum
; j
++) {
5666 dictEntry
*other
= dictFind(src
[j
].dict
,dictGetEntryKey(de
));
5668 value
= src
[j
].weight
* (*(double*)dictGetEntryVal(other
));
5669 zunionInterAggregate(score
, value
, aggregate
);
5673 robj
*o
= dictGetEntryKey(de
);
5674 dictAdd(dstzset
->dict
,o
,score
);
5675 incrRefCount(o
); /* added to dictionary */
5676 zslInsert(dstzset
->zsl
,*score
,o
);
5677 incrRefCount(o
); /* added to skiplist */
5679 dictReleaseIterator(di
);
5682 /* unknown operator */
5683 redisAssert(op
== REDIS_OP_INTER
|| op
== REDIS_OP_UNION
);
5686 deleteKey(c
->db
,dstkey
);
5687 if (dstzset
->zsl
->length
) {
5688 dictAdd(c
->db
->dict
,dstkey
,dstobj
);
5689 incrRefCount(dstkey
);
5690 addReplyLong(c
, dstzset
->zsl
->length
);
5693 decrRefCount(dstobj
);
5694 addReply(c
, shared
.czero
);
5699 static void zunionCommand(redisClient
*c
) {
5700 zunionInterGenericCommand(c
,c
->argv
[1], REDIS_OP_UNION
);
5703 static void zinterCommand(redisClient
*c
) {
5704 zunionInterGenericCommand(c
,c
->argv
[1], REDIS_OP_INTER
);
5707 static void zrangeGenericCommand(redisClient
*c
, int reverse
) {
5709 int start
= atoi(c
->argv
[2]->ptr
);
5710 int end
= atoi(c
->argv
[3]->ptr
);
5719 if (c
->argc
== 5 && !strcasecmp(c
->argv
[4]->ptr
,"withscores")) {
5721 } else if (c
->argc
>= 5) {
5722 addReply(c
,shared
.syntaxerr
);
5726 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullmultibulk
)) == NULL
||
5727 checkType(c
,o
,REDIS_ZSET
)) return;
5732 /* convert negative indexes */
5733 if (start
< 0) start
= llen
+start
;
5734 if (end
< 0) end
= llen
+end
;
5735 if (start
< 0) start
= 0;
5736 if (end
< 0) end
= 0;
5738 /* indexes sanity checks */
5739 if (start
> end
|| start
>= llen
) {
5740 /* Out of range start or start > end result in empty list */
5741 addReply(c
,shared
.emptymultibulk
);
5744 if (end
>= llen
) end
= llen
-1;
5745 rangelen
= (end
-start
)+1;
5747 /* check if starting point is trivial, before searching
5748 * the element in log(N) time */
5750 ln
= start
== 0 ? zsl
->tail
: zslGetElementByRank(zsl
, llen
-start
);
5753 zsl
->header
->forward
[0] : zslGetElementByRank(zsl
, start
+1);
5756 /* Return the result in form of a multi-bulk reply */
5757 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",
5758 withscores
? (rangelen
*2) : rangelen
));
5759 for (j
= 0; j
< rangelen
; j
++) {
5761 addReplyBulk(c
,ele
);
5763 addReplyDouble(c
,ln
->score
);
5764 ln
= reverse
? ln
->backward
: ln
->forward
[0];
5768 static void zrangeCommand(redisClient
*c
) {
5769 zrangeGenericCommand(c
,0);
5772 static void zrevrangeCommand(redisClient
*c
) {
5773 zrangeGenericCommand(c
,1);
5776 /* This command implements both ZRANGEBYSCORE and ZCOUNT.
5777 * If justcount is non-zero, just the count is returned. */
5778 static void genericZrangebyscoreCommand(redisClient
*c
, int justcount
) {
5781 int minex
= 0, maxex
= 0; /* are min or max exclusive? */
5782 int offset
= 0, limit
= -1;
5786 /* Parse the min-max interval. If one of the values is prefixed
5787 * by the "(" character, it's considered "open". For instance
5788 * ZRANGEBYSCORE zset (1.5 (2.5 will match min < x < max
5789 * ZRANGEBYSCORE zset 1.5 2.5 will instead match min <= x <= max */
5790 if (((char*)c
->argv
[2]->ptr
)[0] == '(') {
5791 min
= strtod((char*)c
->argv
[2]->ptr
+1,NULL
);
5794 min
= strtod(c
->argv
[2]->ptr
,NULL
);
5796 if (((char*)c
->argv
[3]->ptr
)[0] == '(') {
5797 max
= strtod((char*)c
->argv
[3]->ptr
+1,NULL
);
5800 max
= strtod(c
->argv
[3]->ptr
,NULL
);
5803 /* Parse "WITHSCORES": note that if the command was called with
5804 * the name ZCOUNT then we are sure that c->argc == 4, so we'll never
5805 * enter the following paths to parse WITHSCORES and LIMIT. */
5806 if (c
->argc
== 5 || c
->argc
== 8) {
5807 if (strcasecmp(c
->argv
[c
->argc
-1]->ptr
,"withscores") == 0)
5812 if (c
->argc
!= (4 + withscores
) && c
->argc
!= (7 + withscores
))
5816 sdsnew("-ERR wrong number of arguments for ZRANGEBYSCORE\r\n"));
5821 if (c
->argc
== (7 + withscores
) && strcasecmp(c
->argv
[4]->ptr
,"limit")) {
5822 addReply(c
,shared
.syntaxerr
);
5824 } else if (c
->argc
== (7 + withscores
)) {
5825 offset
= atoi(c
->argv
[5]->ptr
);
5826 limit
= atoi(c
->argv
[6]->ptr
);
5827 if (offset
< 0) offset
= 0;
5830 /* Ok, lookup the key and get the range */
5831 o
= lookupKeyRead(c
->db
,c
->argv
[1]);
5833 addReply(c
,justcount
? shared
.czero
: shared
.nullmultibulk
);
5835 if (o
->type
!= REDIS_ZSET
) {
5836 addReply(c
,shared
.wrongtypeerr
);
5838 zset
*zsetobj
= o
->ptr
;
5839 zskiplist
*zsl
= zsetobj
->zsl
;
5841 robj
*ele
, *lenobj
= NULL
;
5842 unsigned long rangelen
= 0;
5844 /* Get the first node with the score >= min, or with
5845 * score > min if 'minex' is true. */
5846 ln
= zslFirstWithScore(zsl
,min
);
5847 while (minex
&& ln
&& ln
->score
== min
) ln
= ln
->forward
[0];
5850 /* No element matching the speciifed interval */
5851 addReply(c
,justcount
? shared
.czero
: shared
.emptymultibulk
);
5855 /* We don't know in advance how many matching elements there
5856 * are in the list, so we push this object that will represent
5857 * the multi-bulk length in the output buffer, and will "fix"
5860 lenobj
= createObject(REDIS_STRING
,NULL
);
5862 decrRefCount(lenobj
);
5865 while(ln
&& (maxex
? (ln
->score
< max
) : (ln
->score
<= max
))) {
5868 ln
= ln
->forward
[0];
5871 if (limit
== 0) break;
5874 addReplyBulk(c
,ele
);
5876 addReplyDouble(c
,ln
->score
);
5878 ln
= ln
->forward
[0];
5880 if (limit
> 0) limit
--;
5883 addReplyLong(c
,(long)rangelen
);
5885 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%lu\r\n",
5886 withscores
? (rangelen
*2) : rangelen
);
5892 static void zrangebyscoreCommand(redisClient
*c
) {
5893 genericZrangebyscoreCommand(c
,0);
5896 static void zcountCommand(redisClient
*c
) {
5897 genericZrangebyscoreCommand(c
,1);
5900 static void zcardCommand(redisClient
*c
) {
5904 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
5905 checkType(c
,o
,REDIS_ZSET
)) return;
5908 addReplyUlong(c
,zs
->zsl
->length
);
5911 static void zscoreCommand(redisClient
*c
) {
5916 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
5917 checkType(c
,o
,REDIS_ZSET
)) return;
5920 de
= dictFind(zs
->dict
,c
->argv
[2]);
5922 addReply(c
,shared
.nullbulk
);
5924 double *score
= dictGetEntryVal(de
);
5926 addReplyDouble(c
,*score
);
5930 static void zrankGenericCommand(redisClient
*c
, int reverse
) {
5938 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
5939 checkType(c
,o
,REDIS_ZSET
)) return;
5943 de
= dictFind(zs
->dict
,c
->argv
[2]);
5945 addReply(c
,shared
.nullbulk
);
5949 score
= dictGetEntryVal(de
);
5950 rank
= zslGetRank(zsl
, *score
, c
->argv
[2]);
5953 addReplyLong(c
, zsl
->length
- rank
);
5955 addReplyLong(c
, rank
-1);
5958 addReply(c
,shared
.nullbulk
);
5962 static void zrankCommand(redisClient
*c
) {
5963 zrankGenericCommand(c
, 0);
5966 static void zrevrankCommand(redisClient
*c
) {
5967 zrankGenericCommand(c
, 1);
5970 /* =================================== Hashes =============================== */
5971 static void hsetCommand(redisClient
*c
) {
5973 robj
*o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
5976 o
= createHashObject();
5977 dictAdd(c
->db
->dict
,c
->argv
[1],o
);
5978 incrRefCount(c
->argv
[1]);
5980 if (o
->type
!= REDIS_HASH
) {
5981 addReply(c
,shared
.wrongtypeerr
);
5985 /* We want to convert the zipmap into an hash table right now if the
5986 * entry to be added is too big. Note that we check if the object
5987 * is integer encoded before to try fetching the length in the test below.
5988 * This is because integers are small, but currently stringObjectLen()
5989 * performs a slow conversion: not worth it. */
5990 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
&&
5991 ((c
->argv
[2]->encoding
== REDIS_ENCODING_RAW
&&
5992 sdslen(c
->argv
[2]->ptr
) > server
.hash_max_zipmap_value
) ||
5993 (c
->argv
[3]->encoding
== REDIS_ENCODING_RAW
&&
5994 sdslen(c
->argv
[3]->ptr
) > server
.hash_max_zipmap_value
)))
5996 convertToRealHash(o
);
5999 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6000 unsigned char *zm
= o
->ptr
;
6001 robj
*valobj
= getDecodedObject(c
->argv
[3]);
6003 zm
= zipmapSet(zm
,c
->argv
[2]->ptr
,sdslen(c
->argv
[2]->ptr
),
6004 valobj
->ptr
,sdslen(valobj
->ptr
),&update
);
6005 decrRefCount(valobj
);
6008 /* And here there is the second check for hash conversion. */
6009 if (zipmapLen(zm
) > server
.hash_max_zipmap_entries
)
6010 convertToRealHash(o
);
6012 tryObjectEncoding(c
->argv
[2]);
6013 /* note that c->argv[3] is already encoded, as the latest arg
6014 * of a bulk command is always integer encoded if possible. */
6015 if (dictReplace(o
->ptr
,c
->argv
[2],c
->argv
[3])) {
6016 incrRefCount(c
->argv
[2]);
6020 incrRefCount(c
->argv
[3]);
6023 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",update
== 0));
6026 static void hincrbyCommand(redisClient
*c
) {
6027 long long value
= 0, incr
= 0;
6028 robj
*o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
6031 o
= createHashObject();
6032 dictAdd(c
->db
->dict
,c
->argv
[1],o
);
6033 incrRefCount(c
->argv
[1]);
6035 if (o
->type
!= REDIS_HASH
) {
6036 addReply(c
,shared
.wrongtypeerr
);
6041 robj
*o_incr
= getDecodedObject(c
->argv
[3]);
6042 incr
= strtoll(o_incr
->ptr
, NULL
, 10);
6043 decrRefCount(o_incr
);
6045 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6046 unsigned char *zm
= o
->ptr
;
6047 unsigned char *zval
;
6050 /* Find value if already present in hash */
6051 if (zipmapGet(zm
,c
->argv
[2]->ptr
,sdslen(c
->argv
[2]->ptr
),
6053 /* strtoll needs the char* to have a trailing \0, but
6054 * the zipmap doesn't include them. */
6055 sds szval
= sdsnewlen(zval
, zvlen
);
6056 value
= strtoll(szval
,NULL
,10);
6061 sds svalue
= sdscatprintf(sdsempty(),"%lld",value
);
6062 zm
= zipmapSet(zm
,c
->argv
[2]->ptr
,sdslen(c
->argv
[2]->ptr
),
6063 (unsigned char*)svalue
,sdslen(svalue
),NULL
);
6067 /* Check if the zipmap needs to be converted. */
6068 if (zipmapLen(zm
) > server
.hash_max_zipmap_entries
)
6069 convertToRealHash(o
);
6074 /* Find value if already present in hash */
6075 de
= dictFind(o
->ptr
,c
->argv
[2]);
6077 hval
= dictGetEntryVal(de
);
6078 if (hval
->encoding
== REDIS_ENCODING_RAW
)
6079 value
= strtoll(hval
->ptr
,NULL
,10);
6080 else if (hval
->encoding
== REDIS_ENCODING_INT
)
6081 value
= (long)hval
->ptr
;
6083 redisAssert(1 != 1);
6087 hval
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",value
));
6088 tryObjectEncoding(hval
);
6089 if (dictReplace(o
->ptr
,c
->argv
[2],hval
)) {
6090 incrRefCount(c
->argv
[2]);
6095 addReplyLong(c
, value
);
6098 static void hgetCommand(redisClient
*c
) {
6101 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
6102 checkType(c
,o
,REDIS_HASH
)) return;
6104 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6105 unsigned char *zm
= o
->ptr
;
6110 field
= getDecodedObject(c
->argv
[2]);
6111 if (zipmapGet(zm
,field
->ptr
,sdslen(field
->ptr
), &val
,&vlen
)) {
6112 addReplySds(c
,sdscatprintf(sdsempty(),"$%u\r\n", vlen
));
6113 addReplySds(c
,sdsnewlen(val
,vlen
));
6114 addReply(c
,shared
.crlf
);
6115 decrRefCount(field
);
6118 addReply(c
,shared
.nullbulk
);
6119 decrRefCount(field
);
6123 struct dictEntry
*de
;
6125 de
= dictFind(o
->ptr
,c
->argv
[2]);
6127 addReply(c
,shared
.nullbulk
);
6129 robj
*e
= dictGetEntryVal(de
);
6136 static void hdelCommand(redisClient
*c
) {
6140 if ((o
= lookupKeyWriteOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
6141 checkType(c
,o
,REDIS_HASH
)) return;
6143 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6144 robj
*field
= getDecodedObject(c
->argv
[2]);
6146 o
->ptr
= zipmapDel((unsigned char*) o
->ptr
,
6147 (unsigned char*) field
->ptr
,
6148 sdslen(field
->ptr
), &deleted
);
6149 decrRefCount(field
);
6150 if (zipmapLen((unsigned char*) o
->ptr
) == 0)
6151 deleteKey(c
->db
,c
->argv
[1]);
6153 deleted
= dictDelete((dict
*)o
->ptr
,c
->argv
[2]) == DICT_OK
;
6154 if (htNeedsResize(o
->ptr
)) dictResize(o
->ptr
);
6155 if (dictSize((dict
*)o
->ptr
) == 0) deleteKey(c
->db
,c
->argv
[1]);
6157 if (deleted
) server
.dirty
++;
6158 addReply(c
,deleted
? shared
.cone
: shared
.czero
);
6161 static void hlenCommand(redisClient
*c
) {
6165 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
6166 checkType(c
,o
,REDIS_HASH
)) return;
6168 len
= (o
->encoding
== REDIS_ENCODING_ZIPMAP
) ?
6169 zipmapLen((unsigned char*)o
->ptr
) : dictSize((dict
*)o
->ptr
);
6170 addReplyUlong(c
,len
);
6173 #define REDIS_GETALL_KEYS 1
6174 #define REDIS_GETALL_VALS 2
6175 static void genericHgetallCommand(redisClient
*c
, int flags
) {
6177 unsigned long count
= 0;
6179 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullmultibulk
)) == NULL
6180 || checkType(c
,o
,REDIS_HASH
)) return;
6182 lenobj
= createObject(REDIS_STRING
,NULL
);
6184 decrRefCount(lenobj
);
6186 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6187 unsigned char *p
= zipmapRewind(o
->ptr
);
6188 unsigned char *field
, *val
;
6189 unsigned int flen
, vlen
;
6191 while((p
= zipmapNext(p
,&field
,&flen
,&val
,&vlen
)) != NULL
) {
6194 if (flags
& REDIS_GETALL_KEYS
) {
6195 aux
= createStringObject((char*)field
,flen
);
6196 addReplyBulk(c
,aux
);
6200 if (flags
& REDIS_GETALL_VALS
) {
6201 aux
= createStringObject((char*)val
,vlen
);
6202 addReplyBulk(c
,aux
);
6208 dictIterator
*di
= dictGetIterator(o
->ptr
);
6211 while((de
= dictNext(di
)) != NULL
) {
6212 robj
*fieldobj
= dictGetEntryKey(de
);
6213 robj
*valobj
= dictGetEntryVal(de
);
6215 if (flags
& REDIS_GETALL_KEYS
) {
6216 addReplyBulk(c
,fieldobj
);
6219 if (flags
& REDIS_GETALL_VALS
) {
6220 addReplyBulk(c
,valobj
);
6224 dictReleaseIterator(di
);
6226 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%lu\r\n",count
);
6229 static void hkeysCommand(redisClient
*c
) {
6230 genericHgetallCommand(c
,REDIS_GETALL_KEYS
);
6233 static void hvalsCommand(redisClient
*c
) {
6234 genericHgetallCommand(c
,REDIS_GETALL_VALS
);
6237 static void hgetallCommand(redisClient
*c
) {
6238 genericHgetallCommand(c
,REDIS_GETALL_KEYS
|REDIS_GETALL_VALS
);
6241 static void hexistsCommand(redisClient
*c
) {
6245 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
6246 checkType(c
,o
,REDIS_HASH
)) return;
6248 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
6250 unsigned char *zm
= o
->ptr
;
6252 field
= getDecodedObject(c
->argv
[2]);
6253 exists
= zipmapExists(zm
,field
->ptr
,sdslen(field
->ptr
));
6254 decrRefCount(field
);
6256 exists
= dictFind(o
->ptr
,c
->argv
[2]) != NULL
;
6258 addReply(c
,exists
? shared
.cone
: shared
.czero
);
6261 static void convertToRealHash(robj
*o
) {
6262 unsigned char *key
, *val
, *p
, *zm
= o
->ptr
;
6263 unsigned int klen
, vlen
;
6264 dict
*dict
= dictCreate(&hashDictType
,NULL
);
6266 assert(o
->type
== REDIS_HASH
&& o
->encoding
!= REDIS_ENCODING_HT
);
6267 p
= zipmapRewind(zm
);
6268 while((p
= zipmapNext(p
,&key
,&klen
,&val
,&vlen
)) != NULL
) {
6269 robj
*keyobj
, *valobj
;
6271 keyobj
= createStringObject((char*)key
,klen
);
6272 valobj
= createStringObject((char*)val
,vlen
);
6273 tryObjectEncoding(keyobj
);
6274 tryObjectEncoding(valobj
);
6275 dictAdd(dict
,keyobj
,valobj
);
6277 o
->encoding
= REDIS_ENCODING_HT
;
6282 /* ========================= Non type-specific commands ==================== */
6284 static void flushdbCommand(redisClient
*c
) {
6285 server
.dirty
+= dictSize(c
->db
->dict
);
6286 dictEmpty(c
->db
->dict
);
6287 dictEmpty(c
->db
->expires
);
6288 addReply(c
,shared
.ok
);
6291 static void flushallCommand(redisClient
*c
) {
6292 server
.dirty
+= emptyDb();
6293 addReply(c
,shared
.ok
);
6294 if (server
.bgsavechildpid
!= -1) {
6295 kill(server
.bgsavechildpid
,SIGKILL
);
6296 rdbRemoveTempFile(server
.bgsavechildpid
);
6298 rdbSave(server
.dbfilename
);
6302 static redisSortOperation
*createSortOperation(int type
, robj
*pattern
) {
6303 redisSortOperation
*so
= zmalloc(sizeof(*so
));
6305 so
->pattern
= pattern
;
6309 /* Return the value associated to the key with a name obtained
6310 * substituting the first occurence of '*' in 'pattern' with 'subst' */
6311 static robj
*lookupKeyByPattern(redisDb
*db
, robj
*pattern
, robj
*subst
) {
6315 int prefixlen
, sublen
, postfixlen
;
6316 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
6320 char buf
[REDIS_SORTKEY_MAX
+1];
6323 /* If the pattern is "#" return the substitution object itself in order
6324 * to implement the "SORT ... GET #" feature. */
6325 spat
= pattern
->ptr
;
6326 if (spat
[0] == '#' && spat
[1] == '\0') {
6330 /* The substitution object may be specially encoded. If so we create
6331 * a decoded object on the fly. Otherwise getDecodedObject will just
6332 * increment the ref count, that we'll decrement later. */
6333 subst
= getDecodedObject(subst
);
6336 if (sdslen(spat
)+sdslen(ssub
)-1 > REDIS_SORTKEY_MAX
) return NULL
;
6337 p
= strchr(spat
,'*');
6339 decrRefCount(subst
);
6344 sublen
= sdslen(ssub
);
6345 postfixlen
= sdslen(spat
)-(prefixlen
+1);
6346 memcpy(keyname
.buf
,spat
,prefixlen
);
6347 memcpy(keyname
.buf
+prefixlen
,ssub
,sublen
);
6348 memcpy(keyname
.buf
+prefixlen
+sublen
,p
+1,postfixlen
);
6349 keyname
.buf
[prefixlen
+sublen
+postfixlen
] = '\0';
6350 keyname
.len
= prefixlen
+sublen
+postfixlen
;
6352 initStaticStringObject(keyobj
,((char*)&keyname
)+(sizeof(long)*2))
6353 decrRefCount(subst
);
6355 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
6356 return lookupKeyRead(db
,&keyobj
);
6359 /* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
6360 * the additional parameter is not standard but a BSD-specific we have to
6361 * pass sorting parameters via the global 'server' structure */
6362 static int sortCompare(const void *s1
, const void *s2
) {
6363 const redisSortObject
*so1
= s1
, *so2
= s2
;
6366 if (!server
.sort_alpha
) {
6367 /* Numeric sorting. Here it's trivial as we precomputed scores */
6368 if (so1
->u
.score
> so2
->u
.score
) {
6370 } else if (so1
->u
.score
< so2
->u
.score
) {
6376 /* Alphanumeric sorting */
6377 if (server
.sort_bypattern
) {
6378 if (!so1
->u
.cmpobj
|| !so2
->u
.cmpobj
) {
6379 /* At least one compare object is NULL */
6380 if (so1
->u
.cmpobj
== so2
->u
.cmpobj
)
6382 else if (so1
->u
.cmpobj
== NULL
)
6387 /* We have both the objects, use strcoll */
6388 cmp
= strcoll(so1
->u
.cmpobj
->ptr
,so2
->u
.cmpobj
->ptr
);
6391 /* Compare elements directly */
6394 dec1
= getDecodedObject(so1
->obj
);
6395 dec2
= getDecodedObject(so2
->obj
);
6396 cmp
= strcoll(dec1
->ptr
,dec2
->ptr
);
6401 return server
.sort_desc
? -cmp
: cmp
;
6404 /* The SORT command is the most complex command in Redis. Warning: this code
6405 * is optimized for speed and a bit less for readability */
6406 static void sortCommand(redisClient
*c
) {
6409 int desc
= 0, alpha
= 0;
6410 int limit_start
= 0, limit_count
= -1, start
, end
;
6411 int j
, dontsort
= 0, vectorlen
;
6412 int getop
= 0; /* GET operation counter */
6413 robj
*sortval
, *sortby
= NULL
, *storekey
= NULL
;
6414 redisSortObject
*vector
; /* Resulting vector to sort */
6416 /* Lookup the key to sort. It must be of the right types */
6417 sortval
= lookupKeyRead(c
->db
,c
->argv
[1]);
6418 if (sortval
== NULL
) {
6419 addReply(c
,shared
.nullmultibulk
);
6422 if (sortval
->type
!= REDIS_SET
&& sortval
->type
!= REDIS_LIST
&&
6423 sortval
->type
!= REDIS_ZSET
)
6425 addReply(c
,shared
.wrongtypeerr
);
6429 /* Create a list of operations to perform for every sorted element.
6430 * Operations can be GET/DEL/INCR/DECR */
6431 operations
= listCreate();
6432 listSetFreeMethod(operations
,zfree
);
6435 /* Now we need to protect sortval incrementing its count, in the future
6436 * SORT may have options able to overwrite/delete keys during the sorting
6437 * and the sorted key itself may get destroied */
6438 incrRefCount(sortval
);
6440 /* The SORT command has an SQL-alike syntax, parse it */
6441 while(j
< c
->argc
) {
6442 int leftargs
= c
->argc
-j
-1;
6443 if (!strcasecmp(c
->argv
[j
]->ptr
,"asc")) {
6445 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"desc")) {
6447 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"alpha")) {
6449 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"limit") && leftargs
>= 2) {
6450 limit_start
= atoi(c
->argv
[j
+1]->ptr
);
6451 limit_count
= atoi(c
->argv
[j
+2]->ptr
);
6453 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"store") && leftargs
>= 1) {
6454 storekey
= c
->argv
[j
+1];
6456 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"by") && leftargs
>= 1) {
6457 sortby
= c
->argv
[j
+1];
6458 /* If the BY pattern does not contain '*', i.e. it is constant,
6459 * we don't need to sort nor to lookup the weight keys. */
6460 if (strchr(c
->argv
[j
+1]->ptr
,'*') == NULL
) dontsort
= 1;
6462 } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs
>= 1) {
6463 listAddNodeTail(operations
,createSortOperation(
6464 REDIS_SORT_GET
,c
->argv
[j
+1]));
6468 decrRefCount(sortval
);
6469 listRelease(operations
);
6470 addReply(c
,shared
.syntaxerr
);
6476 /* Load the sorting vector with all the objects to sort */
6477 switch(sortval
->type
) {
6478 case REDIS_LIST
: vectorlen
= listLength((list
*)sortval
->ptr
); break;
6479 case REDIS_SET
: vectorlen
= dictSize((dict
*)sortval
->ptr
); break;
6480 case REDIS_ZSET
: vectorlen
= dictSize(((zset
*)sortval
->ptr
)->dict
); break;
6481 default: vectorlen
= 0; redisAssert(0); /* Avoid GCC warning */
6483 vector
= zmalloc(sizeof(redisSortObject
)*vectorlen
);
6486 if (sortval
->type
== REDIS_LIST
) {
6487 list
*list
= sortval
->ptr
;
6491 listRewind(list
,&li
);
6492 while((ln
= listNext(&li
))) {
6493 robj
*ele
= ln
->value
;
6494 vector
[j
].obj
= ele
;
6495 vector
[j
].u
.score
= 0;
6496 vector
[j
].u
.cmpobj
= NULL
;
6504 if (sortval
->type
== REDIS_SET
) {
6507 zset
*zs
= sortval
->ptr
;
6511 di
= dictGetIterator(set
);
6512 while((setele
= dictNext(di
)) != NULL
) {
6513 vector
[j
].obj
= dictGetEntryKey(setele
);
6514 vector
[j
].u
.score
= 0;
6515 vector
[j
].u
.cmpobj
= NULL
;
6518 dictReleaseIterator(di
);
6520 redisAssert(j
== vectorlen
);
6522 /* Now it's time to load the right scores in the sorting vector */
6523 if (dontsort
== 0) {
6524 for (j
= 0; j
< vectorlen
; j
++) {
6528 byval
= lookupKeyByPattern(c
->db
,sortby
,vector
[j
].obj
);
6529 if (!byval
|| byval
->type
!= REDIS_STRING
) continue;
6531 vector
[j
].u
.cmpobj
= getDecodedObject(byval
);
6533 if (byval
->encoding
== REDIS_ENCODING_RAW
) {
6534 vector
[j
].u
.score
= strtod(byval
->ptr
,NULL
);
6536 /* Don't need to decode the object if it's
6537 * integer-encoded (the only encoding supported) so
6538 * far. We can just cast it */
6539 if (byval
->encoding
== REDIS_ENCODING_INT
) {
6540 vector
[j
].u
.score
= (long)byval
->ptr
;
6542 redisAssert(1 != 1);
6547 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_RAW
)
6548 vector
[j
].u
.score
= strtod(vector
[j
].obj
->ptr
,NULL
);
6550 if (vector
[j
].obj
->encoding
== REDIS_ENCODING_INT
)
6551 vector
[j
].u
.score
= (long) vector
[j
].obj
->ptr
;
6553 redisAssert(1 != 1);
6560 /* We are ready to sort the vector... perform a bit of sanity check
6561 * on the LIMIT option too. We'll use a partial version of quicksort. */
6562 start
= (limit_start
< 0) ? 0 : limit_start
;
6563 end
= (limit_count
< 0) ? vectorlen
-1 : start
+limit_count
-1;
6564 if (start
>= vectorlen
) {
6565 start
= vectorlen
-1;
6568 if (end
>= vectorlen
) end
= vectorlen
-1;
6570 if (dontsort
== 0) {
6571 server
.sort_desc
= desc
;
6572 server
.sort_alpha
= alpha
;
6573 server
.sort_bypattern
= sortby
? 1 : 0;
6574 if (sortby
&& (start
!= 0 || end
!= vectorlen
-1))
6575 pqsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
, start
,end
);
6577 qsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
);
6580 /* Send command output to the output buffer, performing the specified
6581 * GET/DEL/INCR/DECR operations if any. */
6582 outputlen
= getop
? getop
*(end
-start
+1) : end
-start
+1;
6583 if (storekey
== NULL
) {
6584 /* STORE option not specified, sent the sorting result to client */
6585 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",outputlen
));
6586 for (j
= start
; j
<= end
; j
++) {
6590 if (!getop
) addReplyBulk(c
,vector
[j
].obj
);
6591 listRewind(operations
,&li
);
6592 while((ln
= listNext(&li
))) {
6593 redisSortOperation
*sop
= ln
->value
;
6594 robj
*val
= lookupKeyByPattern(c
->db
,sop
->pattern
,
6597 if (sop
->type
== REDIS_SORT_GET
) {
6598 if (!val
|| val
->type
!= REDIS_STRING
) {
6599 addReply(c
,shared
.nullbulk
);
6601 addReplyBulk(c
,val
);
6604 redisAssert(sop
->type
== REDIS_SORT_GET
); /* always fails */
6609 robj
*listObject
= createListObject();
6610 list
*listPtr
= (list
*) listObject
->ptr
;
6612 /* STORE option specified, set the sorting result as a List object */
6613 for (j
= start
; j
<= end
; j
++) {
6618 listAddNodeTail(listPtr
,vector
[j
].obj
);
6619 incrRefCount(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 listAddNodeTail(listPtr
,createStringObject("",0));
6631 listAddNodeTail(listPtr
,val
);
6635 redisAssert(sop
->type
== REDIS_SORT_GET
); /* always fails */
6639 if (dictReplace(c
->db
->dict
,storekey
,listObject
)) {
6640 incrRefCount(storekey
);
6642 /* Note: we add 1 because the DB is dirty anyway since even if the
6643 * SORT result is empty a new key is set and maybe the old content
6645 server
.dirty
+= 1+outputlen
;
6646 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",outputlen
));
6650 decrRefCount(sortval
);
6651 listRelease(operations
);
6652 for (j
= 0; j
< vectorlen
; j
++) {
6653 if (sortby
&& alpha
&& vector
[j
].u
.cmpobj
)
6654 decrRefCount(vector
[j
].u
.cmpobj
);
6659 /* Convert an amount of bytes into a human readable string in the form
6660 * of 100B, 2G, 100M, 4K, and so forth. */
6661 static void bytesToHuman(char *s
, unsigned long long n
) {
6666 sprintf(s
,"%lluB",n
);
6668 } else if (n
< (1024*1024)) {
6669 d
= (double)n
/(1024);
6670 sprintf(s
,"%.2fK",d
);
6671 } else if (n
< (1024LL*1024*1024)) {
6672 d
= (double)n
/(1024*1024);
6673 sprintf(s
,"%.2fM",d
);
6674 } else if (n
< (1024LL*1024*1024*1024)) {
6675 d
= (double)n
/(1024LL*1024*1024);
6676 sprintf(s
,"%.2fG",d
);
6680 /* Create the string returned by the INFO command. This is decoupled
6681 * by the INFO command itself as we need to report the same information
6682 * on memory corruption problems. */
6683 static sds
genRedisInfoString(void) {
6685 time_t uptime
= time(NULL
)-server
.stat_starttime
;
6689 bytesToHuman(hmem
,zmalloc_used_memory());
6690 info
= sdscatprintf(sdsempty(),
6691 "redis_version:%s\r\n"
6693 "multiplexing_api:%s\r\n"
6694 "process_id:%ld\r\n"
6695 "uptime_in_seconds:%ld\r\n"
6696 "uptime_in_days:%ld\r\n"
6697 "connected_clients:%d\r\n"
6698 "connected_slaves:%d\r\n"
6699 "blocked_clients:%d\r\n"
6700 "used_memory:%zu\r\n"
6701 "used_memory_human:%s\r\n"
6702 "changes_since_last_save:%lld\r\n"
6703 "bgsave_in_progress:%d\r\n"
6704 "last_save_time:%ld\r\n"
6705 "bgrewriteaof_in_progress:%d\r\n"
6706 "total_connections_received:%lld\r\n"
6707 "total_commands_processed:%lld\r\n"
6708 "expired_keys:%lld\r\n"
6709 "hash_max_zipmap_entries:%ld\r\n"
6710 "hash_max_zipmap_value:%ld\r\n"
6711 "pubsub_channels:%ld\r\n"
6712 "pubsub_patterns:%u\r\n"
6716 (sizeof(long) == 8) ? "64" : "32",
6721 listLength(server
.clients
)-listLength(server
.slaves
),
6722 listLength(server
.slaves
),
6723 server
.blpop_blocked_clients
,
6724 zmalloc_used_memory(),
6727 server
.bgsavechildpid
!= -1,
6729 server
.bgrewritechildpid
!= -1,
6730 server
.stat_numconnections
,
6731 server
.stat_numcommands
,
6732 server
.stat_expiredkeys
,
6733 server
.hash_max_zipmap_entries
,
6734 server
.hash_max_zipmap_value
,
6735 dictSize(server
.pubsub_channels
),
6736 listLength(server
.pubsub_patterns
),
6737 server
.vm_enabled
!= 0,
6738 server
.masterhost
== NULL
? "master" : "slave"
6740 if (server
.masterhost
) {
6741 info
= sdscatprintf(info
,
6742 "master_host:%s\r\n"
6743 "master_port:%d\r\n"
6744 "master_link_status:%s\r\n"
6745 "master_last_io_seconds_ago:%d\r\n"
6748 (server
.replstate
== REDIS_REPL_CONNECTED
) ?
6750 server
.master
? ((int)(time(NULL
)-server
.master
->lastinteraction
)) : -1
6753 if (server
.vm_enabled
) {
6755 info
= sdscatprintf(info
,
6756 "vm_conf_max_memory:%llu\r\n"
6757 "vm_conf_page_size:%llu\r\n"
6758 "vm_conf_pages:%llu\r\n"
6759 "vm_stats_used_pages:%llu\r\n"
6760 "vm_stats_swapped_objects:%llu\r\n"
6761 "vm_stats_swappin_count:%llu\r\n"
6762 "vm_stats_swappout_count:%llu\r\n"
6763 "vm_stats_io_newjobs_len:%lu\r\n"
6764 "vm_stats_io_processing_len:%lu\r\n"
6765 "vm_stats_io_processed_len:%lu\r\n"
6766 "vm_stats_io_active_threads:%lu\r\n"
6767 "vm_stats_blocked_clients:%lu\r\n"
6768 ,(unsigned long long) server
.vm_max_memory
,
6769 (unsigned long long) server
.vm_page_size
,
6770 (unsigned long long) server
.vm_pages
,
6771 (unsigned long long) server
.vm_stats_used_pages
,
6772 (unsigned long long) server
.vm_stats_swapped_objects
,
6773 (unsigned long long) server
.vm_stats_swapins
,
6774 (unsigned long long) server
.vm_stats_swapouts
,
6775 (unsigned long) listLength(server
.io_newjobs
),
6776 (unsigned long) listLength(server
.io_processing
),
6777 (unsigned long) listLength(server
.io_processed
),
6778 (unsigned long) server
.io_active_threads
,
6779 (unsigned long) server
.vm_blocked_clients
6783 for (j
= 0; j
< server
.dbnum
; j
++) {
6784 long long keys
, vkeys
;
6786 keys
= dictSize(server
.db
[j
].dict
);
6787 vkeys
= dictSize(server
.db
[j
].expires
);
6788 if (keys
|| vkeys
) {
6789 info
= sdscatprintf(info
, "db%d:keys=%lld,expires=%lld\r\n",
6796 static void infoCommand(redisClient
*c
) {
6797 sds info
= genRedisInfoString();
6798 addReplySds(c
,sdscatprintf(sdsempty(),"$%lu\r\n",
6799 (unsigned long)sdslen(info
)));
6800 addReplySds(c
,info
);
6801 addReply(c
,shared
.crlf
);
6804 static void monitorCommand(redisClient
*c
) {
6805 /* ignore MONITOR if aleady slave or in monitor mode */
6806 if (c
->flags
& REDIS_SLAVE
) return;
6808 c
->flags
|= (REDIS_SLAVE
|REDIS_MONITOR
);
6810 listAddNodeTail(server
.monitors
,c
);
6811 addReply(c
,shared
.ok
);
6814 /* ================================= Expire ================================= */
6815 static int removeExpire(redisDb
*db
, robj
*key
) {
6816 if (dictDelete(db
->expires
,key
) == DICT_OK
) {
6823 static int setExpire(redisDb
*db
, robj
*key
, time_t when
) {
6824 if (dictAdd(db
->expires
,key
,(void*)when
) == DICT_ERR
) {
6832 /* Return the expire time of the specified key, or -1 if no expire
6833 * is associated with this key (i.e. the key is non volatile) */
6834 static time_t getExpire(redisDb
*db
, robj
*key
) {
6837 /* No expire? return ASAP */
6838 if (dictSize(db
->expires
) == 0 ||
6839 (de
= dictFind(db
->expires
,key
)) == NULL
) return -1;
6841 return (time_t) dictGetEntryVal(de
);
6844 static int expireIfNeeded(redisDb
*db
, robj
*key
) {
6848 /* No expire? return ASAP */
6849 if (dictSize(db
->expires
) == 0 ||
6850 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
6852 /* Lookup the expire */
6853 when
= (time_t) dictGetEntryVal(de
);
6854 if (time(NULL
) <= when
) return 0;
6856 /* Delete the key */
6857 dictDelete(db
->expires
,key
);
6858 server
.stat_expiredkeys
++;
6859 return dictDelete(db
->dict
,key
) == DICT_OK
;
6862 static int deleteIfVolatile(redisDb
*db
, robj
*key
) {
6865 /* No expire? return ASAP */
6866 if (dictSize(db
->expires
) == 0 ||
6867 (de
= dictFind(db
->expires
,key
)) == NULL
) return 0;
6869 /* Delete the key */
6871 server
.stat_expiredkeys
++;
6872 dictDelete(db
->expires
,key
);
6873 return dictDelete(db
->dict
,key
) == DICT_OK
;
6876 static void expireGenericCommand(redisClient
*c
, robj
*key
, time_t seconds
) {
6879 de
= dictFind(c
->db
->dict
,key
);
6881 addReply(c
,shared
.czero
);
6885 if (deleteKey(c
->db
,key
)) server
.dirty
++;
6886 addReply(c
, shared
.cone
);
6889 time_t when
= time(NULL
)+seconds
;
6890 if (setExpire(c
->db
,key
,when
)) {
6891 addReply(c
,shared
.cone
);
6894 addReply(c
,shared
.czero
);
6900 static void expireCommand(redisClient
*c
) {
6901 expireGenericCommand(c
,c
->argv
[1],strtol(c
->argv
[2]->ptr
,NULL
,10));
6904 static void expireatCommand(redisClient
*c
) {
6905 expireGenericCommand(c
,c
->argv
[1],strtol(c
->argv
[2]->ptr
,NULL
,10)-time(NULL
));
6908 static void ttlCommand(redisClient
*c
) {
6912 expire
= getExpire(c
->db
,c
->argv
[1]);
6914 ttl
= (int) (expire
-time(NULL
));
6915 if (ttl
< 0) ttl
= -1;
6917 addReplySds(c
,sdscatprintf(sdsempty(),":%d\r\n",ttl
));
6920 /* ================================ MULTI/EXEC ============================== */
6922 /* Client state initialization for MULTI/EXEC */
6923 static void initClientMultiState(redisClient
*c
) {
6924 c
->mstate
.commands
= NULL
;
6925 c
->mstate
.count
= 0;
6928 /* Release all the resources associated with MULTI/EXEC state */
6929 static void freeClientMultiState(redisClient
*c
) {
6932 for (j
= 0; j
< c
->mstate
.count
; j
++) {
6934 multiCmd
*mc
= c
->mstate
.commands
+j
;
6936 for (i
= 0; i
< mc
->argc
; i
++)
6937 decrRefCount(mc
->argv
[i
]);
6940 zfree(c
->mstate
.commands
);
6943 /* Add a new command into the MULTI commands queue */
6944 static void queueMultiCommand(redisClient
*c
, struct redisCommand
*cmd
) {
6948 c
->mstate
.commands
= zrealloc(c
->mstate
.commands
,
6949 sizeof(multiCmd
)*(c
->mstate
.count
+1));
6950 mc
= c
->mstate
.commands
+c
->mstate
.count
;
6953 mc
->argv
= zmalloc(sizeof(robj
*)*c
->argc
);
6954 memcpy(mc
->argv
,c
->argv
,sizeof(robj
*)*c
->argc
);
6955 for (j
= 0; j
< c
->argc
; j
++)
6956 incrRefCount(mc
->argv
[j
]);
6960 static void multiCommand(redisClient
*c
) {
6961 c
->flags
|= REDIS_MULTI
;
6962 addReply(c
,shared
.ok
);
6965 static void discardCommand(redisClient
*c
) {
6966 if (!(c
->flags
& REDIS_MULTI
)) {
6967 addReplySds(c
,sdsnew("-ERR DISCARD without MULTI\r\n"));
6971 freeClientMultiState(c
);
6972 initClientMultiState(c
);
6973 c
->flags
&= (~REDIS_MULTI
);
6974 addReply(c
,shared
.ok
);
6977 static void execCommand(redisClient
*c
) {
6982 if (!(c
->flags
& REDIS_MULTI
)) {
6983 addReplySds(c
,sdsnew("-ERR EXEC without MULTI\r\n"));
6987 orig_argv
= c
->argv
;
6988 orig_argc
= c
->argc
;
6989 addReplySds(c
,sdscatprintf(sdsempty(),"*%d\r\n",c
->mstate
.count
));
6990 for (j
= 0; j
< c
->mstate
.count
; j
++) {
6991 c
->argc
= c
->mstate
.commands
[j
].argc
;
6992 c
->argv
= c
->mstate
.commands
[j
].argv
;
6993 call(c
,c
->mstate
.commands
[j
].cmd
);
6995 c
->argv
= orig_argv
;
6996 c
->argc
= orig_argc
;
6997 freeClientMultiState(c
);
6998 initClientMultiState(c
);
6999 c
->flags
&= (~REDIS_MULTI
);
7002 /* =========================== Blocking Operations ========================= */
7004 /* Currently Redis blocking operations support is limited to list POP ops,
7005 * so the current implementation is not fully generic, but it is also not
7006 * completely specific so it will not require a rewrite to support new
7007 * kind of blocking operations in the future.
7009 * Still it's important to note that list blocking operations can be already
7010 * used as a notification mechanism in order to implement other blocking
7011 * operations at application level, so there must be a very strong evidence
7012 * of usefulness and generality before new blocking operations are implemented.
7014 * This is how the current blocking POP works, we use BLPOP as example:
7015 * - If the user calls BLPOP and the key exists and contains a non empty list
7016 * then LPOP is called instead. So BLPOP is semantically the same as LPOP
7017 * if there is not to block.
7018 * - If instead BLPOP is called and the key does not exists or the list is
7019 * empty we need to block. In order to do so we remove the notification for
7020 * new data to read in the client socket (so that we'll not serve new
7021 * requests if the blocking request is not served). Also we put the client
7022 * in a dictionary (db->blockingkeys) mapping keys to a list of clients
7023 * blocking for this keys.
7024 * - If a PUSH operation against a key with blocked clients waiting is
7025 * performed, we serve the first in the list: basically instead to push
7026 * the new element inside the list we return it to the (first / oldest)
7027 * blocking client, unblock the client, and remove it form the list.
7029 * The above comment and the source code should be enough in order to understand
7030 * the implementation and modify / fix it later.
7033 /* Set a client in blocking mode for the specified key, with the specified
7035 static void blockForKeys(redisClient
*c
, robj
**keys
, int numkeys
, time_t timeout
) {
7040 c
->blockingkeys
= zmalloc(sizeof(robj
*)*numkeys
);
7041 c
->blockingkeysnum
= numkeys
;
7042 c
->blockingto
= timeout
;
7043 for (j
= 0; j
< numkeys
; j
++) {
7044 /* Add the key in the client structure, to map clients -> keys */
7045 c
->blockingkeys
[j
] = keys
[j
];
7046 incrRefCount(keys
[j
]);
7048 /* And in the other "side", to map keys -> clients */
7049 de
= dictFind(c
->db
->blockingkeys
,keys
[j
]);
7053 /* For every key we take a list of clients blocked for it */
7055 retval
= dictAdd(c
->db
->blockingkeys
,keys
[j
],l
);
7056 incrRefCount(keys
[j
]);
7057 assert(retval
== DICT_OK
);
7059 l
= dictGetEntryVal(de
);
7061 listAddNodeTail(l
,c
);
7063 /* Mark the client as a blocked client */
7064 c
->flags
|= REDIS_BLOCKED
;
7065 server
.blpop_blocked_clients
++;
7068 /* Unblock a client that's waiting in a blocking operation such as BLPOP */
7069 static void unblockClientWaitingData(redisClient
*c
) {
7074 assert(c
->blockingkeys
!= NULL
);
7075 /* The client may wait for multiple keys, so unblock it for every key. */
7076 for (j
= 0; j
< c
->blockingkeysnum
; j
++) {
7077 /* Remove this client from the list of clients waiting for this key. */
7078 de
= dictFind(c
->db
->blockingkeys
,c
->blockingkeys
[j
]);
7080 l
= dictGetEntryVal(de
);
7081 listDelNode(l
,listSearchKey(l
,c
));
7082 /* If the list is empty we need to remove it to avoid wasting memory */
7083 if (listLength(l
) == 0)
7084 dictDelete(c
->db
->blockingkeys
,c
->blockingkeys
[j
]);
7085 decrRefCount(c
->blockingkeys
[j
]);
7087 /* Cleanup the client structure */
7088 zfree(c
->blockingkeys
);
7089 c
->blockingkeys
= NULL
;
7090 c
->flags
&= (~REDIS_BLOCKED
);
7091 server
.blpop_blocked_clients
--;
7092 /* We want to process data if there is some command waiting
7093 * in the input buffer. Note that this is safe even if
7094 * unblockClientWaitingData() gets called from freeClient() because
7095 * freeClient() will be smart enough to call this function
7096 * *after* c->querybuf was set to NULL. */
7097 if (c
->querybuf
&& sdslen(c
->querybuf
) > 0) processInputBuffer(c
);
7100 /* This should be called from any function PUSHing into lists.
7101 * 'c' is the "pushing client", 'key' is the key it is pushing data against,
7102 * 'ele' is the element pushed.
7104 * If the function returns 0 there was no client waiting for a list push
7107 * If the function returns 1 there was a client waiting for a list push
7108 * against this key, the element was passed to this client thus it's not
7109 * needed to actually add it to the list and the caller should return asap. */
7110 static int handleClientsWaitingListPush(redisClient
*c
, robj
*key
, robj
*ele
) {
7111 struct dictEntry
*de
;
7112 redisClient
*receiver
;
7116 de
= dictFind(c
->db
->blockingkeys
,key
);
7117 if (de
== NULL
) return 0;
7118 l
= dictGetEntryVal(de
);
7121 receiver
= ln
->value
;
7123 addReplySds(receiver
,sdsnew("*2\r\n"));
7124 addReplyBulk(receiver
,key
);
7125 addReplyBulk(receiver
,ele
);
7126 unblockClientWaitingData(receiver
);
7130 /* Blocking RPOP/LPOP */
7131 static void blockingPopGenericCommand(redisClient
*c
, int where
) {
7136 for (j
= 1; j
< c
->argc
-1; j
++) {
7137 o
= lookupKeyWrite(c
->db
,c
->argv
[j
]);
7139 if (o
->type
!= REDIS_LIST
) {
7140 addReply(c
,shared
.wrongtypeerr
);
7143 list
*list
= o
->ptr
;
7144 if (listLength(list
) != 0) {
7145 /* If the list contains elements fall back to the usual
7146 * non-blocking POP operation */
7147 robj
*argv
[2], **orig_argv
;
7150 /* We need to alter the command arguments before to call
7151 * popGenericCommand() as the command takes a single key. */
7152 orig_argv
= c
->argv
;
7153 orig_argc
= c
->argc
;
7154 argv
[1] = c
->argv
[j
];
7158 /* Also the return value is different, we need to output
7159 * the multi bulk reply header and the key name. The
7160 * "real" command will add the last element (the value)
7161 * for us. If this souds like an hack to you it's just
7162 * because it is... */
7163 addReplySds(c
,sdsnew("*2\r\n"));
7164 addReplyBulk(c
,argv
[1]);
7165 popGenericCommand(c
,where
);
7167 /* Fix the client structure with the original stuff */
7168 c
->argv
= orig_argv
;
7169 c
->argc
= orig_argc
;
7175 /* If the list is empty or the key does not exists we must block */
7176 timeout
= strtol(c
->argv
[c
->argc
-1]->ptr
,NULL
,10);
7177 if (timeout
> 0) timeout
+= time(NULL
);
7178 blockForKeys(c
,c
->argv
+1,c
->argc
-2,timeout
);
7181 static void blpopCommand(redisClient
*c
) {
7182 blockingPopGenericCommand(c
,REDIS_HEAD
);
7185 static void brpopCommand(redisClient
*c
) {
7186 blockingPopGenericCommand(c
,REDIS_TAIL
);
7189 /* =============================== Replication ============================= */
7191 static int syncWrite(int fd
, char *ptr
, ssize_t size
, int timeout
) {
7192 ssize_t nwritten
, ret
= size
;
7193 time_t start
= time(NULL
);
7197 if (aeWait(fd
,AE_WRITABLE
,1000) & AE_WRITABLE
) {
7198 nwritten
= write(fd
,ptr
,size
);
7199 if (nwritten
== -1) return -1;
7203 if ((time(NULL
)-start
) > timeout
) {
7211 static int syncRead(int fd
, char *ptr
, ssize_t size
, int timeout
) {
7212 ssize_t nread
, totread
= 0;
7213 time_t start
= time(NULL
);
7217 if (aeWait(fd
,AE_READABLE
,1000) & AE_READABLE
) {
7218 nread
= read(fd
,ptr
,size
);
7219 if (nread
== -1) return -1;
7224 if ((time(NULL
)-start
) > timeout
) {
7232 static int syncReadLine(int fd
, char *ptr
, ssize_t size
, int timeout
) {
7239 if (syncRead(fd
,&c
,1,timeout
) == -1) return -1;
7242 if (nread
&& *(ptr
-1) == '\r') *(ptr
-1) = '\0';
7253 static void syncCommand(redisClient
*c
) {
7254 /* ignore SYNC if aleady slave or in monitor mode */
7255 if (c
->flags
& REDIS_SLAVE
) return;
7257 /* SYNC can't be issued when the server has pending data to send to
7258 * the client about already issued commands. We need a fresh reply
7259 * buffer registering the differences between the BGSAVE and the current
7260 * dataset, so that we can copy to other slaves if needed. */
7261 if (listLength(c
->reply
) != 0) {
7262 addReplySds(c
,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
7266 redisLog(REDIS_NOTICE
,"Slave ask for synchronization");
7267 /* Here we need to check if there is a background saving operation
7268 * in progress, or if it is required to start one */
7269 if (server
.bgsavechildpid
!= -1) {
7270 /* Ok a background save is in progress. Let's check if it is a good
7271 * one for replication, i.e. if there is another slave that is
7272 * registering differences since the server forked to save */
7277 listRewind(server
.slaves
,&li
);
7278 while((ln
= listNext(&li
))) {
7280 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) break;
7283 /* Perfect, the server is already registering differences for
7284 * another slave. Set the right state, and copy the buffer. */
7285 listRelease(c
->reply
);
7286 c
->reply
= listDup(slave
->reply
);
7287 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
7288 redisLog(REDIS_NOTICE
,"Waiting for end of BGSAVE for SYNC");
7290 /* No way, we need to wait for the next BGSAVE in order to
7291 * register differences */
7292 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
7293 redisLog(REDIS_NOTICE
,"Waiting for next BGSAVE for SYNC");
7296 /* Ok we don't have a BGSAVE in progress, let's start one */
7297 redisLog(REDIS_NOTICE
,"Starting BGSAVE for SYNC");
7298 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
7299 redisLog(REDIS_NOTICE
,"Replication failed, can't BGSAVE");
7300 addReplySds(c
,sdsnew("-ERR Unalbe to perform background save\r\n"));
7303 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
7306 c
->flags
|= REDIS_SLAVE
;
7308 listAddNodeTail(server
.slaves
,c
);
7312 static void sendBulkToSlave(aeEventLoop
*el
, int fd
, void *privdata
, int mask
) {
7313 redisClient
*slave
= privdata
;
7315 REDIS_NOTUSED(mask
);
7316 char buf
[REDIS_IOBUF_LEN
];
7317 ssize_t nwritten
, buflen
;
7319 if (slave
->repldboff
== 0) {
7320 /* Write the bulk write count before to transfer the DB. In theory here
7321 * we don't know how much room there is in the output buffer of the
7322 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
7323 * operations) will never be smaller than the few bytes we need. */
7326 bulkcount
= sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
7328 if (write(fd
,bulkcount
,sdslen(bulkcount
)) != (signed)sdslen(bulkcount
))
7336 lseek(slave
->repldbfd
,slave
->repldboff
,SEEK_SET
);
7337 buflen
= read(slave
->repldbfd
,buf
,REDIS_IOBUF_LEN
);
7339 redisLog(REDIS_WARNING
,"Read error sending DB to slave: %s",
7340 (buflen
== 0) ? "premature EOF" : strerror(errno
));
7344 if ((nwritten
= write(fd
,buf
,buflen
)) == -1) {
7345 redisLog(REDIS_VERBOSE
,"Write error sending DB to slave: %s",
7350 slave
->repldboff
+= nwritten
;
7351 if (slave
->repldboff
== slave
->repldbsize
) {
7352 close(slave
->repldbfd
);
7353 slave
->repldbfd
= -1;
7354 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
7355 slave
->replstate
= REDIS_REPL_ONLINE
;
7356 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
,
7357 sendReplyToClient
, slave
) == AE_ERR
) {
7361 addReplySds(slave
,sdsempty());
7362 redisLog(REDIS_NOTICE
,"Synchronization with slave succeeded");
7366 /* This function is called at the end of every backgrond saving.
7367 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
7368 * otherwise REDIS_ERR is passed to the function.
7370 * The goal of this function is to handle slaves waiting for a successful
7371 * background saving in order to perform non-blocking synchronization. */
7372 static void updateSlavesWaitingBgsave(int bgsaveerr
) {
7374 int startbgsave
= 0;
7377 listRewind(server
.slaves
,&li
);
7378 while((ln
= listNext(&li
))) {
7379 redisClient
*slave
= ln
->value
;
7381 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
) {
7383 slave
->replstate
= REDIS_REPL_WAIT_BGSAVE_END
;
7384 } else if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_END
) {
7385 struct redis_stat buf
;
7387 if (bgsaveerr
!= REDIS_OK
) {
7389 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE child returned an error");
7392 if ((slave
->repldbfd
= open(server
.dbfilename
,O_RDONLY
)) == -1 ||
7393 redis_fstat(slave
->repldbfd
,&buf
) == -1) {
7395 redisLog(REDIS_WARNING
,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno
));
7398 slave
->repldboff
= 0;
7399 slave
->repldbsize
= buf
.st_size
;
7400 slave
->replstate
= REDIS_REPL_SEND_BULK
;
7401 aeDeleteFileEvent(server
.el
,slave
->fd
,AE_WRITABLE
);
7402 if (aeCreateFileEvent(server
.el
, slave
->fd
, AE_WRITABLE
, sendBulkToSlave
, slave
) == AE_ERR
) {
7409 if (rdbSaveBackground(server
.dbfilename
) != REDIS_OK
) {
7412 listRewind(server
.slaves
,&li
);
7413 redisLog(REDIS_WARNING
,"SYNC failed. BGSAVE failed");
7414 while((ln
= listNext(&li
))) {
7415 redisClient
*slave
= ln
->value
;
7417 if (slave
->replstate
== REDIS_REPL_WAIT_BGSAVE_START
)
7424 static int syncWithMaster(void) {
7425 char buf
[1024], tmpfile
[256], authcmd
[1024];
7427 int fd
= anetTcpConnect(NULL
,server
.masterhost
,server
.masterport
);
7428 int dfd
, maxtries
= 5;
7431 redisLog(REDIS_WARNING
,"Unable to connect to MASTER: %s",
7436 /* AUTH with the master if required. */
7437 if(server
.masterauth
) {
7438 snprintf(authcmd
, 1024, "AUTH %s\r\n", server
.masterauth
);
7439 if (syncWrite(fd
, authcmd
, strlen(server
.masterauth
)+7, 5) == -1) {
7441 redisLog(REDIS_WARNING
,"Unable to AUTH to MASTER: %s",
7445 /* Read the AUTH result. */
7446 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
7448 redisLog(REDIS_WARNING
,"I/O error reading auth result from MASTER: %s",
7452 if (buf
[0] != '+') {
7454 redisLog(REDIS_WARNING
,"Cannot AUTH to MASTER, is the masterauth password correct?");
7459 /* Issue the SYNC command */
7460 if (syncWrite(fd
,"SYNC \r\n",7,5) == -1) {
7462 redisLog(REDIS_WARNING
,"I/O error writing to MASTER: %s",
7466 /* Read the bulk write count */
7467 if (syncReadLine(fd
,buf
,1024,3600) == -1) {
7469 redisLog(REDIS_WARNING
,"I/O error reading bulk count from MASTER: %s",
7473 if (buf
[0] != '$') {
7475 redisLog(REDIS_WARNING
,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
7478 dumpsize
= strtol(buf
+1,NULL
,10);
7479 redisLog(REDIS_NOTICE
,"Receiving %ld bytes data dump from MASTER",dumpsize
);
7480 /* Read the bulk write data on a temp file */
7482 snprintf(tmpfile
,256,
7483 "temp-%d.%ld.rdb",(int)time(NULL
),(long int)getpid());
7484 dfd
= open(tmpfile
,O_CREAT
|O_WRONLY
|O_EXCL
,0644);
7485 if (dfd
!= -1) break;
7490 redisLog(REDIS_WARNING
,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno
));
7494 int nread
, nwritten
;
7496 nread
= read(fd
,buf
,(dumpsize
< 1024)?dumpsize
:1024);
7498 redisLog(REDIS_WARNING
,"I/O error trying to sync with MASTER: %s",
7504 nwritten
= write(dfd
,buf
,nread
);
7505 if (nwritten
== -1) {
7506 redisLog(REDIS_WARNING
,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno
));
7514 if (rename(tmpfile
,server
.dbfilename
) == -1) {
7515 redisLog(REDIS_WARNING
,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno
));
7521 if (rdbLoad(server
.dbfilename
) != REDIS_OK
) {
7522 redisLog(REDIS_WARNING
,"Failed trying to load the MASTER synchronization DB from disk");
7526 server
.master
= createClient(fd
);
7527 server
.master
->flags
|= REDIS_MASTER
;
7528 server
.master
->authenticated
= 1;
7529 server
.replstate
= REDIS_REPL_CONNECTED
;
7533 static void slaveofCommand(redisClient
*c
) {
7534 if (!strcasecmp(c
->argv
[1]->ptr
,"no") &&
7535 !strcasecmp(c
->argv
[2]->ptr
,"one")) {
7536 if (server
.masterhost
) {
7537 sdsfree(server
.masterhost
);
7538 server
.masterhost
= NULL
;
7539 if (server
.master
) freeClient(server
.master
);
7540 server
.replstate
= REDIS_REPL_NONE
;
7541 redisLog(REDIS_NOTICE
,"MASTER MODE enabled (user request)");
7544 sdsfree(server
.masterhost
);
7545 server
.masterhost
= sdsdup(c
->argv
[1]->ptr
);
7546 server
.masterport
= atoi(c
->argv
[2]->ptr
);
7547 if (server
.master
) freeClient(server
.master
);
7548 server
.replstate
= REDIS_REPL_CONNECT
;
7549 redisLog(REDIS_NOTICE
,"SLAVE OF %s:%d enabled (user request)",
7550 server
.masterhost
, server
.masterport
);
7552 addReply(c
,shared
.ok
);
7555 /* ============================ Maxmemory directive ======================== */
7557 /* Try to free one object form the pre-allocated objects free list.
7558 * This is useful under low mem conditions as by default we take 1 million
7559 * free objects allocated. On success REDIS_OK is returned, otherwise
7561 static int tryFreeOneObjectFromFreelist(void) {
7564 if (server
.vm_enabled
) pthread_mutex_lock(&server
.obj_freelist_mutex
);
7565 if (listLength(server
.objfreelist
)) {
7566 listNode
*head
= listFirst(server
.objfreelist
);
7567 o
= listNodeValue(head
);
7568 listDelNode(server
.objfreelist
,head
);
7569 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
7573 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
7578 /* This function gets called when 'maxmemory' is set on the config file to limit
7579 * the max memory used by the server, and we are out of memory.
7580 * This function will try to, in order:
7582 * - Free objects from the free list
7583 * - Try to remove keys with an EXPIRE set
7585 * It is not possible to free enough memory to reach used-memory < maxmemory
7586 * the server will start refusing commands that will enlarge even more the
7589 static void freeMemoryIfNeeded(void) {
7590 while (server
.maxmemory
&& zmalloc_used_memory() > server
.maxmemory
) {
7591 int j
, k
, freed
= 0;
7593 if (tryFreeOneObjectFromFreelist() == REDIS_OK
) continue;
7594 for (j
= 0; j
< server
.dbnum
; j
++) {
7596 robj
*minkey
= NULL
;
7597 struct dictEntry
*de
;
7599 if (dictSize(server
.db
[j
].expires
)) {
7601 /* From a sample of three keys drop the one nearest to
7602 * the natural expire */
7603 for (k
= 0; k
< 3; k
++) {
7606 de
= dictGetRandomKey(server
.db
[j
].expires
);
7607 t
= (time_t) dictGetEntryVal(de
);
7608 if (minttl
== -1 || t
< minttl
) {
7609 minkey
= dictGetEntryKey(de
);
7613 deleteKey(server
.db
+j
,minkey
);
7616 if (!freed
) return; /* nothing to free... */
7620 /* ============================== Append Only file ========================== */
7622 static void feedAppendOnlyFile(struct redisCommand
*cmd
, int dictid
, robj
**argv
, int argc
) {
7623 sds buf
= sdsempty();
7629 /* The DB this command was targetting is not the same as the last command
7630 * we appendend. To issue a SELECT command is needed. */
7631 if (dictid
!= server
.appendseldb
) {
7634 snprintf(seldb
,sizeof(seldb
),"%d",dictid
);
7635 buf
= sdscatprintf(buf
,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
7636 (unsigned long)strlen(seldb
),seldb
);
7637 server
.appendseldb
= dictid
;
7640 /* "Fix" the argv vector if the command is EXPIRE. We want to translate
7641 * EXPIREs into EXPIREATs calls */
7642 if (cmd
->proc
== expireCommand
) {
7645 tmpargv
[0] = createStringObject("EXPIREAT",8);
7646 tmpargv
[1] = argv
[1];
7647 incrRefCount(argv
[1]);
7648 when
= time(NULL
)+strtol(argv
[2]->ptr
,NULL
,10);
7649 tmpargv
[2] = createObject(REDIS_STRING
,
7650 sdscatprintf(sdsempty(),"%ld",when
));
7654 /* Append the actual command */
7655 buf
= sdscatprintf(buf
,"*%d\r\n",argc
);
7656 for (j
= 0; j
< argc
; j
++) {
7659 o
= getDecodedObject(o
);
7660 buf
= sdscatprintf(buf
,"$%lu\r\n",(unsigned long)sdslen(o
->ptr
));
7661 buf
= sdscatlen(buf
,o
->ptr
,sdslen(o
->ptr
));
7662 buf
= sdscatlen(buf
,"\r\n",2);
7666 /* Free the objects from the modified argv for EXPIREAT */
7667 if (cmd
->proc
== expireCommand
) {
7668 for (j
= 0; j
< 3; j
++)
7669 decrRefCount(argv
[j
]);
7672 /* We want to perform a single write. This should be guaranteed atomic
7673 * at least if the filesystem we are writing is a real physical one.
7674 * While this will save us against the server being killed I don't think
7675 * there is much to do about the whole server stopping for power problems
7677 nwritten
= write(server
.appendfd
,buf
,sdslen(buf
));
7678 if (nwritten
!= (signed)sdslen(buf
)) {
7679 /* Ooops, we are in troubles. The best thing to do for now is
7680 * to simply exit instead to give the illusion that everything is
7681 * working as expected. */
7682 if (nwritten
== -1) {
7683 redisLog(REDIS_WARNING
,"Exiting on error writing to the append-only file: %s",strerror(errno
));
7685 redisLog(REDIS_WARNING
,"Exiting on short write while writing to the append-only file: %s",strerror(errno
));
7689 /* If a background append only file rewriting is in progress we want to
7690 * accumulate the differences between the child DB and the current one
7691 * in a buffer, so that when the child process will do its work we
7692 * can append the differences to the new append only file. */
7693 if (server
.bgrewritechildpid
!= -1)
7694 server
.bgrewritebuf
= sdscatlen(server
.bgrewritebuf
,buf
,sdslen(buf
));
7698 if (server
.appendfsync
== APPENDFSYNC_ALWAYS
||
7699 (server
.appendfsync
== APPENDFSYNC_EVERYSEC
&&
7700 now
-server
.lastfsync
> 1))
7702 fsync(server
.appendfd
); /* Let's try to get this data on the disk */
7703 server
.lastfsync
= now
;
7707 /* In Redis commands are always executed in the context of a client, so in
7708 * order to load the append only file we need to create a fake client. */
7709 static struct redisClient
*createFakeClient(void) {
7710 struct redisClient
*c
= zmalloc(sizeof(*c
));
7714 c
->querybuf
= sdsempty();
7718 /* We set the fake client as a slave waiting for the synchronization
7719 * so that Redis will not try to send replies to this client. */
7720 c
->replstate
= REDIS_REPL_WAIT_BGSAVE_START
;
7721 c
->reply
= listCreate();
7722 listSetFreeMethod(c
->reply
,decrRefCount
);
7723 listSetDupMethod(c
->reply
,dupClientReplyValue
);
7727 static void freeFakeClient(struct redisClient
*c
) {
7728 sdsfree(c
->querybuf
);
7729 listRelease(c
->reply
);
7733 /* Replay the append log file. On error REDIS_OK is returned. On non fatal
7734 * error (the append only file is zero-length) REDIS_ERR is returned. On
7735 * fatal error an error message is logged and the program exists. */
7736 int loadAppendOnlyFile(char *filename
) {
7737 struct redisClient
*fakeClient
;
7738 FILE *fp
= fopen(filename
,"r");
7739 struct redis_stat sb
;
7740 unsigned long long loadedkeys
= 0;
7742 if (redis_fstat(fileno(fp
),&sb
) != -1 && sb
.st_size
== 0)
7746 redisLog(REDIS_WARNING
,"Fatal error: can't open the append log file for reading: %s",strerror(errno
));
7750 fakeClient
= createFakeClient();
7757 struct redisCommand
*cmd
;
7759 if (fgets(buf
,sizeof(buf
),fp
) == NULL
) {
7765 if (buf
[0] != '*') goto fmterr
;
7767 argv
= zmalloc(sizeof(robj
*)*argc
);
7768 for (j
= 0; j
< argc
; j
++) {
7769 if (fgets(buf
,sizeof(buf
),fp
) == NULL
) goto readerr
;
7770 if (buf
[0] != '$') goto fmterr
;
7771 len
= strtol(buf
+1,NULL
,10);
7772 argsds
= sdsnewlen(NULL
,len
);
7773 if (len
&& fread(argsds
,len
,1,fp
) == 0) goto fmterr
;
7774 argv
[j
] = createObject(REDIS_STRING
,argsds
);
7775 if (fread(buf
,2,1,fp
) == 0) goto fmterr
; /* discard CRLF */
7778 /* Command lookup */
7779 cmd
= lookupCommand(argv
[0]->ptr
);
7781 redisLog(REDIS_WARNING
,"Unknown command '%s' reading the append only file", argv
[0]->ptr
);
7784 /* Try object sharing and encoding */
7785 if (server
.shareobjects
) {
7787 for(j
= 1; j
< argc
; j
++)
7788 argv
[j
] = tryObjectSharing(argv
[j
]);
7790 if (cmd
->flags
& REDIS_CMD_BULK
)
7791 tryObjectEncoding(argv
[argc
-1]);
7792 /* Run the command in the context of a fake client */
7793 fakeClient
->argc
= argc
;
7794 fakeClient
->argv
= argv
;
7795 cmd
->proc(fakeClient
);
7796 /* Discard the reply objects list from the fake client */
7797 while(listLength(fakeClient
->reply
))
7798 listDelNode(fakeClient
->reply
,listFirst(fakeClient
->reply
));
7799 /* Clean up, ready for the next command */
7800 for (j
= 0; j
< argc
; j
++) decrRefCount(argv
[j
]);
7802 /* Handle swapping while loading big datasets when VM is on */
7804 if (server
.vm_enabled
&& (loadedkeys
% 5000) == 0) {
7805 while (zmalloc_used_memory() > server
.vm_max_memory
) {
7806 if (vmSwapOneObjectBlocking() == REDIS_ERR
) break;
7811 freeFakeClient(fakeClient
);
7816 redisLog(REDIS_WARNING
,"Unexpected end of file reading the append only file");
7818 redisLog(REDIS_WARNING
,"Unrecoverable error reading the append only file: %s", strerror(errno
));
7822 redisLog(REDIS_WARNING
,"Bad file format reading the append only file");
7826 /* Write an object into a file in the bulk format $<count>\r\n<payload>\r\n */
7827 static int fwriteBulkObject(FILE *fp
, robj
*obj
) {
7831 /* Avoid the incr/decr ref count business if possible to help
7832 * copy-on-write (we are often in a child process when this function
7834 * Also makes sure that key objects don't get incrRefCount-ed when VM
7836 if (obj
->encoding
!= REDIS_ENCODING_RAW
) {
7837 obj
= getDecodedObject(obj
);
7840 snprintf(buf
,sizeof(buf
),"$%ld\r\n",(long)sdslen(obj
->ptr
));
7841 if (fwrite(buf
,strlen(buf
),1,fp
) == 0) goto err
;
7842 if (sdslen(obj
->ptr
) && fwrite(obj
->ptr
,sdslen(obj
->ptr
),1,fp
) == 0)
7844 if (fwrite("\r\n",2,1,fp
) == 0) goto err
;
7845 if (decrrc
) decrRefCount(obj
);
7848 if (decrrc
) decrRefCount(obj
);
7852 /* Write binary-safe string into a file in the bulkformat
7853 * $<count>\r\n<payload>\r\n */
7854 static int fwriteBulkString(FILE *fp
, char *s
, unsigned long len
) {
7857 snprintf(buf
,sizeof(buf
),"$%ld\r\n",(unsigned long)len
);
7858 if (fwrite(buf
,strlen(buf
),1,fp
) == 0) return 0;
7859 if (len
&& fwrite(s
,len
,1,fp
) == 0) return 0;
7860 if (fwrite("\r\n",2,1,fp
) == 0) return 0;
7864 /* Write a double value in bulk format $<count>\r\n<payload>\r\n */
7865 static int fwriteBulkDouble(FILE *fp
, double d
) {
7866 char buf
[128], dbuf
[128];
7868 snprintf(dbuf
,sizeof(dbuf
),"%.17g\r\n",d
);
7869 snprintf(buf
,sizeof(buf
),"$%lu\r\n",(unsigned long)strlen(dbuf
)-2);
7870 if (fwrite(buf
,strlen(buf
),1,fp
) == 0) return 0;
7871 if (fwrite(dbuf
,strlen(dbuf
),1,fp
) == 0) return 0;
7875 /* Write a long value in bulk format $<count>\r\n<payload>\r\n */
7876 static int fwriteBulkLong(FILE *fp
, long l
) {
7877 char buf
[128], lbuf
[128];
7879 snprintf(lbuf
,sizeof(lbuf
),"%ld\r\n",l
);
7880 snprintf(buf
,sizeof(buf
),"$%lu\r\n",(unsigned long)strlen(lbuf
)-2);
7881 if (fwrite(buf
,strlen(buf
),1,fp
) == 0) return 0;
7882 if (fwrite(lbuf
,strlen(lbuf
),1,fp
) == 0) return 0;
7886 /* Write a sequence of commands able to fully rebuild the dataset into
7887 * "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
7888 static int rewriteAppendOnlyFile(char *filename
) {
7889 dictIterator
*di
= NULL
;
7894 time_t now
= time(NULL
);
7896 /* Note that we have to use a different temp name here compared to the
7897 * one used by rewriteAppendOnlyFileBackground() function. */
7898 snprintf(tmpfile
,256,"temp-rewriteaof-%d.aof", (int) getpid());
7899 fp
= fopen(tmpfile
,"w");
7901 redisLog(REDIS_WARNING
, "Failed rewriting the append only file: %s", strerror(errno
));
7904 for (j
= 0; j
< server
.dbnum
; j
++) {
7905 char selectcmd
[] = "*2\r\n$6\r\nSELECT\r\n";
7906 redisDb
*db
= server
.db
+j
;
7908 if (dictSize(d
) == 0) continue;
7909 di
= dictGetIterator(d
);
7915 /* SELECT the new DB */
7916 if (fwrite(selectcmd
,sizeof(selectcmd
)-1,1,fp
) == 0) goto werr
;
7917 if (fwriteBulkLong(fp
,j
) == 0) goto werr
;
7919 /* Iterate this DB writing every entry */
7920 while((de
= dictNext(di
)) != NULL
) {
7925 key
= dictGetEntryKey(de
);
7926 /* If the value for this key is swapped, load a preview in memory.
7927 * We use a "swapped" flag to remember if we need to free the
7928 * value object instead to just increment the ref count anyway
7929 * in order to avoid copy-on-write of pages if we are forked() */
7930 if (!server
.vm_enabled
|| key
->storage
== REDIS_VM_MEMORY
||
7931 key
->storage
== REDIS_VM_SWAPPING
) {
7932 o
= dictGetEntryVal(de
);
7935 o
= vmPreviewObject(key
);
7938 expiretime
= getExpire(db
,key
);
7940 /* Save the key and associated value */
7941 if (o
->type
== REDIS_STRING
) {
7942 /* Emit a SET command */
7943 char cmd
[]="*3\r\n$3\r\nSET\r\n";
7944 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
7946 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
7947 if (fwriteBulkObject(fp
,o
) == 0) goto werr
;
7948 } else if (o
->type
== REDIS_LIST
) {
7949 /* Emit the RPUSHes needed to rebuild the list */
7950 list
*list
= o
->ptr
;
7954 listRewind(list
,&li
);
7955 while((ln
= listNext(&li
))) {
7956 char cmd
[]="*3\r\n$5\r\nRPUSH\r\n";
7957 robj
*eleobj
= listNodeValue(ln
);
7959 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
7960 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
7961 if (fwriteBulkObject(fp
,eleobj
) == 0) goto werr
;
7963 } else if (o
->type
== REDIS_SET
) {
7964 /* Emit the SADDs needed to rebuild the set */
7966 dictIterator
*di
= dictGetIterator(set
);
7969 while((de
= dictNext(di
)) != NULL
) {
7970 char cmd
[]="*3\r\n$4\r\nSADD\r\n";
7971 robj
*eleobj
= dictGetEntryKey(de
);
7973 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
7974 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
7975 if (fwriteBulkObject(fp
,eleobj
) == 0) goto werr
;
7977 dictReleaseIterator(di
);
7978 } else if (o
->type
== REDIS_ZSET
) {
7979 /* Emit the ZADDs needed to rebuild the sorted set */
7981 dictIterator
*di
= dictGetIterator(zs
->dict
);
7984 while((de
= dictNext(di
)) != NULL
) {
7985 char cmd
[]="*4\r\n$4\r\nZADD\r\n";
7986 robj
*eleobj
= dictGetEntryKey(de
);
7987 double *score
= dictGetEntryVal(de
);
7989 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
7990 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
7991 if (fwriteBulkDouble(fp
,*score
) == 0) goto werr
;
7992 if (fwriteBulkObject(fp
,eleobj
) == 0) goto werr
;
7994 dictReleaseIterator(di
);
7995 } else if (o
->type
== REDIS_HASH
) {
7996 char cmd
[]="*4\r\n$4\r\nHSET\r\n";
7998 /* Emit the HSETs needed to rebuild the hash */
7999 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
8000 unsigned char *p
= zipmapRewind(o
->ptr
);
8001 unsigned char *field
, *val
;
8002 unsigned int flen
, vlen
;
8004 while((p
= zipmapNext(p
,&field
,&flen
,&val
,&vlen
)) != NULL
) {
8005 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
8006 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
8007 if (fwriteBulkString(fp
,(char*)field
,flen
) == -1)
8009 if (fwriteBulkString(fp
,(char*)val
,vlen
) == -1)
8013 dictIterator
*di
= dictGetIterator(o
->ptr
);
8016 while((de
= dictNext(di
)) != NULL
) {
8017 robj
*field
= dictGetEntryKey(de
);
8018 robj
*val
= dictGetEntryVal(de
);
8020 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
8021 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
8022 if (fwriteBulkObject(fp
,field
) == -1) return -1;
8023 if (fwriteBulkObject(fp
,val
) == -1) return -1;
8025 dictReleaseIterator(di
);
8030 /* Save the expire time */
8031 if (expiretime
!= -1) {
8032 char cmd
[]="*3\r\n$8\r\nEXPIREAT\r\n";
8033 /* If this key is already expired skip it */
8034 if (expiretime
< now
) continue;
8035 if (fwrite(cmd
,sizeof(cmd
)-1,1,fp
) == 0) goto werr
;
8036 if (fwriteBulkObject(fp
,key
) == 0) goto werr
;
8037 if (fwriteBulkLong(fp
,expiretime
) == 0) goto werr
;
8039 if (swapped
) decrRefCount(o
);
8041 dictReleaseIterator(di
);
8044 /* Make sure data will not remain on the OS's output buffers */
8049 /* Use RENAME to make sure the DB file is changed atomically only
8050 * if the generate DB file is ok. */
8051 if (rename(tmpfile
,filename
) == -1) {
8052 redisLog(REDIS_WARNING
,"Error moving temp append only file on the final destination: %s", strerror(errno
));
8056 redisLog(REDIS_NOTICE
,"SYNC append only file rewrite performed");
8062 redisLog(REDIS_WARNING
,"Write error writing append only file on disk: %s", strerror(errno
));
8063 if (di
) dictReleaseIterator(di
);
8067 /* This is how rewriting of the append only file in background works:
8069 * 1) The user calls BGREWRITEAOF
8070 * 2) Redis calls this function, that forks():
8071 * 2a) the child rewrite the append only file in a temp file.
8072 * 2b) the parent accumulates differences in server.bgrewritebuf.
8073 * 3) When the child finished '2a' exists.
8074 * 4) The parent will trap the exit code, if it's OK, will append the
8075 * data accumulated into server.bgrewritebuf into the temp file, and
8076 * finally will rename(2) the temp file in the actual file name.
8077 * The the new file is reopened as the new append only file. Profit!
8079 static int rewriteAppendOnlyFileBackground(void) {
8082 if (server
.bgrewritechildpid
!= -1) return REDIS_ERR
;
8083 if (server
.vm_enabled
) waitEmptyIOJobsQueue();
8084 if ((childpid
= fork()) == 0) {
8088 if (server
.vm_enabled
) vmReopenSwapFile();
8090 snprintf(tmpfile
,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
8091 if (rewriteAppendOnlyFile(tmpfile
) == REDIS_OK
) {
8098 if (childpid
== -1) {
8099 redisLog(REDIS_WARNING
,
8100 "Can't rewrite append only file in background: fork: %s",
8104 redisLog(REDIS_NOTICE
,
8105 "Background append only file rewriting started by pid %d",childpid
);
8106 server
.bgrewritechildpid
= childpid
;
8107 /* We set appendseldb to -1 in order to force the next call to the
8108 * feedAppendOnlyFile() to issue a SELECT command, so the differences
8109 * accumulated by the parent into server.bgrewritebuf will start
8110 * with a SELECT statement and it will be safe to merge. */
8111 server
.appendseldb
= -1;
8114 return REDIS_OK
; /* unreached */
8117 static void bgrewriteaofCommand(redisClient
*c
) {
8118 if (server
.bgrewritechildpid
!= -1) {
8119 addReplySds(c
,sdsnew("-ERR background append only file rewriting already in progress\r\n"));
8122 if (rewriteAppendOnlyFileBackground() == REDIS_OK
) {
8123 char *status
= "+Background append only file rewriting started\r\n";
8124 addReplySds(c
,sdsnew(status
));
8126 addReply(c
,shared
.err
);
8130 static void aofRemoveTempFile(pid_t childpid
) {
8133 snprintf(tmpfile
,256,"temp-rewriteaof-bg-%d.aof", (int) childpid
);
8137 /* Virtual Memory is composed mainly of two subsystems:
8138 * - Blocking Virutal Memory
8139 * - Threaded Virtual Memory I/O
8140 * The two parts are not fully decoupled, but functions are split among two
8141 * different sections of the source code (delimited by comments) in order to
8142 * make more clear what functionality is about the blocking VM and what about
8143 * the threaded (not blocking) VM.
8147 * Redis VM is a blocking VM (one that blocks reading swapped values from
8148 * disk into memory when a value swapped out is needed in memory) that is made
8149 * unblocking by trying to examine the command argument vector in order to
8150 * load in background values that will likely be needed in order to exec
8151 * the command. The command is executed only once all the relevant keys
8152 * are loaded into memory.
8154 * This basically is almost as simple of a blocking VM, but almost as parallel
8155 * as a fully non-blocking VM.
8158 /* =================== Virtual Memory - Blocking Side ====================== */
8160 /* substitute the first occurrence of '%p' with the process pid in the
8161 * swap file name. */
8162 static void expandVmSwapFilename(void) {
8163 char *p
= strstr(server
.vm_swap_file
,"%p");
8169 new = sdscat(new,server
.vm_swap_file
);
8170 new = sdscatprintf(new,"%ld",(long) getpid());
8171 new = sdscat(new,p
+2);
8172 zfree(server
.vm_swap_file
);
8173 server
.vm_swap_file
= new;
8176 static void vmInit(void) {
8181 if (server
.vm_max_threads
!= 0)
8182 zmalloc_enable_thread_safeness(); /* we need thread safe zmalloc() */
8184 expandVmSwapFilename();
8185 redisLog(REDIS_NOTICE
,"Using '%s' as swap file",server
.vm_swap_file
);
8186 if ((server
.vm_fp
= fopen(server
.vm_swap_file
,"r+b")) == NULL
) {
8187 server
.vm_fp
= fopen(server
.vm_swap_file
,"w+b");
8189 if (server
.vm_fp
== NULL
) {
8190 redisLog(REDIS_WARNING
,
8191 "Impossible to open the swap file: %s. Exiting.",
8195 server
.vm_fd
= fileno(server
.vm_fp
);
8196 server
.vm_next_page
= 0;
8197 server
.vm_near_pages
= 0;
8198 server
.vm_stats_used_pages
= 0;
8199 server
.vm_stats_swapped_objects
= 0;
8200 server
.vm_stats_swapouts
= 0;
8201 server
.vm_stats_swapins
= 0;
8202 totsize
= server
.vm_pages
*server
.vm_page_size
;
8203 redisLog(REDIS_NOTICE
,"Allocating %lld bytes of swap file",totsize
);
8204 if (ftruncate(server
.vm_fd
,totsize
) == -1) {
8205 redisLog(REDIS_WARNING
,"Can't ftruncate swap file: %s. Exiting.",
8209 redisLog(REDIS_NOTICE
,"Swap file allocated with success");
8211 server
.vm_bitmap
= zmalloc((server
.vm_pages
+7)/8);
8212 redisLog(REDIS_VERBOSE
,"Allocated %lld bytes page table for %lld pages",
8213 (long long) (server
.vm_pages
+7)/8, server
.vm_pages
);
8214 memset(server
.vm_bitmap
,0,(server
.vm_pages
+7)/8);
8216 /* Initialize threaded I/O (used by Virtual Memory) */
8217 server
.io_newjobs
= listCreate();
8218 server
.io_processing
= listCreate();
8219 server
.io_processed
= listCreate();
8220 server
.io_ready_clients
= listCreate();
8221 pthread_mutex_init(&server
.io_mutex
,NULL
);
8222 pthread_mutex_init(&server
.obj_freelist_mutex
,NULL
);
8223 pthread_mutex_init(&server
.io_swapfile_mutex
,NULL
);
8224 server
.io_active_threads
= 0;
8225 if (pipe(pipefds
) == -1) {
8226 redisLog(REDIS_WARNING
,"Unable to intialized VM: pipe(2): %s. Exiting."
8230 server
.io_ready_pipe_read
= pipefds
[0];
8231 server
.io_ready_pipe_write
= pipefds
[1];
8232 redisAssert(anetNonBlock(NULL
,server
.io_ready_pipe_read
) != ANET_ERR
);
8233 /* LZF requires a lot of stack */
8234 pthread_attr_init(&server
.io_threads_attr
);
8235 pthread_attr_getstacksize(&server
.io_threads_attr
, &stacksize
);
8236 while (stacksize
< REDIS_THREAD_STACK_SIZE
) stacksize
*= 2;
8237 pthread_attr_setstacksize(&server
.io_threads_attr
, stacksize
);
8238 /* Listen for events in the threaded I/O pipe */
8239 if (aeCreateFileEvent(server
.el
, server
.io_ready_pipe_read
, AE_READABLE
,
8240 vmThreadedIOCompletedJob
, NULL
) == AE_ERR
)
8241 oom("creating file event");
8244 /* Mark the page as used */
8245 static void vmMarkPageUsed(off_t page
) {
8246 off_t byte
= page
/8;
8248 redisAssert(vmFreePage(page
) == 1);
8249 server
.vm_bitmap
[byte
] |= 1<<bit
;
8252 /* Mark N contiguous pages as used, with 'page' being the first. */
8253 static void vmMarkPagesUsed(off_t page
, off_t count
) {
8256 for (j
= 0; j
< count
; j
++)
8257 vmMarkPageUsed(page
+j
);
8258 server
.vm_stats_used_pages
+= count
;
8259 redisLog(REDIS_DEBUG
,"Mark USED pages: %lld pages at %lld\n",
8260 (long long)count
, (long long)page
);
8263 /* Mark the page as free */
8264 static void vmMarkPageFree(off_t page
) {
8265 off_t byte
= page
/8;
8267 redisAssert(vmFreePage(page
) == 0);
8268 server
.vm_bitmap
[byte
] &= ~(1<<bit
);
8271 /* Mark N contiguous pages as free, with 'page' being the first. */
8272 static void vmMarkPagesFree(off_t page
, off_t count
) {
8275 for (j
= 0; j
< count
; j
++)
8276 vmMarkPageFree(page
+j
);
8277 server
.vm_stats_used_pages
-= count
;
8278 redisLog(REDIS_DEBUG
,"Mark FREE pages: %lld pages at %lld\n",
8279 (long long)count
, (long long)page
);
8282 /* Test if the page is free */
8283 static int vmFreePage(off_t page
) {
8284 off_t byte
= page
/8;
8286 return (server
.vm_bitmap
[byte
] & (1<<bit
)) == 0;
8289 /* Find N contiguous free pages storing the first page of the cluster in *first.
8290 * Returns REDIS_OK if it was able to find N contiguous pages, otherwise
8291 * REDIS_ERR is returned.
8293 * This function uses a simple algorithm: we try to allocate
8294 * REDIS_VM_MAX_NEAR_PAGES sequentially, when we reach this limit we start
8295 * again from the start of the swap file searching for free spaces.
8297 * If it looks pretty clear that there are no free pages near our offset
8298 * we try to find less populated places doing a forward jump of
8299 * REDIS_VM_MAX_RANDOM_JUMP, then we start scanning again a few pages
8300 * without hurry, and then we jump again and so forth...
8302 * This function can be improved using a free list to avoid to guess
8303 * too much, since we could collect data about freed pages.
8305 * note: I implemented this function just after watching an episode of
8306 * Battlestar Galactica, where the hybrid was continuing to say "JUMP!"
8308 static int vmFindContiguousPages(off_t
*first
, off_t n
) {
8309 off_t base
, offset
= 0, since_jump
= 0, numfree
= 0;
8311 if (server
.vm_near_pages
== REDIS_VM_MAX_NEAR_PAGES
) {
8312 server
.vm_near_pages
= 0;
8313 server
.vm_next_page
= 0;
8315 server
.vm_near_pages
++; /* Yet another try for pages near to the old ones */
8316 base
= server
.vm_next_page
;
8318 while(offset
< server
.vm_pages
) {
8319 off_t
this = base
+offset
;
8321 /* If we overflow, restart from page zero */
8322 if (this >= server
.vm_pages
) {
8323 this -= server
.vm_pages
;
8325 /* Just overflowed, what we found on tail is no longer
8326 * interesting, as it's no longer contiguous. */
8330 if (vmFreePage(this)) {
8331 /* This is a free page */
8333 /* Already got N free pages? Return to the caller, with success */
8335 *first
= this-(n
-1);
8336 server
.vm_next_page
= this+1;
8337 redisLog(REDIS_DEBUG
, "FOUND CONTIGUOUS PAGES: %lld pages at %lld\n", (long long) n
, (long long) *first
);
8341 /* The current one is not a free page */
8345 /* Fast-forward if the current page is not free and we already
8346 * searched enough near this place. */
8348 if (!numfree
&& since_jump
>= REDIS_VM_MAX_RANDOM_JUMP
/4) {
8349 offset
+= random() % REDIS_VM_MAX_RANDOM_JUMP
;
8351 /* Note that even if we rewind after the jump, we are don't need
8352 * to make sure numfree is set to zero as we only jump *if* it
8353 * is set to zero. */
8355 /* Otherwise just check the next page */
8362 /* Write the specified object at the specified page of the swap file */
8363 static int vmWriteObjectOnSwap(robj
*o
, off_t page
) {
8364 if (server
.vm_enabled
) pthread_mutex_lock(&server
.io_swapfile_mutex
);
8365 if (fseeko(server
.vm_fp
,page
*server
.vm_page_size
,SEEK_SET
) == -1) {
8366 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.io_swapfile_mutex
);
8367 redisLog(REDIS_WARNING
,
8368 "Critical VM problem in vmWriteObjectOnSwap(): can't seek: %s",
8372 rdbSaveObject(server
.vm_fp
,o
);
8373 fflush(server
.vm_fp
);
8374 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.io_swapfile_mutex
);
8378 /* Swap the 'val' object relative to 'key' into disk. Store all the information
8379 * needed to later retrieve the object into the key object.
8380 * If we can't find enough contiguous empty pages to swap the object on disk
8381 * REDIS_ERR is returned. */
8382 static int vmSwapObjectBlocking(robj
*key
, robj
*val
) {
8383 off_t pages
= rdbSavedObjectPages(val
,NULL
);
8386 assert(key
->storage
== REDIS_VM_MEMORY
);
8387 assert(key
->refcount
== 1);
8388 if (vmFindContiguousPages(&page
,pages
) == REDIS_ERR
) return REDIS_ERR
;
8389 if (vmWriteObjectOnSwap(val
,page
) == REDIS_ERR
) return REDIS_ERR
;
8390 key
->vm
.page
= page
;
8391 key
->vm
.usedpages
= pages
;
8392 key
->storage
= REDIS_VM_SWAPPED
;
8393 key
->vtype
= val
->type
;
8394 decrRefCount(val
); /* Deallocate the object from memory. */
8395 vmMarkPagesUsed(page
,pages
);
8396 redisLog(REDIS_DEBUG
,"VM: object %s swapped out at %lld (%lld pages)",
8397 (unsigned char*) key
->ptr
,
8398 (unsigned long long) page
, (unsigned long long) pages
);
8399 server
.vm_stats_swapped_objects
++;
8400 server
.vm_stats_swapouts
++;
8404 static robj
*vmReadObjectFromSwap(off_t page
, int type
) {
8407 if (server
.vm_enabled
) pthread_mutex_lock(&server
.io_swapfile_mutex
);
8408 if (fseeko(server
.vm_fp
,page
*server
.vm_page_size
,SEEK_SET
) == -1) {
8409 redisLog(REDIS_WARNING
,
8410 "Unrecoverable VM problem in vmReadObjectFromSwap(): can't seek: %s",
8414 o
= rdbLoadObject(type
,server
.vm_fp
);
8416 redisLog(REDIS_WARNING
, "Unrecoverable VM problem in vmReadObjectFromSwap(): can't load object from swap file: %s", strerror(errno
));
8419 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.io_swapfile_mutex
);
8423 /* Load the value object relative to the 'key' object from swap to memory.
8424 * The newly allocated object is returned.
8426 * If preview is true the unserialized object is returned to the caller but
8427 * no changes are made to the key object, nor the pages are marked as freed */
8428 static robj
*vmGenericLoadObject(robj
*key
, int preview
) {
8431 redisAssert(key
->storage
== REDIS_VM_SWAPPED
|| key
->storage
== REDIS_VM_LOADING
);
8432 val
= vmReadObjectFromSwap(key
->vm
.page
,key
->vtype
);
8434 key
->storage
= REDIS_VM_MEMORY
;
8435 key
->vm
.atime
= server
.unixtime
;
8436 vmMarkPagesFree(key
->vm
.page
,key
->vm
.usedpages
);
8437 redisLog(REDIS_DEBUG
, "VM: object %s loaded from disk",
8438 (unsigned char*) key
->ptr
);
8439 server
.vm_stats_swapped_objects
--;
8441 redisLog(REDIS_DEBUG
, "VM: object %s previewed from disk",
8442 (unsigned char*) key
->ptr
);
8444 server
.vm_stats_swapins
++;
8448 /* Plain object loading, from swap to memory */
8449 static robj
*vmLoadObject(robj
*key
) {
8450 /* If we are loading the object in background, stop it, we
8451 * need to load this object synchronously ASAP. */
8452 if (key
->storage
== REDIS_VM_LOADING
)
8453 vmCancelThreadedIOJob(key
);
8454 return vmGenericLoadObject(key
,0);
8457 /* Just load the value on disk, without to modify the key.
8458 * This is useful when we want to perform some operation on the value
8459 * without to really bring it from swap to memory, like while saving the
8460 * dataset or rewriting the append only log. */
8461 static robj
*vmPreviewObject(robj
*key
) {
8462 return vmGenericLoadObject(key
,1);
8465 /* How a good candidate is this object for swapping?
8466 * The better candidate it is, the greater the returned value.
8468 * Currently we try to perform a fast estimation of the object size in
8469 * memory, and combine it with aging informations.
8471 * Basically swappability = idle-time * log(estimated size)
8473 * Bigger objects are preferred over smaller objects, but not
8474 * proportionally, this is why we use the logarithm. This algorithm is
8475 * just a first try and will probably be tuned later. */
8476 static double computeObjectSwappability(robj
*o
) {
8477 time_t age
= server
.unixtime
- o
->vm
.atime
;
8481 struct dictEntry
*de
;
8484 if (age
<= 0) return 0;
8487 if (o
->encoding
!= REDIS_ENCODING_RAW
) {
8490 asize
= sdslen(o
->ptr
)+sizeof(*o
)+sizeof(long)*2;
8495 listNode
*ln
= listFirst(l
);
8497 asize
= sizeof(list
);
8499 robj
*ele
= ln
->value
;
8502 elesize
= (ele
->encoding
== REDIS_ENCODING_RAW
) ?
8503 (sizeof(*o
)+sdslen(ele
->ptr
)) :
8505 asize
+= (sizeof(listNode
)+elesize
)*listLength(l
);
8510 z
= (o
->type
== REDIS_ZSET
);
8511 d
= z
? ((zset
*)o
->ptr
)->dict
: o
->ptr
;
8513 asize
= sizeof(dict
)+(sizeof(struct dictEntry
*)*dictSlots(d
));
8514 if (z
) asize
+= sizeof(zset
)-sizeof(dict
);
8519 de
= dictGetRandomKey(d
);
8520 ele
= dictGetEntryKey(de
);
8521 elesize
= (ele
->encoding
== REDIS_ENCODING_RAW
) ?
8522 (sizeof(*o
)+sdslen(ele
->ptr
)) :
8524 asize
+= (sizeof(struct dictEntry
)+elesize
)*dictSize(d
);
8525 if (z
) asize
+= sizeof(zskiplistNode
)*dictSize(d
);
8529 if (o
->encoding
== REDIS_ENCODING_ZIPMAP
) {
8530 unsigned char *p
= zipmapRewind((unsigned char*)o
->ptr
);
8531 unsigned int len
= zipmapLen((unsigned char*)o
->ptr
);
8532 unsigned int klen
, vlen
;
8533 unsigned char *key
, *val
;
8535 if ((p
= zipmapNext(p
,&key
,&klen
,&val
,&vlen
)) == NULL
) {
8539 asize
= len
*(klen
+vlen
+3);
8540 } else if (o
->encoding
== REDIS_ENCODING_HT
) {
8542 asize
= sizeof(dict
)+(sizeof(struct dictEntry
*)*dictSlots(d
));
8547 de
= dictGetRandomKey(d
);
8548 ele
= dictGetEntryKey(de
);
8549 elesize
= (ele
->encoding
== REDIS_ENCODING_RAW
) ?
8550 (sizeof(*o
)+sdslen(ele
->ptr
)) :
8552 ele
= dictGetEntryVal(de
);
8553 elesize
= (ele
->encoding
== REDIS_ENCODING_RAW
) ?
8554 (sizeof(*o
)+sdslen(ele
->ptr
)) :
8556 asize
+= (sizeof(struct dictEntry
)+elesize
)*dictSize(d
);
8561 return (double)age
*log(1+asize
);
8564 /* Try to swap an object that's a good candidate for swapping.
8565 * Returns REDIS_OK if the object was swapped, REDIS_ERR if it's not possible
8566 * to swap any object at all.
8568 * If 'usethreaded' is true, Redis will try to swap the object in background
8569 * using I/O threads. */
8570 static int vmSwapOneObject(int usethreads
) {
8572 struct dictEntry
*best
= NULL
;
8573 double best_swappability
= 0;
8574 redisDb
*best_db
= NULL
;
8577 for (j
= 0; j
< server
.dbnum
; j
++) {
8578 redisDb
*db
= server
.db
+j
;
8579 /* Why maxtries is set to 100?
8580 * Because this way (usually) we'll find 1 object even if just 1% - 2%
8581 * are swappable objects */
8584 if (dictSize(db
->dict
) == 0) continue;
8585 for (i
= 0; i
< 5; i
++) {
8587 double swappability
;
8589 if (maxtries
) maxtries
--;
8590 de
= dictGetRandomKey(db
->dict
);
8591 key
= dictGetEntryKey(de
);
8592 val
= dictGetEntryVal(de
);
8593 /* Only swap objects that are currently in memory.
8595 * Also don't swap shared objects if threaded VM is on, as we
8596 * try to ensure that the main thread does not touch the
8597 * object while the I/O thread is using it, but we can't
8598 * control other keys without adding additional mutex. */
8599 if (key
->storage
!= REDIS_VM_MEMORY
||
8600 (server
.vm_max_threads
!= 0 && val
->refcount
!= 1)) {
8601 if (maxtries
) i
--; /* don't count this try */
8604 swappability
= computeObjectSwappability(val
);
8605 if (!best
|| swappability
> best_swappability
) {
8607 best_swappability
= swappability
;
8612 if (best
== NULL
) return REDIS_ERR
;
8613 key
= dictGetEntryKey(best
);
8614 val
= dictGetEntryVal(best
);
8616 redisLog(REDIS_DEBUG
,"Key with best swappability: %s, %f",
8617 key
->ptr
, best_swappability
);
8619 /* Unshare the key if needed */
8620 if (key
->refcount
> 1) {
8621 robj
*newkey
= dupStringObject(key
);
8623 key
= dictGetEntryKey(best
) = newkey
;
8627 vmSwapObjectThreaded(key
,val
,best_db
);
8630 if (vmSwapObjectBlocking(key
,val
) == REDIS_OK
) {
8631 dictGetEntryVal(best
) = NULL
;
8639 static int vmSwapOneObjectBlocking() {
8640 return vmSwapOneObject(0);
8643 static int vmSwapOneObjectThreaded() {
8644 return vmSwapOneObject(1);
8647 /* Return true if it's safe to swap out objects in a given moment.
8648 * Basically we don't want to swap objects out while there is a BGSAVE
8649 * or a BGAEOREWRITE running in backgroud. */
8650 static int vmCanSwapOut(void) {
8651 return (server
.bgsavechildpid
== -1 && server
.bgrewritechildpid
== -1);
8654 /* Delete a key if swapped. Returns 1 if the key was found, was swapped
8655 * and was deleted. Otherwise 0 is returned. */
8656 static int deleteIfSwapped(redisDb
*db
, robj
*key
) {
8660 if ((de
= dictFind(db
->dict
,key
)) == NULL
) return 0;
8661 foundkey
= dictGetEntryKey(de
);
8662 if (foundkey
->storage
== REDIS_VM_MEMORY
) return 0;
8667 /* =================== Virtual Memory - Threaded I/O ======================= */
8669 static void freeIOJob(iojob
*j
) {
8670 if ((j
->type
== REDIS_IOJOB_PREPARE_SWAP
||
8671 j
->type
== REDIS_IOJOB_DO_SWAP
||
8672 j
->type
== REDIS_IOJOB_LOAD
) && j
->val
!= NULL
)
8673 decrRefCount(j
->val
);
8674 decrRefCount(j
->key
);
8678 /* Every time a thread finished a Job, it writes a byte into the write side
8679 * of an unix pipe in order to "awake" the main thread, and this function
8681 static void vmThreadedIOCompletedJob(aeEventLoop
*el
, int fd
, void *privdata
,
8685 int retval
, processed
= 0, toprocess
= -1, trytoswap
= 1;
8687 REDIS_NOTUSED(mask
);
8688 REDIS_NOTUSED(privdata
);
8690 /* For every byte we read in the read side of the pipe, there is one
8691 * I/O job completed to process. */
8692 while((retval
= read(fd
,buf
,1)) == 1) {
8696 struct dictEntry
*de
;
8698 redisLog(REDIS_DEBUG
,"Processing I/O completed job");
8700 /* Get the processed element (the oldest one) */
8702 assert(listLength(server
.io_processed
) != 0);
8703 if (toprocess
== -1) {
8704 toprocess
= (listLength(server
.io_processed
)*REDIS_MAX_COMPLETED_JOBS_PROCESSED
)/100;
8705 if (toprocess
<= 0) toprocess
= 1;
8707 ln
= listFirst(server
.io_processed
);
8709 listDelNode(server
.io_processed
,ln
);
8711 /* If this job is marked as canceled, just ignore it */
8716 /* Post process it in the main thread, as there are things we
8717 * can do just here to avoid race conditions and/or invasive locks */
8718 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
);
8719 de
= dictFind(j
->db
->dict
,j
->key
);
8721 key
= dictGetEntryKey(de
);
8722 if (j
->type
== REDIS_IOJOB_LOAD
) {
8725 /* Key loaded, bring it at home */
8726 key
->storage
= REDIS_VM_MEMORY
;
8727 key
->vm
.atime
= server
.unixtime
;
8728 vmMarkPagesFree(key
->vm
.page
,key
->vm
.usedpages
);
8729 redisLog(REDIS_DEBUG
, "VM: object %s loaded from disk (threaded)",
8730 (unsigned char*) key
->ptr
);
8731 server
.vm_stats_swapped_objects
--;
8732 server
.vm_stats_swapins
++;
8733 dictGetEntryVal(de
) = j
->val
;
8734 incrRefCount(j
->val
);
8737 /* Handle clients waiting for this key to be loaded. */
8738 handleClientsBlockedOnSwappedKey(db
,key
);
8739 } else if (j
->type
== REDIS_IOJOB_PREPARE_SWAP
) {
8740 /* Now we know the amount of pages required to swap this object.
8741 * Let's find some space for it, and queue this task again
8742 * rebranded as REDIS_IOJOB_DO_SWAP. */
8743 if (!vmCanSwapOut() ||
8744 vmFindContiguousPages(&j
->page
,j
->pages
) == REDIS_ERR
)
8746 /* Ooops... no space or we can't swap as there is
8747 * a fork()ed Redis trying to save stuff on disk. */
8749 key
->storage
= REDIS_VM_MEMORY
; /* undo operation */
8751 /* Note that we need to mark this pages as used now,
8752 * if the job will be canceled, we'll mark them as freed
8754 vmMarkPagesUsed(j
->page
,j
->pages
);
8755 j
->type
= REDIS_IOJOB_DO_SWAP
;
8760 } else if (j
->type
== REDIS_IOJOB_DO_SWAP
) {
8763 /* Key swapped. We can finally free some memory. */
8764 if (key
->storage
!= REDIS_VM_SWAPPING
) {
8765 printf("key->storage: %d\n",key
->storage
);
8766 printf("key->name: %s\n",(char*)key
->ptr
);
8767 printf("key->refcount: %d\n",key
->refcount
);
8768 printf("val: %p\n",(void*)j
->val
);
8769 printf("val->type: %d\n",j
->val
->type
);
8770 printf("val->ptr: %s\n",(char*)j
->val
->ptr
);
8772 redisAssert(key
->storage
== REDIS_VM_SWAPPING
);
8773 val
= dictGetEntryVal(de
);
8774 key
->vm
.page
= j
->page
;
8775 key
->vm
.usedpages
= j
->pages
;
8776 key
->storage
= REDIS_VM_SWAPPED
;
8777 key
->vtype
= j
->val
->type
;
8778 decrRefCount(val
); /* Deallocate the object from memory. */
8779 dictGetEntryVal(de
) = NULL
;
8780 redisLog(REDIS_DEBUG
,
8781 "VM: object %s swapped out at %lld (%lld pages) (threaded)",
8782 (unsigned char*) key
->ptr
,
8783 (unsigned long long) j
->page
, (unsigned long long) j
->pages
);
8784 server
.vm_stats_swapped_objects
++;
8785 server
.vm_stats_swapouts
++;
8787 /* Put a few more swap requests in queue if we are still
8789 if (trytoswap
&& vmCanSwapOut() &&
8790 zmalloc_used_memory() > server
.vm_max_memory
)
8795 more
= listLength(server
.io_newjobs
) <
8796 (unsigned) server
.vm_max_threads
;
8798 /* Don't waste CPU time if swappable objects are rare. */
8799 if (vmSwapOneObjectThreaded() == REDIS_ERR
) {
8807 if (processed
== toprocess
) return;
8809 if (retval
< 0 && errno
!= EAGAIN
) {
8810 redisLog(REDIS_WARNING
,
8811 "WARNING: read(2) error in vmThreadedIOCompletedJob() %s",
8816 static void lockThreadedIO(void) {
8817 pthread_mutex_lock(&server
.io_mutex
);
8820 static void unlockThreadedIO(void) {
8821 pthread_mutex_unlock(&server
.io_mutex
);
8824 /* Remove the specified object from the threaded I/O queue if still not
8825 * processed, otherwise make sure to flag it as canceled. */
8826 static void vmCancelThreadedIOJob(robj
*o
) {
8828 server
.io_newjobs
, /* 0 */
8829 server
.io_processing
, /* 1 */
8830 server
.io_processed
/* 2 */
8834 assert(o
->storage
== REDIS_VM_LOADING
|| o
->storage
== REDIS_VM_SWAPPING
);
8837 /* Search for a matching key in one of the queues */
8838 for (i
= 0; i
< 3; i
++) {
8842 listRewind(lists
[i
],&li
);
8843 while ((ln
= listNext(&li
)) != NULL
) {
8844 iojob
*job
= ln
->value
;
8846 if (job
->canceled
) continue; /* Skip this, already canceled. */
8847 if (compareStringObjects(job
->key
,o
) == 0) {
8848 redisLog(REDIS_DEBUG
,"*** CANCELED %p (%s) (type %d) (LIST ID %d)\n",
8849 (void*)job
, (char*)o
->ptr
, job
->type
, i
);
8850 /* Mark the pages as free since the swap didn't happened
8851 * or happened but is now discarded. */
8852 if (i
!= 1 && job
->type
== REDIS_IOJOB_DO_SWAP
)
8853 vmMarkPagesFree(job
->page
,job
->pages
);
8854 /* Cancel the job. It depends on the list the job is
8857 case 0: /* io_newjobs */
8858 /* If the job was yet not processed the best thing to do
8859 * is to remove it from the queue at all */
8861 listDelNode(lists
[i
],ln
);
8863 case 1: /* io_processing */
8864 /* Oh Shi- the thread is messing with the Job:
8866 * Probably it's accessing the object if this is a
8867 * PREPARE_SWAP or DO_SWAP job.
8868 * If it's a LOAD job it may be reading from disk and
8869 * if we don't wait for the job to terminate before to
8870 * cancel it, maybe in a few microseconds data can be
8871 * corrupted in this pages. So the short story is:
8873 * Better to wait for the job to move into the
8874 * next queue (processed)... */
8876 /* We try again and again until the job is completed. */
8878 /* But let's wait some time for the I/O thread
8879 * to finish with this job. After all this condition
8880 * should be very rare. */
8883 case 2: /* io_processed */
8884 /* The job was already processed, that's easy...
8885 * just mark it as canceled so that we'll ignore it
8886 * when processing completed jobs. */
8890 /* Finally we have to adjust the storage type of the object
8891 * in order to "UNDO" the operaiton. */
8892 if (o
->storage
== REDIS_VM_LOADING
)
8893 o
->storage
= REDIS_VM_SWAPPED
;
8894 else if (o
->storage
== REDIS_VM_SWAPPING
)
8895 o
->storage
= REDIS_VM_MEMORY
;
8902 assert(1 != 1); /* We should never reach this */
8905 static void *IOThreadEntryPoint(void *arg
) {
8910 pthread_detach(pthread_self());
8912 /* Get a new job to process */
8914 if (listLength(server
.io_newjobs
) == 0) {
8915 /* No new jobs in queue, exit. */
8916 redisLog(REDIS_DEBUG
,"Thread %ld exiting, nothing to do",
8917 (long) pthread_self());
8918 server
.io_active_threads
--;
8922 ln
= listFirst(server
.io_newjobs
);
8924 listDelNode(server
.io_newjobs
,ln
);
8925 /* Add the job in the processing queue */
8926 j
->thread
= pthread_self();
8927 listAddNodeTail(server
.io_processing
,j
);
8928 ln
= listLast(server
.io_processing
); /* We use ln later to remove it */
8930 redisLog(REDIS_DEBUG
,"Thread %ld got a new job (type %d): %p about key '%s'",
8931 (long) pthread_self(), j
->type
, (void*)j
, (char*)j
->key
->ptr
);
8933 /* Process the Job */
8934 if (j
->type
== REDIS_IOJOB_LOAD
) {
8935 j
->val
= vmReadObjectFromSwap(j
->page
,j
->key
->vtype
);
8936 } else if (j
->type
== REDIS_IOJOB_PREPARE_SWAP
) {
8937 FILE *fp
= fopen("/dev/null","w+");
8938 j
->pages
= rdbSavedObjectPages(j
->val
,fp
);
8940 } else if (j
->type
== REDIS_IOJOB_DO_SWAP
) {
8941 if (vmWriteObjectOnSwap(j
->val
,j
->page
) == REDIS_ERR
)
8945 /* Done: insert the job into the processed queue */
8946 redisLog(REDIS_DEBUG
,"Thread %ld completed the job: %p (key %s)",
8947 (long) pthread_self(), (void*)j
, (char*)j
->key
->ptr
);
8949 listDelNode(server
.io_processing
,ln
);
8950 listAddNodeTail(server
.io_processed
,j
);
8953 /* Signal the main thread there is new stuff to process */
8954 assert(write(server
.io_ready_pipe_write
,"x",1) == 1);
8956 return NULL
; /* never reached */
8959 static void spawnIOThread(void) {
8961 sigset_t mask
, omask
;
8965 sigaddset(&mask
,SIGCHLD
);
8966 sigaddset(&mask
,SIGHUP
);
8967 sigaddset(&mask
,SIGPIPE
);
8968 pthread_sigmask(SIG_SETMASK
, &mask
, &omask
);
8969 while ((err
= pthread_create(&thread
,&server
.io_threads_attr
,IOThreadEntryPoint
,NULL
)) != 0) {
8970 redisLog(REDIS_WARNING
,"Unable to spawn an I/O thread: %s",
8974 pthread_sigmask(SIG_SETMASK
, &omask
, NULL
);
8975 server
.io_active_threads
++;
8978 /* We need to wait for the last thread to exit before we are able to
8979 * fork() in order to BGSAVE or BGREWRITEAOF. */
8980 static void waitEmptyIOJobsQueue(void) {
8982 int io_processed_len
;
8985 if (listLength(server
.io_newjobs
) == 0 &&
8986 listLength(server
.io_processing
) == 0 &&
8987 server
.io_active_threads
== 0)
8992 /* While waiting for empty jobs queue condition we post-process some
8993 * finshed job, as I/O threads may be hanging trying to write against
8994 * the io_ready_pipe_write FD but there are so much pending jobs that
8996 io_processed_len
= listLength(server
.io_processed
);
8998 if (io_processed_len
) {
8999 vmThreadedIOCompletedJob(NULL
,server
.io_ready_pipe_read
,NULL
,0);
9000 usleep(1000); /* 1 millisecond */
9002 usleep(10000); /* 10 milliseconds */
9007 static void vmReopenSwapFile(void) {
9008 /* Note: we don't close the old one as we are in the child process
9009 * and don't want to mess at all with the original file object. */
9010 server
.vm_fp
= fopen(server
.vm_swap_file
,"r+b");
9011 if (server
.vm_fp
== NULL
) {
9012 redisLog(REDIS_WARNING
,"Can't re-open the VM swap file: %s. Exiting.",
9013 server
.vm_swap_file
);
9016 server
.vm_fd
= fileno(server
.vm_fp
);
9019 /* This function must be called while with threaded IO locked */
9020 static void queueIOJob(iojob
*j
) {
9021 redisLog(REDIS_DEBUG
,"Queued IO Job %p type %d about key '%s'\n",
9022 (void*)j
, j
->type
, (char*)j
->key
->ptr
);
9023 listAddNodeTail(server
.io_newjobs
,j
);
9024 if (server
.io_active_threads
< server
.vm_max_threads
)
9028 static int vmSwapObjectThreaded(robj
*key
, robj
*val
, redisDb
*db
) {
9031 assert(key
->storage
== REDIS_VM_MEMORY
);
9032 assert(key
->refcount
== 1);
9034 j
= zmalloc(sizeof(*j
));
9035 j
->type
= REDIS_IOJOB_PREPARE_SWAP
;
9037 j
->key
= dupStringObject(key
);
9041 j
->thread
= (pthread_t
) -1;
9042 key
->storage
= REDIS_VM_SWAPPING
;
9050 /* ============ Virtual Memory - Blocking clients on missing keys =========== */
9052 /* This function makes the clinet 'c' waiting for the key 'key' to be loaded.
9053 * If there is not already a job loading the key, it is craeted.
9054 * The key is added to the io_keys list in the client structure, and also
9055 * in the hash table mapping swapped keys to waiting clients, that is,
9056 * server.io_waited_keys. */
9057 static int waitForSwappedKey(redisClient
*c
, robj
*key
) {
9058 struct dictEntry
*de
;
9062 /* If the key does not exist or is already in RAM we don't need to
9063 * block the client at all. */
9064 de
= dictFind(c
->db
->dict
,key
);
9065 if (de
== NULL
) return 0;
9066 o
= dictGetEntryKey(de
);
9067 if (o
->storage
== REDIS_VM_MEMORY
) {
9069 } else if (o
->storage
== REDIS_VM_SWAPPING
) {
9070 /* We were swapping the key, undo it! */
9071 vmCancelThreadedIOJob(o
);
9075 /* OK: the key is either swapped, or being loaded just now. */
9077 /* Add the key to the list of keys this client is waiting for.
9078 * This maps clients to keys they are waiting for. */
9079 listAddNodeTail(c
->io_keys
,key
);
9082 /* Add the client to the swapped keys => clients waiting map. */
9083 de
= dictFind(c
->db
->io_keys
,key
);
9087 /* For every key we take a list of clients blocked for it */
9089 retval
= dictAdd(c
->db
->io_keys
,key
,l
);
9091 assert(retval
== DICT_OK
);
9093 l
= dictGetEntryVal(de
);
9095 listAddNodeTail(l
,c
);
9097 /* Are we already loading the key from disk? If not create a job */
9098 if (o
->storage
== REDIS_VM_SWAPPED
) {
9101 o
->storage
= REDIS_VM_LOADING
;
9102 j
= zmalloc(sizeof(*j
));
9103 j
->type
= REDIS_IOJOB_LOAD
;
9105 j
->key
= dupStringObject(key
);
9106 j
->key
->vtype
= o
->vtype
;
9107 j
->page
= o
->vm
.page
;
9110 j
->thread
= (pthread_t
) -1;
9118 /* Preload keys needed for the ZUNION and ZINTER commands. */
9119 static void zunionInterBlockClientOnSwappedKeys(redisClient
*c
) {
9121 num
= atoi(c
->argv
[2]->ptr
);
9122 for (i
= 0; i
< num
; i
++) {
9123 waitForSwappedKey(c
,c
->argv
[3+i
]);
9127 /* Is this client attempting to run a command against swapped keys?
9128 * If so, block it ASAP, load the keys in background, then resume it.
9130 * The important idea about this function is that it can fail! If keys will
9131 * still be swapped when the client is resumed, this key lookups will
9132 * just block loading keys from disk. In practical terms this should only
9133 * happen with SORT BY command or if there is a bug in this function.
9135 * Return 1 if the client is marked as blocked, 0 if the client can
9136 * continue as the keys it is going to access appear to be in memory. */
9137 static int blockClientOnSwappedKeys(struct redisCommand
*cmd
, redisClient
*c
) {
9140 if (cmd
->vm_preload_proc
!= NULL
) {
9141 cmd
->vm_preload_proc(c
);
9143 if (cmd
->vm_firstkey
== 0) return 0;
9144 last
= cmd
->vm_lastkey
;
9145 if (last
< 0) last
= c
->argc
+last
;
9146 for (j
= cmd
->vm_firstkey
; j
<= last
; j
+= cmd
->vm_keystep
)
9147 waitForSwappedKey(c
,c
->argv
[j
]);
9150 /* If the client was blocked for at least one key, mark it as blocked. */
9151 if (listLength(c
->io_keys
)) {
9152 c
->flags
|= REDIS_IO_WAIT
;
9153 aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
);
9154 server
.vm_blocked_clients
++;
9161 /* Remove the 'key' from the list of blocked keys for a given client.
9163 * The function returns 1 when there are no longer blocking keys after
9164 * the current one was removed (and the client can be unblocked). */
9165 static int dontWaitForSwappedKey(redisClient
*c
, robj
*key
) {
9169 struct dictEntry
*de
;
9171 /* Remove the key from the list of keys this client is waiting for. */
9172 listRewind(c
->io_keys
,&li
);
9173 while ((ln
= listNext(&li
)) != NULL
) {
9174 if (compareStringObjects(ln
->value
,key
) == 0) {
9175 listDelNode(c
->io_keys
,ln
);
9181 /* Remove the client form the key => waiting clients map. */
9182 de
= dictFind(c
->db
->io_keys
,key
);
9184 l
= dictGetEntryVal(de
);
9185 ln
= listSearchKey(l
,c
);
9188 if (listLength(l
) == 0)
9189 dictDelete(c
->db
->io_keys
,key
);
9191 return listLength(c
->io_keys
) == 0;
9194 static void handleClientsBlockedOnSwappedKey(redisDb
*db
, robj
*key
) {
9195 struct dictEntry
*de
;
9200 de
= dictFind(db
->io_keys
,key
);
9203 l
= dictGetEntryVal(de
);
9204 len
= listLength(l
);
9205 /* Note: we can't use something like while(listLength(l)) as the list
9206 * can be freed by the calling function when we remove the last element. */
9209 redisClient
*c
= ln
->value
;
9211 if (dontWaitForSwappedKey(c
,key
)) {
9212 /* Put the client in the list of clients ready to go as we
9213 * loaded all the keys about it. */
9214 listAddNodeTail(server
.io_ready_clients
,c
);
9219 /* =========================== Remote Configuration ========================= */
9221 static void configSetCommand(redisClient
*c
) {
9222 robj
*o
= getDecodedObject(c
->argv
[3]);
9223 if (!strcasecmp(c
->argv
[2]->ptr
,"dbfilename")) {
9224 zfree(server
.dbfilename
);
9225 server
.dbfilename
= zstrdup(o
->ptr
);
9226 } else if (!strcasecmp(c
->argv
[2]->ptr
,"requirepass")) {
9227 zfree(server
.requirepass
);
9228 server
.requirepass
= zstrdup(o
->ptr
);
9229 } else if (!strcasecmp(c
->argv
[2]->ptr
,"masterauth")) {
9230 zfree(server
.masterauth
);
9231 server
.masterauth
= zstrdup(o
->ptr
);
9232 } else if (!strcasecmp(c
->argv
[2]->ptr
,"maxmemory")) {
9233 server
.maxmemory
= strtoll(o
->ptr
, NULL
, 10);
9235 addReplySds(c
,sdscatprintf(sdsempty(),
9236 "-ERR not supported CONFIG parameter %s\r\n",
9237 (char*)c
->argv
[2]->ptr
));
9242 addReply(c
,shared
.ok
);
9245 static void configGetCommand(redisClient
*c
) {
9246 robj
*o
= getDecodedObject(c
->argv
[2]);
9247 robj
*lenobj
= createObject(REDIS_STRING
,NULL
);
9248 char *pattern
= o
->ptr
;
9252 decrRefCount(lenobj
);
9254 if (stringmatch(pattern
,"dbfilename",0)) {
9255 addReplyBulkCString(c
,"dbfilename");
9256 addReplyBulkCString(c
,server
.dbfilename
);
9259 if (stringmatch(pattern
,"requirepass",0)) {
9260 addReplyBulkCString(c
,"requirepass");
9261 addReplyBulkCString(c
,server
.requirepass
);
9264 if (stringmatch(pattern
,"masterauth",0)) {
9265 addReplyBulkCString(c
,"masterauth");
9266 addReplyBulkCString(c
,server
.masterauth
);
9269 if (stringmatch(pattern
,"maxmemory",0)) {
9272 snprintf(buf
,128,"%llu\n",server
.maxmemory
);
9273 addReplyBulkCString(c
,"maxmemory");
9274 addReplyBulkCString(c
,buf
);
9278 lenobj
->ptr
= sdscatprintf(sdsempty(),"*%d\r\n",matches
*2);
9281 static void configCommand(redisClient
*c
) {
9282 if (!strcasecmp(c
->argv
[1]->ptr
,"set")) {
9283 if (c
->argc
!= 4) goto badarity
;
9284 configSetCommand(c
);
9285 } else if (!strcasecmp(c
->argv
[1]->ptr
,"get")) {
9286 if (c
->argc
!= 3) goto badarity
;
9287 configGetCommand(c
);
9288 } else if (!strcasecmp(c
->argv
[1]->ptr
,"resetstat")) {
9289 if (c
->argc
!= 2) goto badarity
;
9290 server
.stat_numcommands
= 0;
9291 server
.stat_numconnections
= 0;
9292 server
.stat_expiredkeys
= 0;
9293 server
.stat_starttime
= time(NULL
);
9294 addReply(c
,shared
.ok
);
9296 addReplySds(c
,sdscatprintf(sdsempty(),
9297 "-ERR CONFIG subcommand must be one of GET, SET, RESETSTAT\r\n"));
9302 addReplySds(c
,sdscatprintf(sdsempty(),
9303 "-ERR Wrong number of arguments for CONFIG %s\r\n",
9304 (char*) c
->argv
[1]->ptr
));
9307 /* =========================== Pubsub implementation ======================== */
9309 static void freePubsubPattern(void *p
) {
9310 pubsubPattern
*pat
= p
;
9312 decrRefCount(pat
->pattern
);
9316 static int listMatchPubsubPattern(void *a
, void *b
) {
9317 pubsubPattern
*pa
= a
, *pb
= b
;
9319 return (pa
->client
== pb
->client
) &&
9320 (compareStringObjects(pa
->pattern
,pb
->pattern
) == 0);
9323 /* Subscribe a client to a channel. Returns 1 if the operation succeeded, or
9324 * 0 if the client was already subscribed to that channel. */
9325 static int pubsubSubscribeChannel(redisClient
*c
, robj
*channel
) {
9326 struct dictEntry
*de
;
9327 list
*clients
= NULL
;
9330 /* Add the channel to the client -> channels hash table */
9331 if (dictAdd(c
->pubsub_channels
,channel
,NULL
) == DICT_OK
) {
9333 incrRefCount(channel
);
9334 /* Add the client to the channel -> list of clients hash table */
9335 de
= dictFind(server
.pubsub_channels
,channel
);
9337 clients
= listCreate();
9338 dictAdd(server
.pubsub_channels
,channel
,clients
);
9339 incrRefCount(channel
);
9341 clients
= dictGetEntryVal(de
);
9343 listAddNodeTail(clients
,c
);
9345 /* Notify the client */
9346 addReply(c
,shared
.mbulk3
);
9347 addReply(c
,shared
.subscribebulk
);
9348 addReplyBulk(c
,channel
);
9349 addReplyLong(c
,dictSize(c
->pubsub_channels
)+listLength(c
->pubsub_patterns
));
9353 /* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
9354 * 0 if the client was not subscribed to the specified channel. */
9355 static int pubsubUnsubscribeChannel(redisClient
*c
, robj
*channel
, int notify
) {
9356 struct dictEntry
*de
;
9361 /* Remove the channel from the client -> channels hash table */
9362 incrRefCount(channel
); /* channel may be just a pointer to the same object
9363 we have in the hash tables. Protect it... */
9364 if (dictDelete(c
->pubsub_channels
,channel
) == DICT_OK
) {
9366 /* Remove the client from the channel -> clients list hash table */
9367 de
= dictFind(server
.pubsub_channels
,channel
);
9369 clients
= dictGetEntryVal(de
);
9370 ln
= listSearchKey(clients
,c
);
9372 listDelNode(clients
,ln
);
9373 if (listLength(clients
) == 0) {
9374 /* Free the list and associated hash entry at all if this was
9375 * the latest client, so that it will be possible to abuse
9376 * Redis PUBSUB creating millions of channels. */
9377 dictDelete(server
.pubsub_channels
,channel
);
9380 /* Notify the client */
9382 addReply(c
,shared
.mbulk3
);
9383 addReply(c
,shared
.unsubscribebulk
);
9384 addReplyBulk(c
,channel
);
9385 addReplyLong(c
,dictSize(c
->pubsub_channels
)+
9386 listLength(c
->pubsub_patterns
));
9389 decrRefCount(channel
); /* it is finally safe to release it */
9393 /* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the clinet was already subscribed to that pattern. */
9394 static int pubsubSubscribePattern(redisClient
*c
, robj
*pattern
) {
9397 if (listSearchKey(c
->pubsub_patterns
,pattern
) == NULL
) {
9400 listAddNodeTail(c
->pubsub_patterns
,pattern
);
9401 incrRefCount(pattern
);
9402 pat
= zmalloc(sizeof(*pat
));
9403 pat
->pattern
= getDecodedObject(pattern
);
9405 listAddNodeTail(server
.pubsub_patterns
,pat
);
9407 /* Notify the client */
9408 addReply(c
,shared
.mbulk3
);
9409 addReply(c
,shared
.psubscribebulk
);
9410 addReplyBulk(c
,pattern
);
9411 addReplyLong(c
,dictSize(c
->pubsub_channels
)+listLength(c
->pubsub_patterns
));
9415 /* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
9416 * 0 if the client was not subscribed to the specified channel. */
9417 static int pubsubUnsubscribePattern(redisClient
*c
, robj
*pattern
, int notify
) {
9422 incrRefCount(pattern
); /* Protect the object. May be the same we remove */
9423 if ((ln
= listSearchKey(c
->pubsub_patterns
,pattern
)) != NULL
) {
9425 listDelNode(c
->pubsub_patterns
,ln
);
9427 pat
.pattern
= pattern
;
9428 ln
= listSearchKey(server
.pubsub_patterns
,&pat
);
9429 listDelNode(server
.pubsub_patterns
,ln
);
9431 /* Notify the client */
9433 addReply(c
,shared
.mbulk3
);
9434 addReply(c
,shared
.punsubscribebulk
);
9435 addReplyBulk(c
,pattern
);
9436 addReplyLong(c
,dictSize(c
->pubsub_channels
)+
9437 listLength(c
->pubsub_patterns
));
9439 decrRefCount(pattern
);
9443 /* Unsubscribe from all the channels. Return the number of channels the
9444 * client was subscribed from. */
9445 static int pubsubUnsubscribeAllChannels(redisClient
*c
, int notify
) {
9446 dictIterator
*di
= dictGetIterator(c
->pubsub_channels
);
9450 while((de
= dictNext(di
)) != NULL
) {
9451 robj
*channel
= dictGetEntryKey(de
);
9453 count
+= pubsubUnsubscribeChannel(c
,channel
,notify
);
9455 dictReleaseIterator(di
);
9459 /* Unsubscribe from all the patterns. Return the number of patterns the
9460 * client was subscribed from. */
9461 static int pubsubUnsubscribeAllPatterns(redisClient
*c
, int notify
) {
9466 listRewind(c
->pubsub_patterns
,&li
);
9467 while ((ln
= listNext(&li
)) != NULL
) {
9468 robj
*pattern
= ln
->value
;
9470 count
+= pubsubUnsubscribePattern(c
,pattern
,notify
);
9475 /* Publish a message */
9476 static int pubsubPublishMessage(robj
*channel
, robj
*message
) {
9478 struct dictEntry
*de
;
9482 /* Send to clients listening for that channel */
9483 de
= dictFind(server
.pubsub_channels
,channel
);
9485 list
*list
= dictGetEntryVal(de
);
9489 listRewind(list
,&li
);
9490 while ((ln
= listNext(&li
)) != NULL
) {
9491 redisClient
*c
= ln
->value
;
9493 addReply(c
,shared
.mbulk3
);
9494 addReply(c
,shared
.messagebulk
);
9495 addReplyBulk(c
,channel
);
9496 addReplyBulk(c
,message
);
9500 /* Send to clients listening to matching channels */
9501 if (listLength(server
.pubsub_patterns
)) {
9502 listRewind(server
.pubsub_patterns
,&li
);
9503 channel
= getDecodedObject(channel
);
9504 while ((ln
= listNext(&li
)) != NULL
) {
9505 pubsubPattern
*pat
= ln
->value
;
9507 if (stringmatchlen((char*)pat
->pattern
->ptr
,
9508 sdslen(pat
->pattern
->ptr
),
9509 (char*)channel
->ptr
,
9510 sdslen(channel
->ptr
),0)) {
9511 addReply(pat
->client
,shared
.mbulk3
);
9512 addReply(pat
->client
,shared
.messagebulk
);
9513 addReplyBulk(pat
->client
,channel
);
9514 addReplyBulk(pat
->client
,message
);
9518 decrRefCount(channel
);
9523 static void subscribeCommand(redisClient
*c
) {
9526 for (j
= 1; j
< c
->argc
; j
++)
9527 pubsubSubscribeChannel(c
,c
->argv
[j
]);
9530 static void unsubscribeCommand(redisClient
*c
) {
9532 pubsubUnsubscribeAllChannels(c
,1);
9537 for (j
= 1; j
< c
->argc
; j
++)
9538 pubsubUnsubscribeChannel(c
,c
->argv
[j
],1);
9542 static void psubscribeCommand(redisClient
*c
) {
9545 for (j
= 1; j
< c
->argc
; j
++)
9546 pubsubSubscribePattern(c
,c
->argv
[j
]);
9549 static void punsubscribeCommand(redisClient
*c
) {
9551 pubsubUnsubscribeAllPatterns(c
,1);
9556 for (j
= 1; j
< c
->argc
; j
++)
9557 pubsubUnsubscribePattern(c
,c
->argv
[j
],1);
9561 static void publishCommand(redisClient
*c
) {
9562 int receivers
= pubsubPublishMessage(c
->argv
[1],c
->argv
[2]);
9563 addReplyLong(c
,receivers
);
9566 /* ================================= Debugging ============================== */
9568 static void debugCommand(redisClient
*c
) {
9569 if (!strcasecmp(c
->argv
[1]->ptr
,"segfault")) {
9571 } else if (!strcasecmp(c
->argv
[1]->ptr
,"reload")) {
9572 if (rdbSave(server
.dbfilename
) != REDIS_OK
) {
9573 addReply(c
,shared
.err
);
9577 if (rdbLoad(server
.dbfilename
) != REDIS_OK
) {
9578 addReply(c
,shared
.err
);
9581 redisLog(REDIS_WARNING
,"DB reloaded by DEBUG RELOAD");
9582 addReply(c
,shared
.ok
);
9583 } else if (!strcasecmp(c
->argv
[1]->ptr
,"loadaof")) {
9585 if (loadAppendOnlyFile(server
.appendfilename
) != REDIS_OK
) {
9586 addReply(c
,shared
.err
);
9589 redisLog(REDIS_WARNING
,"Append Only File loaded by DEBUG LOADAOF");
9590 addReply(c
,shared
.ok
);
9591 } else if (!strcasecmp(c
->argv
[1]->ptr
,"object") && c
->argc
== 3) {
9592 dictEntry
*de
= dictFind(c
->db
->dict
,c
->argv
[2]);
9596 addReply(c
,shared
.nokeyerr
);
9599 key
= dictGetEntryKey(de
);
9600 val
= dictGetEntryVal(de
);
9601 if (!server
.vm_enabled
|| (key
->storage
== REDIS_VM_MEMORY
||
9602 key
->storage
== REDIS_VM_SWAPPING
)) {
9606 if (val
->encoding
< (sizeof(strencoding
)/sizeof(char*))) {
9607 strenc
= strencoding
[val
->encoding
];
9609 snprintf(buf
,64,"unknown encoding %d\n", val
->encoding
);
9612 addReplySds(c
,sdscatprintf(sdsempty(),
9613 "+Key at:%p refcount:%d, value at:%p refcount:%d "
9614 "encoding:%s serializedlength:%lld\r\n",
9615 (void*)key
, key
->refcount
, (void*)val
, val
->refcount
,
9616 strenc
, (long long) rdbSavedObjectLen(val
,NULL
)));
9618 addReplySds(c
,sdscatprintf(sdsempty(),
9619 "+Key at:%p refcount:%d, value swapped at: page %llu "
9620 "using %llu pages\r\n",
9621 (void*)key
, key
->refcount
, (unsigned long long) key
->vm
.page
,
9622 (unsigned long long) key
->vm
.usedpages
));
9624 } else if (!strcasecmp(c
->argv
[1]->ptr
,"swapout") && c
->argc
== 3) {
9625 dictEntry
*de
= dictFind(c
->db
->dict
,c
->argv
[2]);
9628 if (!server
.vm_enabled
) {
9629 addReplySds(c
,sdsnew("-ERR Virtual Memory is disabled\r\n"));
9633 addReply(c
,shared
.nokeyerr
);
9636 key
= dictGetEntryKey(de
);
9637 val
= dictGetEntryVal(de
);
9638 /* If the key is shared we want to create a copy */
9639 if (key
->refcount
> 1) {
9640 robj
*newkey
= dupStringObject(key
);
9642 key
= dictGetEntryKey(de
) = newkey
;
9645 if (key
->storage
!= REDIS_VM_MEMORY
) {
9646 addReplySds(c
,sdsnew("-ERR This key is not in memory\r\n"));
9647 } else if (vmSwapObjectBlocking(key
,val
) == REDIS_OK
) {
9648 dictGetEntryVal(de
) = NULL
;
9649 addReply(c
,shared
.ok
);
9651 addReply(c
,shared
.err
);
9654 addReplySds(c
,sdsnew(
9655 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPOUT <key>|RELOAD]\r\n"));
9659 static void _redisAssert(char *estr
, char *file
, int line
) {
9660 redisLog(REDIS_WARNING
,"=== ASSERTION FAILED ===");
9661 redisLog(REDIS_WARNING
,"==> %s:%d '%s' is not true\n",file
,line
,estr
);
9662 #ifdef HAVE_BACKTRACE
9663 redisLog(REDIS_WARNING
,"(forcing SIGSEGV in order to print the stack trace)");
9668 /* =================================== Main! ================================ */
9671 int linuxOvercommitMemoryValue(void) {
9672 FILE *fp
= fopen("/proc/sys/vm/overcommit_memory","r");
9676 if (fgets(buf
,64,fp
) == NULL
) {
9685 void linuxOvercommitMemoryWarning(void) {
9686 if (linuxOvercommitMemoryValue() == 0) {
9687 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.");
9690 #endif /* __linux__ */
9692 static void daemonize(void) {
9696 if (fork() != 0) exit(0); /* parent exits */
9697 setsid(); /* create a new session */
9699 /* Every output goes to /dev/null. If Redis is daemonized but
9700 * the 'logfile' is set to 'stdout' in the configuration file
9701 * it will not log at all. */
9702 if ((fd
= open("/dev/null", O_RDWR
, 0)) != -1) {
9703 dup2(fd
, STDIN_FILENO
);
9704 dup2(fd
, STDOUT_FILENO
);
9705 dup2(fd
, STDERR_FILENO
);
9706 if (fd
> STDERR_FILENO
) close(fd
);
9708 /* Try to write the pid file */
9709 fp
= fopen(server
.pidfile
,"w");
9711 fprintf(fp
,"%d\n",getpid());
9716 static void version() {
9717 printf("Redis server version %s\n", REDIS_VERSION
);
9721 static void usage() {
9722 fprintf(stderr
,"Usage: ./redis-server [/path/to/redis.conf]\n");
9723 fprintf(stderr
," ./redis-server - (read config from stdin)\n");
9727 int main(int argc
, char **argv
) {
9732 if (strcmp(argv
[1], "-v") == 0 ||
9733 strcmp(argv
[1], "--version") == 0) version();
9734 if (strcmp(argv
[1], "--help") == 0) usage();
9735 resetServerSaveParams();
9736 loadServerConfig(argv
[1]);
9737 } else if ((argc
> 2)) {
9740 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'");
9742 if (server
.daemonize
) daemonize();
9744 redisLog(REDIS_NOTICE
,"Server started, Redis version " REDIS_VERSION
);
9746 linuxOvercommitMemoryWarning();
9749 if (server
.appendonly
) {
9750 if (loadAppendOnlyFile(server
.appendfilename
) == REDIS_OK
)
9751 redisLog(REDIS_NOTICE
,"DB loaded from append only file: %ld seconds",time(NULL
)-start
);
9753 if (rdbLoad(server
.dbfilename
) == REDIS_OK
)
9754 redisLog(REDIS_NOTICE
,"DB loaded from disk: %ld seconds",time(NULL
)-start
);
9756 redisLog(REDIS_NOTICE
,"The server is now ready to accept connections on port %d", server
.port
);
9757 aeSetBeforeSleepProc(server
.el
,beforeSleep
);
9759 aeDeleteEventLoop(server
.el
);
9763 /* ============================= Backtrace support ========================= */
9765 #ifdef HAVE_BACKTRACE
9766 static char *findFuncName(void *pointer
, unsigned long *offset
);
9768 static void *getMcontextEip(ucontext_t
*uc
) {
9769 #if defined(__FreeBSD__)
9770 return (void*) uc
->uc_mcontext
.mc_eip
;
9771 #elif defined(__dietlibc__)
9772 return (void*) uc
->uc_mcontext
.eip
;
9773 #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
9775 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
9777 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
9779 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
9780 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
9781 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
9783 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
9785 #elif defined(__i386__) || defined(__X86_64__) || defined(__x86_64__)
9786 return (void*) uc
->uc_mcontext
.gregs
[REG_EIP
]; /* Linux 32/64 bit */
9787 #elif defined(__ia64__) /* Linux IA64 */
9788 return (void*) uc
->uc_mcontext
.sc_ip
;
9794 static void segvHandler(int sig
, siginfo_t
*info
, void *secret
) {
9796 char **messages
= NULL
;
9797 int i
, trace_size
= 0;
9798 unsigned long offset
=0;
9799 ucontext_t
*uc
= (ucontext_t
*) secret
;
9801 REDIS_NOTUSED(info
);
9803 redisLog(REDIS_WARNING
,
9804 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION
, sig
);
9805 infostring
= genRedisInfoString();
9806 redisLog(REDIS_WARNING
, "%s",infostring
);
9807 /* It's not safe to sdsfree() the returned string under memory
9808 * corruption conditions. Let it leak as we are going to abort */
9810 trace_size
= backtrace(trace
, 100);
9811 /* overwrite sigaction with caller's address */
9812 if (getMcontextEip(uc
) != NULL
) {
9813 trace
[1] = getMcontextEip(uc
);
9815 messages
= backtrace_symbols(trace
, trace_size
);
9817 for (i
=1; i
<trace_size
; ++i
) {
9818 char *fn
= findFuncName(trace
[i
], &offset
), *p
;
9820 p
= strchr(messages
[i
],'+');
9821 if (!fn
|| (p
&& ((unsigned long)strtol(p
+1,NULL
,10)) < offset
)) {
9822 redisLog(REDIS_WARNING
,"%s", messages
[i
]);
9824 redisLog(REDIS_WARNING
,"%d redis-server %p %s + %d", i
, trace
[i
], fn
, (unsigned int)offset
);
9827 /* free(messages); Don't call free() with possibly corrupted memory. */
9831 static void setupSigSegvAction(void) {
9832 struct sigaction act
;
9834 sigemptyset (&act
.sa_mask
);
9835 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
9836 * is used. Otherwise, sa_handler is used */
9837 act
.sa_flags
= SA_NODEFER
| SA_ONSTACK
| SA_RESETHAND
| SA_SIGINFO
;
9838 act
.sa_sigaction
= segvHandler
;
9839 sigaction (SIGSEGV
, &act
, NULL
);
9840 sigaction (SIGBUS
, &act
, NULL
);
9841 sigaction (SIGFPE
, &act
, NULL
);
9842 sigaction (SIGILL
, &act
, NULL
);
9843 sigaction (SIGBUS
, &act
, NULL
);
9847 #include "staticsymbols.h"
9848 /* This function try to convert a pointer into a function name. It's used in
9849 * oreder to provide a backtrace under segmentation fault that's able to
9850 * display functions declared as static (otherwise the backtrace is useless). */
9851 static char *findFuncName(void *pointer
, unsigned long *offset
){
9853 unsigned long off
, minoff
= 0;
9855 /* Try to match against the Symbol with the smallest offset */
9856 for (i
=0; symsTable
[i
].pointer
; i
++) {
9857 unsigned long lp
= (unsigned long) pointer
;
9859 if (lp
!= (unsigned long)-1 && lp
>= symsTable
[i
].pointer
) {
9860 off
=lp
-symsTable
[i
].pointer
;
9861 if (ret
< 0 || off
< minoff
) {
9867 if (ret
== -1) return NULL
;
9869 return symsTable
[ret
].name
;
9871 #else /* HAVE_BACKTRACE */
9872 static void setupSigSegvAction(void) {
9874 #endif /* HAVE_BACKTRACE */