]> git.saurik.com Git - redis.git/blob - redis.c
f929828ba2a80d1eac18446614bf74f2023e8877
[redis.git] / redis.c
1 /*
2 * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
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.
16 *
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.
28 */
29
30 #define REDIS_VERSION "1.3.8"
31
32 #include "fmacros.h"
33 #include "config.h"
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <time.h>
39 #include <unistd.h>
40 #define __USE_POSIX199309
41 #define __USE_UNIX98
42 #include <signal.h>
43
44 #ifdef HAVE_BACKTRACE
45 #include <execinfo.h>
46 #include <ucontext.h>
47 #endif /* HAVE_BACKTRACE */
48
49 #include <sys/wait.h>
50 #include <errno.h>
51 #include <assert.h>
52 #include <ctype.h>
53 #include <stdarg.h>
54 #include <inttypes.h>
55 #include <arpa/inet.h>
56 #include <sys/stat.h>
57 #include <fcntl.h>
58 #include <sys/time.h>
59 #include <sys/resource.h>
60 #include <sys/uio.h>
61 #include <limits.h>
62 #include <math.h>
63 #include <pthread.h>
64
65 #if defined(__sun)
66 #include "solarisfixes.h"
67 #endif
68
69 #include "redis.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 */
78 #include "zipmap.h"
79
80 /* Error codes */
81 #define REDIS_OK 0
82 #define REDIS_ERR -1
83
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 */
97
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
102
103 /* Hash table parameters */
104 #define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
105
106 /* Command flags */
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 */
115
116 /* Object types */
117 #define REDIS_STRING 0
118 #define REDIS_LIST 1
119 #define REDIS_SET 2
120 #define REDIS_ZSET 3
121 #define REDIS_HASH 4
122
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 */
130
131 static char* strencoding[] = {
132 "raw", "int", "zipmap", "hashtable"
133 };
134
135 /* Object types only used for dumping to disk */
136 #define REDIS_EXPIRETIME 253
137 #define REDIS_SELECTDB 254
138 #define REDIS_EOF 255
139
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:
143 *
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.
150 *
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
158
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 */
166
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 */
172
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
184
185 /* Client flags */
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 */
192
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 */
197
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 */
206
207 /* List related stuff */
208 #define REDIS_HEAD 0
209 #define REDIS_TAIL 1
210
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
216
217 /* Log levels */
218 #define REDIS_DEBUG 0
219 #define REDIS_VERBOSE 1
220 #define REDIS_NOTICE 2
221 #define REDIS_WARNING 3
222
223 /* Anti-warning macro... */
224 #define REDIS_NOTUSED(V) ((void) V)
225
226 #define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
227 #define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
228
229 /* Append only defines */
230 #define APPENDFSYNC_NO 0
231 #define APPENDFSYNC_ALWAYS 1
232 #define APPENDFSYNC_EVERYSEC 2
233
234 /* Hashes related defaults */
235 #define REDIS_HASH_MAX_ZIPMAP_ENTRIES 64
236 #define REDIS_HASH_MAX_ZIPMAP_VALUE 512
237
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);
241
242 /*================================= Data types ============================== */
243
244 /* A redis object, that is a type able to hold a string / list / set */
245
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 */
251 } vm;
252
253 /* The actual Redis Object */
254 typedef struct redisObject {
255 void *ptr;
256 unsigned char type;
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. */
262 int refcount;
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;
268 } robj;
269
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 { \
275 _var.refcount = 1; \
276 _var.type = REDIS_STRING; \
277 _var.encoding = REDIS_ENCODING_RAW; \
278 _var.ptr = _ptr; \
279 if (server.vm_enabled) _var.storage = REDIS_VM_MEMORY; \
280 } while(0);
281
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 */
287 int id;
288 } redisDb;
289
290 /* Client MULTI/EXEC state */
291 typedef struct multiCmd {
292 robj **argv;
293 int argc;
294 struct redisCommand *cmd;
295 } multiCmd;
296
297 typedef struct multiState {
298 multiCmd *commands; /* Array of MULTI commands */
299 int count; /* Total number of MULTI commands */
300 } multiState;
301
302 /* With multiplexing we need to take per-clinet state.
303 * Clients are taken in a liked list. */
304 typedef struct redisClient {
305 int fd;
306 redisDb *db;
307 int dictid;
308 sds querybuf;
309 robj **argv, **mbargv;
310 int argc, mbargc;
311 int bulklen; /* bulk read len. -1 if not in bulk read mode */
312 int multibulk; /* multi bulk command format active */
313 list *reply;
314 int sentlen;
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) */
333 } redisClient;
334
335 struct saveparam {
336 time_t seconds;
337 int changes;
338 };
339
340 /* Global server state structure */
341 struct redisServer {
342 int port;
343 int fd;
344 redisDb *db;
345 dict *sharingpool; /* Poll used for object sharing */
346 unsigned int sharingpoolsize;
347 long long dirty; /* changes to DB from the last save */
348 list *clients;
349 list *slaves, *monitors;
350 char neterr[ANET_ERR_LEN];
351 aeEventLoop *el;
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 */
360 /* Configuration */
361 int verbosity;
362 int glueoutputbuf;
363 int maxidletime;
364 int dbnum;
365 int daemonize;
366 int appendonly;
367 int appendfsync;
368 time_t lastfsync;
369 int appendfd;
370 int appendseldb;
371 char *pidfile;
372 pid_t bgsavechildpid;
373 pid_t bgrewritechildpid;
374 sds bgrewritebuf; /* buffer taken by parent during oppend only rewrite */
375 struct saveparam *saveparams;
376 int saveparamslen;
377 char *logfile;
378 char *bindaddr;
379 char *dbfilename;
380 char *appendfilename;
381 char *requirepass;
382 int shareobjects;
383 int rdbcompression;
384 /* Replication related */
385 int isslave;
386 char *masterauth;
387 char *masterhost;
388 int masterport;
389 redisClient *master; /* client that is master for this slave */
390 int replstate;
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() */
397 int sort_desc;
398 int sort_alpha;
399 int sort_bypattern;
400 /* Virtual memory configuration */
401 int vm_enabled;
402 char *vm_swap_file;
403 off_t vm_page_size;
404 off_t vm_pages;
405 unsigned long long vm_max_memory;
406 /* Hashes config */
407 size_t hash_max_zipmap_entries;
408 size_t hash_max_zipmap_value;
409 /* Virtual memory state */
410 FILE *vm_fp;
411 int vm_fd;
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;
441 /* Pubsub */
442 dict *pubsub_channels; /* Map channels to list of subscribed clients */
443 list *pubsub_patterns; /* A list of pubsub_patterns */
444 /* Misc */
445 FILE *devnull;
446 };
447
448 typedef struct pubsubPattern {
449 redisClient *client;
450 robj *pattern;
451 } pubsubPattern;
452
453 typedef void redisCommandProc(redisClient *c);
454 struct redisCommand {
455 char *name;
456 redisCommandProc *proc;
457 int arity;
458 int flags;
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 */
467 };
468
469 struct redisFunctionSym {
470 char *name;
471 unsigned long pointer;
472 };
473
474 typedef struct _redisSortObject {
475 robj *obj;
476 union {
477 double score;
478 robj *cmpobj;
479 } u;
480 } redisSortObject;
481
482 typedef struct _redisSortOperation {
483 int type;
484 robj *pattern;
485 } redisSortOperation;
486
487 /* ZSETs use a specialized version of Skiplists */
488
489 typedef struct zskiplistNode {
490 struct zskiplistNode **forward;
491 struct zskiplistNode *backward;
492 unsigned int *span;
493 double score;
494 robj *obj;
495 } zskiplistNode;
496
497 typedef struct zskiplist {
498 struct zskiplistNode *header, *tail;
499 unsigned long length;
500 int level;
501 } zskiplist;
502
503 typedef struct zset {
504 dict *dict;
505 zskiplist *zsl;
506 } zset;
507
508 /* Our shared "common" objects */
509
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;
519 } shared;
520
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. */
524
525 static double R_Zero, R_PosInf, R_NegInf, R_Nan;
526
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 */
541 } iojob;
542
543 /*================================ Prototypes =============================== */
544
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);
623 static void usage();
624
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);
726
727 /*================================= Globals ================================= */
728
729 /* Global vars */
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}
835 };
836
837 /*============================ Utility functions ============================ */
838
839 /* Glob-style pattern matching. */
840 static int stringmatchlen(const char *pattern, int patternLen,
841 const char *string, int stringLen, int nocase)
842 {
843 while(patternLen) {
844 switch(pattern[0]) {
845 case '*':
846 while (pattern[1] == '*') {
847 pattern++;
848 patternLen--;
849 }
850 if (patternLen == 1)
851 return 1; /* match */
852 while(stringLen) {
853 if (stringmatchlen(pattern+1, patternLen-1,
854 string, stringLen, nocase))
855 return 1; /* match */
856 string++;
857 stringLen--;
858 }
859 return 0; /* no match */
860 break;
861 case '?':
862 if (stringLen == 0)
863 return 0; /* no match */
864 string++;
865 stringLen--;
866 break;
867 case '[':
868 {
869 int not, match;
870
871 pattern++;
872 patternLen--;
873 not = pattern[0] == '^';
874 if (not) {
875 pattern++;
876 patternLen--;
877 }
878 match = 0;
879 while(1) {
880 if (pattern[0] == '\\') {
881 pattern++;
882 patternLen--;
883 if (pattern[0] == string[0])
884 match = 1;
885 } else if (pattern[0] == ']') {
886 break;
887 } else if (patternLen == 0) {
888 pattern--;
889 patternLen++;
890 break;
891 } else if (pattern[1] == '-' && patternLen >= 3) {
892 int start = pattern[0];
893 int end = pattern[2];
894 int c = string[0];
895 if (start > end) {
896 int t = start;
897 start = end;
898 end = t;
899 }
900 if (nocase) {
901 start = tolower(start);
902 end = tolower(end);
903 c = tolower(c);
904 }
905 pattern += 2;
906 patternLen -= 2;
907 if (c >= start && c <= end)
908 match = 1;
909 } else {
910 if (!nocase) {
911 if (pattern[0] == string[0])
912 match = 1;
913 } else {
914 if (tolower((int)pattern[0]) == tolower((int)string[0]))
915 match = 1;
916 }
917 }
918 pattern++;
919 patternLen--;
920 }
921 if (not)
922 match = !match;
923 if (!match)
924 return 0; /* no match */
925 string++;
926 stringLen--;
927 break;
928 }
929 case '\\':
930 if (patternLen >= 2) {
931 pattern++;
932 patternLen--;
933 }
934 /* fall through */
935 default:
936 if (!nocase) {
937 if (pattern[0] != string[0])
938 return 0; /* no match */
939 } else {
940 if (tolower((int)pattern[0]) != tolower((int)string[0]))
941 return 0; /* no match */
942 }
943 string++;
944 stringLen--;
945 break;
946 }
947 pattern++;
948 patternLen--;
949 if (stringLen == 0) {
950 while(*pattern == '*') {
951 pattern++;
952 patternLen--;
953 }
954 break;
955 }
956 }
957 if (patternLen == 0 && stringLen == 0)
958 return 1;
959 return 0;
960 }
961
962 static int stringmatch(const char *pattern, const char *string, int nocase) {
963 return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
964 }
965
966 static void redisLog(int level, const char *fmt, ...) {
967 va_list ap;
968 FILE *fp;
969
970 fp = (server.logfile == NULL) ? stdout : fopen(server.logfile,"a");
971 if (!fp) return;
972
973 va_start(ap, fmt);
974 if (level >= server.verbosity) {
975 char *c = ".-*#";
976 char buf[64];
977 time_t now;
978
979 now = time(NULL);
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);
983 fprintf(fp,"\n");
984 fflush(fp);
985 }
986 va_end(ap);
987
988 if (server.logfile) fclose(fp);
989 }
990
991 /*====================== Hash table type implementation ==================== */
992
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,
995 * lists, sets). */
996
997 static void dictVanillaFree(void *privdata, void *val)
998 {
999 DICT_NOTUSED(privdata);
1000 zfree(val);
1001 }
1002
1003 static void dictListDestructor(void *privdata, void *val)
1004 {
1005 DICT_NOTUSED(privdata);
1006 listRelease((list*)val);
1007 }
1008
1009 static int sdsDictKeyCompare(void *privdata, const void *key1,
1010 const void *key2)
1011 {
1012 int l1,l2;
1013 DICT_NOTUSED(privdata);
1014
1015 l1 = sdslen((sds)key1);
1016 l2 = sdslen((sds)key2);
1017 if (l1 != l2) return 0;
1018 return memcmp(key1, key2, l1) == 0;
1019 }
1020
1021 static void dictRedisObjectDestructor(void *privdata, void *val)
1022 {
1023 DICT_NOTUSED(privdata);
1024
1025 if (val == NULL) return; /* Values of swapped out keys as set to NULL */
1026 decrRefCount(val);
1027 }
1028
1029 static int dictObjKeyCompare(void *privdata, const void *key1,
1030 const void *key2)
1031 {
1032 const robj *o1 = key1, *o2 = key2;
1033 return sdsDictKeyCompare(privdata,o1->ptr,o2->ptr);
1034 }
1035
1036 static unsigned int dictObjHash(const void *key) {
1037 const robj *o = key;
1038 return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
1039 }
1040
1041 static int dictEncObjKeyCompare(void *privdata, const void *key1,
1042 const void *key2)
1043 {
1044 robj *o1 = (robj*) key1, *o2 = (robj*) key2;
1045 int cmp;
1046
1047 if (o1->encoding == REDIS_ENCODING_INT &&
1048 o2->encoding == REDIS_ENCODING_INT &&
1049 o1->ptr == o2->ptr) return 1;
1050
1051 o1 = getDecodedObject(o1);
1052 o2 = getDecodedObject(o2);
1053 cmp = sdsDictKeyCompare(privdata,o1->ptr,o2->ptr);
1054 decrRefCount(o1);
1055 decrRefCount(o2);
1056 return cmp;
1057 }
1058
1059 static unsigned int dictEncObjHash(const void *key) {
1060 robj *o = (robj*) key;
1061
1062 if (o->encoding == REDIS_ENCODING_RAW) {
1063 return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
1064 } else {
1065 if (o->encoding == REDIS_ENCODING_INT) {
1066 char buf[32];
1067 int len;
1068
1069 len = snprintf(buf,32,"%ld",(long)o->ptr);
1070 return dictGenHashFunction((unsigned char*)buf, len);
1071 } else {
1072 unsigned int hash;
1073
1074 o = getDecodedObject(o);
1075 hash = dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
1076 decrRefCount(o);
1077 return hash;
1078 }
1079 }
1080 }
1081
1082 /* Sets type and expires */
1083 static dictType setDictType = {
1084 dictEncObjHash, /* hash function */
1085 NULL, /* key dup */
1086 NULL, /* val dup */
1087 dictEncObjKeyCompare, /* key compare */
1088 dictRedisObjectDestructor, /* key destructor */
1089 NULL /* val destructor */
1090 };
1091
1092 /* Sorted sets hash (note: a skiplist is used in addition to the hash table) */
1093 static dictType zsetDictType = {
1094 dictEncObjHash, /* hash function */
1095 NULL, /* key dup */
1096 NULL, /* val dup */
1097 dictEncObjKeyCompare, /* key compare */
1098 dictRedisObjectDestructor, /* key destructor */
1099 dictVanillaFree /* val destructor of malloc(sizeof(double)) */
1100 };
1101
1102 /* Db->dict */
1103 static dictType dbDictType = {
1104 dictObjHash, /* hash function */
1105 NULL, /* key dup */
1106 NULL, /* val dup */
1107 dictObjKeyCompare, /* key compare */
1108 dictRedisObjectDestructor, /* key destructor */
1109 dictRedisObjectDestructor /* val destructor */
1110 };
1111
1112 /* Db->expires */
1113 static dictType keyptrDictType = {
1114 dictObjHash, /* hash function */
1115 NULL, /* key dup */
1116 NULL, /* val dup */
1117 dictObjKeyCompare, /* key compare */
1118 dictRedisObjectDestructor, /* key destructor */
1119 NULL /* val destructor */
1120 };
1121
1122 /* Hash type hash table (note that small hashes are represented with zimpaps) */
1123 static dictType hashDictType = {
1124 dictEncObjHash, /* hash function */
1125 NULL, /* key dup */
1126 NULL, /* val dup */
1127 dictEncObjKeyCompare, /* key compare */
1128 dictRedisObjectDestructor, /* key destructor */
1129 dictRedisObjectDestructor /* val destructor */
1130 };
1131
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 */
1137 NULL, /* key dup */
1138 NULL, /* val dup */
1139 dictObjKeyCompare, /* key compare */
1140 dictRedisObjectDestructor, /* key destructor */
1141 dictListDestructor /* val destructor */
1142 };
1143
1144 static void version();
1145
1146 /* ========================= Random utility functions ======================= */
1147
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);
1155 sleep(1);
1156 abort();
1157 }
1158
1159 /* ====================== Redis server networking stuff ===================== */
1160 static void closeTimedoutClients(void) {
1161 redisClient *c;
1162 listNode *ln;
1163 time_t now = time(NULL);
1164 listIter li;
1165
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))
1175 {
1176 redisLog(REDIS_VERBOSE,"Closing idle client");
1177 freeClient(c);
1178 } else if (c->flags & REDIS_BLOCKED) {
1179 if (c->blockingto != 0 && c->blockingto < now) {
1180 addReply(c,shared.nullmultibulk);
1181 unblockClientWaitingData(c);
1182 }
1183 }
1184 }
1185 }
1186
1187 static int htNeedsResize(dict *dict) {
1188 long long size, used;
1189
1190 size = dictSlots(dict);
1191 used = dictSize(dict);
1192 return (size && used && size > DICT_HT_INITIAL_SIZE &&
1193 (used*100/size < REDIS_HT_MINFILL));
1194 }
1195
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) {
1199 int j;
1200
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);
1206 }
1207 if (htNeedsResize(server.db[j].expires))
1208 dictResize(server.db[j].expires);
1209 }
1210 }
1211
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);
1216
1217 if (!bysignal && exitcode == 0) {
1218 redisLog(REDIS_NOTICE,
1219 "Background saving terminated with success");
1220 server.dirty = 0;
1221 server.lastsave = time(NULL);
1222 } else if (!bysignal && exitcode != 0) {
1223 redisLog(REDIS_WARNING, "Background saving error");
1224 } else {
1225 redisLog(REDIS_WARNING,
1226 "Background saving terminated by signal %d", WTERMSIG(statloc));
1227 rdbRemoveTempFile(server.bgsavechildpid);
1228 }
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);
1233 }
1234
1235 /* A background append only file rewriting (BGREWRITEAOF) terminated its work.
1236 * Handle this. */
1237 void backgroundRewriteDoneHandler(int statloc) {
1238 int exitcode = WEXITSTATUS(statloc);
1239 int bysignal = WIFSIGNALED(statloc);
1240
1241 if (!bysignal && exitcode == 0) {
1242 int fd;
1243 char tmpfile[256];
1244
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);
1250 if (fd == -1) {
1251 redisLog(REDIS_WARNING, "Not able to open the temp append only file produced by the child: %s", strerror(errno));
1252 goto cleanup;
1253 }
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));
1258 close(fd);
1259 goto cleanup;
1260 }
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));
1266 close(fd);
1267 goto cleanup;
1268 }
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;
1275 fsync(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.");
1278 } else {
1279 /* If append only is disabled we just generate a dump in this
1280 * format. Why not? */
1281 close(fd);
1282 }
1283 } else if (!bysignal && exitcode != 0) {
1284 redisLog(REDIS_WARNING, "Background append only file rewriting error");
1285 } else {
1286 redisLog(REDIS_WARNING,
1287 "Background append only file rewriting terminated by signal %d",
1288 WTERMSIG(statloc));
1289 }
1290 cleanup:
1291 sdsfree(server.bgrewritebuf);
1292 server.bgrewritebuf = sdsempty();
1293 aofRemoveTempFile(server.bgrewritechildpid);
1294 server.bgrewritechildpid = -1;
1295 }
1296
1297 /* This function is called once a background process of some kind terminates,
1298 * as we want to avoid resizing the hash tables when there is a child in order
1299 * to play well with copy-on-write (otherwise when a resize happens lots of
1300 * memory pages are copied). The goal of this function is to update the ability
1301 * for dict.c to resize the hash tables accordingly to the fact we have o not
1302 * running childs. */
1303 static void updateDictResizePolicy(void) {
1304 if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1)
1305 dictEnableResize();
1306 else
1307 dictDisableResize();
1308 }
1309
1310 static int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
1311 int j, loops = server.cronloops++;
1312 REDIS_NOTUSED(eventLoop);
1313 REDIS_NOTUSED(id);
1314 REDIS_NOTUSED(clientData);
1315
1316 /* We take a cached value of the unix time in the global state because
1317 * with virtual memory and aging there is to store the current time
1318 * in objects at every object access, and accuracy is not needed.
1319 * To access a global var is faster than calling time(NULL) */
1320 server.unixtime = time(NULL);
1321
1322 /* Show some info about non-empty databases */
1323 for (j = 0; j < server.dbnum; j++) {
1324 long long size, used, vkeys;
1325
1326 size = dictSlots(server.db[j].dict);
1327 used = dictSize(server.db[j].dict);
1328 vkeys = dictSize(server.db[j].expires);
1329 if (!(loops % 50) && (used || vkeys)) {
1330 redisLog(REDIS_VERBOSE,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j,used,vkeys,size);
1331 /* dictPrintStats(server.dict); */
1332 }
1333 }
1334
1335 /* We don't want to resize the hash tables while a bacground saving
1336 * is in progress: the saving child is created using fork() that is
1337 * implemented with a copy-on-write semantic in most modern systems, so
1338 * if we resize the HT while there is the saving child at work actually
1339 * a lot of memory movements in the parent will cause a lot of pages
1340 * copied. */
1341 if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1 &&
1342 !(loops % 10))
1343 {
1344 tryResizeHashTables();
1345 }
1346
1347 /* Show information about connected clients */
1348 if (!(loops % 50)) {
1349 redisLog(REDIS_VERBOSE,"%d clients connected (%d slaves), %zu bytes in use, %d shared objects",
1350 listLength(server.clients)-listLength(server.slaves),
1351 listLength(server.slaves),
1352 zmalloc_used_memory(),
1353 dictSize(server.sharingpool));
1354 }
1355
1356 /* Close connections of timedout clients */
1357 if ((server.maxidletime && !(loops % 100)) || server.blpop_blocked_clients)
1358 closeTimedoutClients();
1359
1360 /* Check if a background saving or AOF rewrite in progress terminated */
1361 if (server.bgsavechildpid != -1 || server.bgrewritechildpid != -1) {
1362 int statloc;
1363 pid_t pid;
1364
1365 if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
1366 if (pid == server.bgsavechildpid) {
1367 backgroundSaveDoneHandler(statloc);
1368 } else {
1369 backgroundRewriteDoneHandler(statloc);
1370 }
1371 updateDictResizePolicy();
1372 }
1373 } else {
1374 /* If there is not a background saving in progress check if
1375 * we have to save now */
1376 time_t now = time(NULL);
1377 for (j = 0; j < server.saveparamslen; j++) {
1378 struct saveparam *sp = server.saveparams+j;
1379
1380 if (server.dirty >= sp->changes &&
1381 now-server.lastsave > sp->seconds) {
1382 redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...",
1383 sp->changes, sp->seconds);
1384 rdbSaveBackground(server.dbfilename);
1385 break;
1386 }
1387 }
1388 }
1389
1390 /* Try to expire a few timed out keys. The algorithm used is adaptive and
1391 * will use few CPU cycles if there are few expiring keys, otherwise
1392 * it will get more aggressive to avoid that too much memory is used by
1393 * keys that can be removed from the keyspace. */
1394 for (j = 0; j < server.dbnum; j++) {
1395 int expired;
1396 redisDb *db = server.db+j;
1397
1398 /* Continue to expire if at the end of the cycle more than 25%
1399 * of the keys were expired. */
1400 do {
1401 long num = dictSize(db->expires);
1402 time_t now = time(NULL);
1403
1404 expired = 0;
1405 if (num > REDIS_EXPIRELOOKUPS_PER_CRON)
1406 num = REDIS_EXPIRELOOKUPS_PER_CRON;
1407 while (num--) {
1408 dictEntry *de;
1409 time_t t;
1410
1411 if ((de = dictGetRandomKey(db->expires)) == NULL) break;
1412 t = (time_t) dictGetEntryVal(de);
1413 if (now > t) {
1414 deleteKey(db,dictGetEntryKey(de));
1415 expired++;
1416 server.stat_expiredkeys++;
1417 }
1418 }
1419 } while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/4);
1420 }
1421
1422 /* Swap a few keys on disk if we are over the memory limit and VM
1423 * is enbled. Try to free objects from the free list first. */
1424 if (vmCanSwapOut()) {
1425 while (server.vm_enabled && zmalloc_used_memory() >
1426 server.vm_max_memory)
1427 {
1428 int retval;
1429
1430 if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
1431 retval = (server.vm_max_threads == 0) ?
1432 vmSwapOneObjectBlocking() :
1433 vmSwapOneObjectThreaded();
1434 if (retval == REDIS_ERR && !(loops % 300) &&
1435 zmalloc_used_memory() >
1436 (server.vm_max_memory+server.vm_max_memory/10))
1437 {
1438 redisLog(REDIS_WARNING,"WARNING: vm-max-memory limit exceeded by more than 10%% but unable to swap more objects out!");
1439 }
1440 /* Note that when using threade I/O we free just one object,
1441 * because anyway when the I/O thread in charge to swap this
1442 * object out will finish, the handler of completed jobs
1443 * will try to swap more objects if we are still out of memory. */
1444 if (retval == REDIS_ERR || server.vm_max_threads > 0) break;
1445 }
1446 }
1447
1448 /* Check if we should connect to a MASTER */
1449 if (server.replstate == REDIS_REPL_CONNECT && !(loops % 10)) {
1450 redisLog(REDIS_NOTICE,"Connecting to MASTER...");
1451 if (syncWithMaster() == REDIS_OK) {
1452 redisLog(REDIS_NOTICE,"MASTER <-> SLAVE sync succeeded");
1453 }
1454 }
1455 return 100;
1456 }
1457
1458 /* This function gets called every time Redis is entering the
1459 * main loop of the event driven library, that is, before to sleep
1460 * for ready file descriptors. */
1461 static void beforeSleep(struct aeEventLoop *eventLoop) {
1462 REDIS_NOTUSED(eventLoop);
1463
1464 if (server.vm_enabled && listLength(server.io_ready_clients)) {
1465 listIter li;
1466 listNode *ln;
1467
1468 listRewind(server.io_ready_clients,&li);
1469 while((ln = listNext(&li))) {
1470 redisClient *c = ln->value;
1471 struct redisCommand *cmd;
1472
1473 /* Resume the client. */
1474 listDelNode(server.io_ready_clients,ln);
1475 c->flags &= (~REDIS_IO_WAIT);
1476 server.vm_blocked_clients--;
1477 aeCreateFileEvent(server.el, c->fd, AE_READABLE,
1478 readQueryFromClient, c);
1479 cmd = lookupCommand(c->argv[0]->ptr);
1480 assert(cmd != NULL);
1481 call(c,cmd);
1482 resetClient(c);
1483 /* There may be more data to process in the input buffer. */
1484 if (c->querybuf && sdslen(c->querybuf) > 0)
1485 processInputBuffer(c);
1486 }
1487 }
1488 }
1489
1490 static void createSharedObjects(void) {
1491 shared.crlf = createObject(REDIS_STRING,sdsnew("\r\n"));
1492 shared.ok = createObject(REDIS_STRING,sdsnew("+OK\r\n"));
1493 shared.err = createObject(REDIS_STRING,sdsnew("-ERR\r\n"));
1494 shared.emptybulk = createObject(REDIS_STRING,sdsnew("$0\r\n\r\n"));
1495 shared.czero = createObject(REDIS_STRING,sdsnew(":0\r\n"));
1496 shared.cone = createObject(REDIS_STRING,sdsnew(":1\r\n"));
1497 shared.nullbulk = createObject(REDIS_STRING,sdsnew("$-1\r\n"));
1498 shared.nullmultibulk = createObject(REDIS_STRING,sdsnew("*-1\r\n"));
1499 shared.emptymultibulk = createObject(REDIS_STRING,sdsnew("*0\r\n"));
1500 shared.pong = createObject(REDIS_STRING,sdsnew("+PONG\r\n"));
1501 shared.queued = createObject(REDIS_STRING,sdsnew("+QUEUED\r\n"));
1502 shared.wrongtypeerr = createObject(REDIS_STRING,sdsnew(
1503 "-ERR Operation against a key holding the wrong kind of value\r\n"));
1504 shared.nokeyerr = createObject(REDIS_STRING,sdsnew(
1505 "-ERR no such key\r\n"));
1506 shared.syntaxerr = createObject(REDIS_STRING,sdsnew(
1507 "-ERR syntax error\r\n"));
1508 shared.sameobjecterr = createObject(REDIS_STRING,sdsnew(
1509 "-ERR source and destination objects are the same\r\n"));
1510 shared.outofrangeerr = createObject(REDIS_STRING,sdsnew(
1511 "-ERR index out of range\r\n"));
1512 shared.space = createObject(REDIS_STRING,sdsnew(" "));
1513 shared.colon = createObject(REDIS_STRING,sdsnew(":"));
1514 shared.plus = createObject(REDIS_STRING,sdsnew("+"));
1515 shared.select0 = createStringObject("select 0\r\n",10);
1516 shared.select1 = createStringObject("select 1\r\n",10);
1517 shared.select2 = createStringObject("select 2\r\n",10);
1518 shared.select3 = createStringObject("select 3\r\n",10);
1519 shared.select4 = createStringObject("select 4\r\n",10);
1520 shared.select5 = createStringObject("select 5\r\n",10);
1521 shared.select6 = createStringObject("select 6\r\n",10);
1522 shared.select7 = createStringObject("select 7\r\n",10);
1523 shared.select8 = createStringObject("select 8\r\n",10);
1524 shared.select9 = createStringObject("select 9\r\n",10);
1525 shared.messagebulk = createStringObject("$7\r\nmessage\r\n",13);
1526 shared.subscribebulk = createStringObject("$9\r\nsubscribe\r\n",15);
1527 shared.unsubscribebulk = createStringObject("$11\r\nunsubscribe\r\n",18);
1528 shared.psubscribebulk = createStringObject("$10\r\npsubscribe\r\n",17);
1529 shared.punsubscribebulk = createStringObject("$12\r\npunsubscribe\r\n",19);
1530 shared.mbulk3 = createStringObject("*3\r\n",4);
1531 }
1532
1533 static void appendServerSaveParams(time_t seconds, int changes) {
1534 server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));
1535 server.saveparams[server.saveparamslen].seconds = seconds;
1536 server.saveparams[server.saveparamslen].changes = changes;
1537 server.saveparamslen++;
1538 }
1539
1540 static void resetServerSaveParams() {
1541 zfree(server.saveparams);
1542 server.saveparams = NULL;
1543 server.saveparamslen = 0;
1544 }
1545
1546 static void initServerConfig() {
1547 server.dbnum = REDIS_DEFAULT_DBNUM;
1548 server.port = REDIS_SERVERPORT;
1549 server.verbosity = REDIS_VERBOSE;
1550 server.maxidletime = REDIS_MAXIDLETIME;
1551 server.saveparams = NULL;
1552 server.logfile = NULL; /* NULL = log on standard output */
1553 server.bindaddr = NULL;
1554 server.glueoutputbuf = 1;
1555 server.daemonize = 0;
1556 server.appendonly = 0;
1557 server.appendfsync = APPENDFSYNC_ALWAYS;
1558 server.lastfsync = time(NULL);
1559 server.appendfd = -1;
1560 server.appendseldb = -1; /* Make sure the first time will not match */
1561 server.pidfile = zstrdup("/var/run/redis.pid");
1562 server.dbfilename = zstrdup("dump.rdb");
1563 server.appendfilename = zstrdup("appendonly.aof");
1564 server.requirepass = NULL;
1565 server.shareobjects = 0;
1566 server.rdbcompression = 1;
1567 server.sharingpoolsize = 1024;
1568 server.maxclients = 0;
1569 server.blpop_blocked_clients = 0;
1570 server.maxmemory = 0;
1571 server.vm_enabled = 0;
1572 server.vm_swap_file = zstrdup("/tmp/redis-%p.vm");
1573 server.vm_page_size = 256; /* 256 bytes per page */
1574 server.vm_pages = 1024*1024*100; /* 104 millions of pages */
1575 server.vm_max_memory = 1024LL*1024*1024*1; /* 1 GB of RAM */
1576 server.vm_max_threads = 4;
1577 server.vm_blocked_clients = 0;
1578 server.hash_max_zipmap_entries = REDIS_HASH_MAX_ZIPMAP_ENTRIES;
1579 server.hash_max_zipmap_value = REDIS_HASH_MAX_ZIPMAP_VALUE;
1580
1581 resetServerSaveParams();
1582
1583 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
1584 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
1585 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1586 /* Replication related */
1587 server.isslave = 0;
1588 server.masterauth = NULL;
1589 server.masterhost = NULL;
1590 server.masterport = 6379;
1591 server.master = NULL;
1592 server.replstate = REDIS_REPL_NONE;
1593
1594 /* Double constants initialization */
1595 R_Zero = 0.0;
1596 R_PosInf = 1.0/R_Zero;
1597 R_NegInf = -1.0/R_Zero;
1598 R_Nan = R_Zero/R_Zero;
1599 }
1600
1601 static void initServer() {
1602 int j;
1603
1604 signal(SIGHUP, SIG_IGN);
1605 signal(SIGPIPE, SIG_IGN);
1606 setupSigSegvAction();
1607
1608 server.devnull = fopen("/dev/null","w");
1609 if (server.devnull == NULL) {
1610 redisLog(REDIS_WARNING, "Can't open /dev/null: %s", server.neterr);
1611 exit(1);
1612 }
1613 server.clients = listCreate();
1614 server.slaves = listCreate();
1615 server.monitors = listCreate();
1616 server.objfreelist = listCreate();
1617 createSharedObjects();
1618 server.el = aeCreateEventLoop();
1619 server.db = zmalloc(sizeof(redisDb)*server.dbnum);
1620 server.sharingpool = dictCreate(&setDictType,NULL);
1621 server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr);
1622 if (server.fd == -1) {
1623 redisLog(REDIS_WARNING, "Opening TCP port: %s", server.neterr);
1624 exit(1);
1625 }
1626 for (j = 0; j < server.dbnum; j++) {
1627 server.db[j].dict = dictCreate(&dbDictType,NULL);
1628 server.db[j].expires = dictCreate(&keyptrDictType,NULL);
1629 server.db[j].blockingkeys = dictCreate(&keylistDictType,NULL);
1630 if (server.vm_enabled)
1631 server.db[j].io_keys = dictCreate(&keylistDictType,NULL);
1632 server.db[j].id = j;
1633 }
1634 server.pubsub_channels = dictCreate(&keylistDictType,NULL);
1635 server.pubsub_patterns = listCreate();
1636 listSetFreeMethod(server.pubsub_patterns,freePubsubPattern);
1637 listSetMatchMethod(server.pubsub_patterns,listMatchPubsubPattern);
1638 server.cronloops = 0;
1639 server.bgsavechildpid = -1;
1640 server.bgrewritechildpid = -1;
1641 server.bgrewritebuf = sdsempty();
1642 server.lastsave = time(NULL);
1643 server.dirty = 0;
1644 server.stat_numcommands = 0;
1645 server.stat_numconnections = 0;
1646 server.stat_expiredkeys = 0;
1647 server.stat_starttime = time(NULL);
1648 server.unixtime = time(NULL);
1649 aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL);
1650 if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,
1651 acceptHandler, NULL) == AE_ERR) oom("creating file event");
1652
1653 if (server.appendonly) {
1654 server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
1655 if (server.appendfd == -1) {
1656 redisLog(REDIS_WARNING, "Can't open the append-only file: %s",
1657 strerror(errno));
1658 exit(1);
1659 }
1660 }
1661
1662 if (server.vm_enabled) vmInit();
1663 }
1664
1665 /* Empty the whole database */
1666 static long long emptyDb() {
1667 int j;
1668 long long removed = 0;
1669
1670 for (j = 0; j < server.dbnum; j++) {
1671 removed += dictSize(server.db[j].dict);
1672 dictEmpty(server.db[j].dict);
1673 dictEmpty(server.db[j].expires);
1674 }
1675 return removed;
1676 }
1677
1678 static int yesnotoi(char *s) {
1679 if (!strcasecmp(s,"yes")) return 1;
1680 else if (!strcasecmp(s,"no")) return 0;
1681 else return -1;
1682 }
1683
1684 /* I agree, this is a very rudimental way to load a configuration...
1685 will improve later if the config gets more complex */
1686 static void loadServerConfig(char *filename) {
1687 FILE *fp;
1688 char buf[REDIS_CONFIGLINE_MAX+1], *err = NULL;
1689 int linenum = 0;
1690 sds line = NULL;
1691 char *errormsg = "Fatal error, can't open config file '%s'";
1692 char *errorbuf = zmalloc(sizeof(char)*(strlen(errormsg)+strlen(filename)));
1693 sprintf(errorbuf, errormsg, filename);
1694
1695 if (filename[0] == '-' && filename[1] == '\0')
1696 fp = stdin;
1697 else {
1698 if ((fp = fopen(filename,"r")) == NULL) {
1699 redisLog(REDIS_WARNING, errorbuf);
1700 exit(1);
1701 }
1702 }
1703
1704 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL) {
1705 sds *argv;
1706 int argc, j;
1707
1708 linenum++;
1709 line = sdsnew(buf);
1710 line = sdstrim(line," \t\r\n");
1711
1712 /* Skip comments and blank lines*/
1713 if (line[0] == '#' || line[0] == '\0') {
1714 sdsfree(line);
1715 continue;
1716 }
1717
1718 /* Split into arguments */
1719 argv = sdssplitlen(line,sdslen(line)," ",1,&argc);
1720 sdstolower(argv[0]);
1721
1722 /* Execute config directives */
1723 if (!strcasecmp(argv[0],"timeout") && argc == 2) {
1724 server.maxidletime = atoi(argv[1]);
1725 if (server.maxidletime < 0) {
1726 err = "Invalid timeout value"; goto loaderr;
1727 }
1728 } else if (!strcasecmp(argv[0],"port") && argc == 2) {
1729 server.port = atoi(argv[1]);
1730 if (server.port < 1 || server.port > 65535) {
1731 err = "Invalid port"; goto loaderr;
1732 }
1733 } else if (!strcasecmp(argv[0],"bind") && argc == 2) {
1734 server.bindaddr = zstrdup(argv[1]);
1735 } else if (!strcasecmp(argv[0],"save") && argc == 3) {
1736 int seconds = atoi(argv[1]);
1737 int changes = atoi(argv[2]);
1738 if (seconds < 1 || changes < 0) {
1739 err = "Invalid save parameters"; goto loaderr;
1740 }
1741 appendServerSaveParams(seconds,changes);
1742 } else if (!strcasecmp(argv[0],"dir") && argc == 2) {
1743 if (chdir(argv[1]) == -1) {
1744 redisLog(REDIS_WARNING,"Can't chdir to '%s': %s",
1745 argv[1], strerror(errno));
1746 exit(1);
1747 }
1748 } else if (!strcasecmp(argv[0],"loglevel") && argc == 2) {
1749 if (!strcasecmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG;
1750 else if (!strcasecmp(argv[1],"verbose")) server.verbosity = REDIS_VERBOSE;
1751 else if (!strcasecmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE;
1752 else if (!strcasecmp(argv[1],"warning")) server.verbosity = REDIS_WARNING;
1753 else {
1754 err = "Invalid log level. Must be one of debug, notice, warning";
1755 goto loaderr;
1756 }
1757 } else if (!strcasecmp(argv[0],"logfile") && argc == 2) {
1758 FILE *logfp;
1759
1760 server.logfile = zstrdup(argv[1]);
1761 if (!strcasecmp(server.logfile,"stdout")) {
1762 zfree(server.logfile);
1763 server.logfile = NULL;
1764 }
1765 if (server.logfile) {
1766 /* Test if we are able to open the file. The server will not
1767 * be able to abort just for this problem later... */
1768 logfp = fopen(server.logfile,"a");
1769 if (logfp == NULL) {
1770 err = sdscatprintf(sdsempty(),
1771 "Can't open the log file: %s", strerror(errno));
1772 goto loaderr;
1773 }
1774 fclose(logfp);
1775 }
1776 } else if (!strcasecmp(argv[0],"databases") && argc == 2) {
1777 server.dbnum = atoi(argv[1]);
1778 if (server.dbnum < 1) {
1779 err = "Invalid number of databases"; goto loaderr;
1780 }
1781 } else if (!strcasecmp(argv[0],"include") && argc == 2) {
1782 loadServerConfig(argv[1]);
1783 } else if (!strcasecmp(argv[0],"maxclients") && argc == 2) {
1784 server.maxclients = atoi(argv[1]);
1785 } else if (!strcasecmp(argv[0],"maxmemory") && argc == 2) {
1786 server.maxmemory = strtoll(argv[1], NULL, 10);
1787 } else if (!strcasecmp(argv[0],"slaveof") && argc == 3) {
1788 server.masterhost = sdsnew(argv[1]);
1789 server.masterport = atoi(argv[2]);
1790 server.replstate = REDIS_REPL_CONNECT;
1791 } else if (!strcasecmp(argv[0],"masterauth") && argc == 2) {
1792 server.masterauth = zstrdup(argv[1]);
1793 } else if (!strcasecmp(argv[0],"glueoutputbuf") && argc == 2) {
1794 if ((server.glueoutputbuf = yesnotoi(argv[1])) == -1) {
1795 err = "argument must be 'yes' or 'no'"; goto loaderr;
1796 }
1797 } else if (!strcasecmp(argv[0],"shareobjects") && argc == 2) {
1798 if ((server.shareobjects = yesnotoi(argv[1])) == -1) {
1799 err = "argument must be 'yes' or 'no'"; goto loaderr;
1800 }
1801 } else if (!strcasecmp(argv[0],"rdbcompression") && argc == 2) {
1802 if ((server.rdbcompression = yesnotoi(argv[1])) == -1) {
1803 err = "argument must be 'yes' or 'no'"; goto loaderr;
1804 }
1805 } else if (!strcasecmp(argv[0],"shareobjectspoolsize") && argc == 2) {
1806 server.sharingpoolsize = atoi(argv[1]);
1807 if (server.sharingpoolsize < 1) {
1808 err = "invalid object sharing pool size"; goto loaderr;
1809 }
1810 } else if (!strcasecmp(argv[0],"daemonize") && argc == 2) {
1811 if ((server.daemonize = yesnotoi(argv[1])) == -1) {
1812 err = "argument must be 'yes' or 'no'"; goto loaderr;
1813 }
1814 } else if (!strcasecmp(argv[0],"appendonly") && argc == 2) {
1815 if ((server.appendonly = yesnotoi(argv[1])) == -1) {
1816 err = "argument must be 'yes' or 'no'"; goto loaderr;
1817 }
1818 } else if (!strcasecmp(argv[0],"appendfsync") && argc == 2) {
1819 if (!strcasecmp(argv[1],"no")) {
1820 server.appendfsync = APPENDFSYNC_NO;
1821 } else if (!strcasecmp(argv[1],"always")) {
1822 server.appendfsync = APPENDFSYNC_ALWAYS;
1823 } else if (!strcasecmp(argv[1],"everysec")) {
1824 server.appendfsync = APPENDFSYNC_EVERYSEC;
1825 } else {
1826 err = "argument must be 'no', 'always' or 'everysec'";
1827 goto loaderr;
1828 }
1829 } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
1830 server.requirepass = zstrdup(argv[1]);
1831 } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
1832 zfree(server.pidfile);
1833 server.pidfile = zstrdup(argv[1]);
1834 } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) {
1835 zfree(server.dbfilename);
1836 server.dbfilename = zstrdup(argv[1]);
1837 } else if (!strcasecmp(argv[0],"vm-enabled") && argc == 2) {
1838 if ((server.vm_enabled = yesnotoi(argv[1])) == -1) {
1839 err = "argument must be 'yes' or 'no'"; goto loaderr;
1840 }
1841 } else if (!strcasecmp(argv[0],"vm-swap-file") && argc == 2) {
1842 zfree(server.vm_swap_file);
1843 server.vm_swap_file = zstrdup(argv[1]);
1844 } else if (!strcasecmp(argv[0],"vm-max-memory") && argc == 2) {
1845 server.vm_max_memory = strtoll(argv[1], NULL, 10);
1846 } else if (!strcasecmp(argv[0],"vm-page-size") && argc == 2) {
1847 server.vm_page_size = strtoll(argv[1], NULL, 10);
1848 } else if (!strcasecmp(argv[0],"vm-pages") && argc == 2) {
1849 server.vm_pages = strtoll(argv[1], NULL, 10);
1850 } else if (!strcasecmp(argv[0],"vm-max-threads") && argc == 2) {
1851 server.vm_max_threads = strtoll(argv[1], NULL, 10);
1852 } else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2){
1853 server.hash_max_zipmap_entries = strtol(argv[1], NULL, 10);
1854 } else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2){
1855 server.hash_max_zipmap_value = strtol(argv[1], NULL, 10);
1856 } else if (!strcasecmp(argv[0],"vm-max-threads") && argc == 2) {
1857 server.vm_max_threads = strtoll(argv[1], NULL, 10);
1858 } else {
1859 err = "Bad directive or wrong number of arguments"; goto loaderr;
1860 }
1861 for (j = 0; j < argc; j++)
1862 sdsfree(argv[j]);
1863 zfree(argv);
1864 sdsfree(line);
1865 }
1866 if (fp != stdin) fclose(fp);
1867 return;
1868
1869 loaderr:
1870 fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n");
1871 fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
1872 fprintf(stderr, ">>> '%s'\n", line);
1873 fprintf(stderr, "%s\n", err);
1874 exit(1);
1875 }
1876
1877 static void freeClientArgv(redisClient *c) {
1878 int j;
1879
1880 for (j = 0; j < c->argc; j++)
1881 decrRefCount(c->argv[j]);
1882 for (j = 0; j < c->mbargc; j++)
1883 decrRefCount(c->mbargv[j]);
1884 c->argc = 0;
1885 c->mbargc = 0;
1886 }
1887
1888 static void freeClient(redisClient *c) {
1889 listNode *ln;
1890
1891 /* Note that if the client we are freeing is blocked into a blocking
1892 * call, we have to set querybuf to NULL *before* to call
1893 * unblockClientWaitingData() to avoid processInputBuffer() will get
1894 * called. Also it is important to remove the file events after
1895 * this, because this call adds the READABLE event. */
1896 sdsfree(c->querybuf);
1897 c->querybuf = NULL;
1898 if (c->flags & REDIS_BLOCKED)
1899 unblockClientWaitingData(c);
1900
1901 /* Unsubscribe from all the pubsub channels */
1902 pubsubUnsubscribeAllChannels(c,0);
1903 pubsubUnsubscribeAllPatterns(c,0);
1904 dictRelease(c->pubsub_channels);
1905 listRelease(c->pubsub_patterns);
1906 /* Obvious cleanup */
1907 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
1908 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
1909 listRelease(c->reply);
1910 freeClientArgv(c);
1911 close(c->fd);
1912 /* Remove from the list of clients */
1913 ln = listSearchKey(server.clients,c);
1914 redisAssert(ln != NULL);
1915 listDelNode(server.clients,ln);
1916 /* Remove from the list of clients waiting for swapped keys */
1917 if (c->flags & REDIS_IO_WAIT && listLength(c->io_keys) == 0) {
1918 ln = listSearchKey(server.io_ready_clients,c);
1919 if (ln) {
1920 listDelNode(server.io_ready_clients,ln);
1921 server.vm_blocked_clients--;
1922 }
1923 }
1924 while (server.vm_enabled && listLength(c->io_keys)) {
1925 ln = listFirst(c->io_keys);
1926 dontWaitForSwappedKey(c,ln->value);
1927 }
1928 listRelease(c->io_keys);
1929 /* Master/slave cleanup */
1930 if (c->flags & REDIS_SLAVE) {
1931 if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1)
1932 close(c->repldbfd);
1933 list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
1934 ln = listSearchKey(l,c);
1935 redisAssert(ln != NULL);
1936 listDelNode(l,ln);
1937 }
1938 if (c->flags & REDIS_MASTER) {
1939 server.master = NULL;
1940 server.replstate = REDIS_REPL_CONNECT;
1941 }
1942 /* Release memory */
1943 zfree(c->argv);
1944 zfree(c->mbargv);
1945 freeClientMultiState(c);
1946 zfree(c);
1947 }
1948
1949 #define GLUEREPLY_UP_TO (1024)
1950 static void glueReplyBuffersIfNeeded(redisClient *c) {
1951 int copylen = 0;
1952 char buf[GLUEREPLY_UP_TO];
1953 listNode *ln;
1954 listIter li;
1955 robj *o;
1956
1957 listRewind(c->reply,&li);
1958 while((ln = listNext(&li))) {
1959 int objlen;
1960
1961 o = ln->value;
1962 objlen = sdslen(o->ptr);
1963 if (copylen + objlen <= GLUEREPLY_UP_TO) {
1964 memcpy(buf+copylen,o->ptr,objlen);
1965 copylen += objlen;
1966 listDelNode(c->reply,ln);
1967 } else {
1968 if (copylen == 0) return;
1969 break;
1970 }
1971 }
1972 /* Now the output buffer is empty, add the new single element */
1973 o = createObject(REDIS_STRING,sdsnewlen(buf,copylen));
1974 listAddNodeHead(c->reply,o);
1975 }
1976
1977 static void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
1978 redisClient *c = privdata;
1979 int nwritten = 0, totwritten = 0, objlen;
1980 robj *o;
1981 REDIS_NOTUSED(el);
1982 REDIS_NOTUSED(mask);
1983
1984 /* Use writev() if we have enough buffers to send */
1985 if (!server.glueoutputbuf &&
1986 listLength(c->reply) > REDIS_WRITEV_THRESHOLD &&
1987 !(c->flags & REDIS_MASTER))
1988 {
1989 sendReplyToClientWritev(el, fd, privdata, mask);
1990 return;
1991 }
1992
1993 while(listLength(c->reply)) {
1994 if (server.glueoutputbuf && listLength(c->reply) > 1)
1995 glueReplyBuffersIfNeeded(c);
1996
1997 o = listNodeValue(listFirst(c->reply));
1998 objlen = sdslen(o->ptr);
1999
2000 if (objlen == 0) {
2001 listDelNode(c->reply,listFirst(c->reply));
2002 continue;
2003 }
2004
2005 if (c->flags & REDIS_MASTER) {
2006 /* Don't reply to a master */
2007 nwritten = objlen - c->sentlen;
2008 } else {
2009 nwritten = write(fd, ((char*)o->ptr)+c->sentlen, objlen - c->sentlen);
2010 if (nwritten <= 0) break;
2011 }
2012 c->sentlen += nwritten;
2013 totwritten += nwritten;
2014 /* If we fully sent the object on head go to the next one */
2015 if (c->sentlen == objlen) {
2016 listDelNode(c->reply,listFirst(c->reply));
2017 c->sentlen = 0;
2018 }
2019 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
2020 * bytes, in a single threaded server it's a good idea to serve
2021 * other clients as well, even if a very large request comes from
2022 * super fast link that is always able to accept data (in real world
2023 * scenario think about 'KEYS *' against the loopback interfae) */
2024 if (totwritten > REDIS_MAX_WRITE_PER_EVENT) break;
2025 }
2026 if (nwritten == -1) {
2027 if (errno == EAGAIN) {
2028 nwritten = 0;
2029 } else {
2030 redisLog(REDIS_VERBOSE,
2031 "Error writing to client: %s", strerror(errno));
2032 freeClient(c);
2033 return;
2034 }
2035 }
2036 if (totwritten > 0) c->lastinteraction = time(NULL);
2037 if (listLength(c->reply) == 0) {
2038 c->sentlen = 0;
2039 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
2040 }
2041 }
2042
2043 static void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask)
2044 {
2045 redisClient *c = privdata;
2046 int nwritten = 0, totwritten = 0, objlen, willwrite;
2047 robj *o;
2048 struct iovec iov[REDIS_WRITEV_IOVEC_COUNT];
2049 int offset, ion = 0;
2050 REDIS_NOTUSED(el);
2051 REDIS_NOTUSED(mask);
2052
2053 listNode *node;
2054 while (listLength(c->reply)) {
2055 offset = c->sentlen;
2056 ion = 0;
2057 willwrite = 0;
2058
2059 /* fill-in the iov[] array */
2060 for(node = listFirst(c->reply); node; node = listNextNode(node)) {
2061 o = listNodeValue(node);
2062 objlen = sdslen(o->ptr);
2063
2064 if (totwritten + objlen - offset > REDIS_MAX_WRITE_PER_EVENT)
2065 break;
2066
2067 if(ion == REDIS_WRITEV_IOVEC_COUNT)
2068 break; /* no more iovecs */
2069
2070 iov[ion].iov_base = ((char*)o->ptr) + offset;
2071 iov[ion].iov_len = objlen - offset;
2072 willwrite += objlen - offset;
2073 offset = 0; /* just for the first item */
2074 ion++;
2075 }
2076
2077 if(willwrite == 0)
2078 break;
2079
2080 /* write all collected blocks at once */
2081 if((nwritten = writev(fd, iov, ion)) < 0) {
2082 if (errno != EAGAIN) {
2083 redisLog(REDIS_VERBOSE,
2084 "Error writing to client: %s", strerror(errno));
2085 freeClient(c);
2086 return;
2087 }
2088 break;
2089 }
2090
2091 totwritten += nwritten;
2092 offset = c->sentlen;
2093
2094 /* remove written robjs from c->reply */
2095 while (nwritten && listLength(c->reply)) {
2096 o = listNodeValue(listFirst(c->reply));
2097 objlen = sdslen(o->ptr);
2098
2099 if(nwritten >= objlen - offset) {
2100 listDelNode(c->reply, listFirst(c->reply));
2101 nwritten -= objlen - offset;
2102 c->sentlen = 0;
2103 } else {
2104 /* partial write */
2105 c->sentlen += nwritten;
2106 break;
2107 }
2108 offset = 0;
2109 }
2110 }
2111
2112 if (totwritten > 0)
2113 c->lastinteraction = time(NULL);
2114
2115 if (listLength(c->reply) == 0) {
2116 c->sentlen = 0;
2117 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
2118 }
2119 }
2120
2121 static struct redisCommand *lookupCommand(char *name) {
2122 int j = 0;
2123 while(cmdTable[j].name != NULL) {
2124 if (!strcasecmp(name,cmdTable[j].name)) return &cmdTable[j];
2125 j++;
2126 }
2127 return NULL;
2128 }
2129
2130 /* resetClient prepare the client to process the next command */
2131 static void resetClient(redisClient *c) {
2132 freeClientArgv(c);
2133 c->bulklen = -1;
2134 c->multibulk = 0;
2135 }
2136
2137 /* Call() is the core of Redis execution of a command */
2138 static void call(redisClient *c, struct redisCommand *cmd) {
2139 long long dirty;
2140
2141 dirty = server.dirty;
2142 cmd->proc(c);
2143 dirty = server.dirty-dirty;
2144
2145 if (server.appendonly && dirty)
2146 feedAppendOnlyFile(cmd,c->db->id,c->argv,c->argc);
2147 if ((dirty || cmd->flags & REDIS_CMD_FORCE_REPLICATION) &&
2148 listLength(server.slaves))
2149 replicationFeedSlaves(server.slaves,c->db->id,c->argv,c->argc);
2150 if (listLength(server.monitors))
2151 replicationFeedSlaves(server.monitors,c->db->id,c->argv,c->argc);
2152 server.stat_numcommands++;
2153 }
2154
2155 /* If this function gets called we already read a whole
2156 * command, argments are in the client argv/argc fields.
2157 * processCommand() execute the command or prepare the
2158 * server for a bulk read from the client.
2159 *
2160 * If 1 is returned the client is still alive and valid and
2161 * and other operations can be performed by the caller. Otherwise
2162 * if 0 is returned the client was destroied (i.e. after QUIT). */
2163 static int processCommand(redisClient *c) {
2164 struct redisCommand *cmd;
2165
2166 /* Free some memory if needed (maxmemory setting) */
2167 if (server.maxmemory) freeMemoryIfNeeded();
2168
2169 /* Handle the multi bulk command type. This is an alternative protocol
2170 * supported by Redis in order to receive commands that are composed of
2171 * multiple binary-safe "bulk" arguments. The latency of processing is
2172 * a bit higher but this allows things like multi-sets, so if this
2173 * protocol is used only for MSET and similar commands this is a big win. */
2174 if (c->multibulk == 0 && c->argc == 1 && ((char*)(c->argv[0]->ptr))[0] == '*') {
2175 c->multibulk = atoi(((char*)c->argv[0]->ptr)+1);
2176 if (c->multibulk <= 0) {
2177 resetClient(c);
2178 return 1;
2179 } else {
2180 decrRefCount(c->argv[c->argc-1]);
2181 c->argc--;
2182 return 1;
2183 }
2184 } else if (c->multibulk) {
2185 if (c->bulklen == -1) {
2186 if (((char*)c->argv[0]->ptr)[0] != '$') {
2187 addReplySds(c,sdsnew("-ERR multi bulk protocol error\r\n"));
2188 resetClient(c);
2189 return 1;
2190 } else {
2191 int bulklen = atoi(((char*)c->argv[0]->ptr)+1);
2192 decrRefCount(c->argv[0]);
2193 if (bulklen < 0 || bulklen > 1024*1024*1024) {
2194 c->argc--;
2195 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
2196 resetClient(c);
2197 return 1;
2198 }
2199 c->argc--;
2200 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
2201 return 1;
2202 }
2203 } else {
2204 c->mbargv = zrealloc(c->mbargv,(sizeof(robj*))*(c->mbargc+1));
2205 c->mbargv[c->mbargc] = c->argv[0];
2206 c->mbargc++;
2207 c->argc--;
2208 c->multibulk--;
2209 if (c->multibulk == 0) {
2210 robj **auxargv;
2211 int auxargc;
2212
2213 /* Here we need to swap the multi-bulk argc/argv with the
2214 * normal argc/argv of the client structure. */
2215 auxargv = c->argv;
2216 c->argv = c->mbargv;
2217 c->mbargv = auxargv;
2218
2219 auxargc = c->argc;
2220 c->argc = c->mbargc;
2221 c->mbargc = auxargc;
2222
2223 /* We need to set bulklen to something different than -1
2224 * in order for the code below to process the command without
2225 * to try to read the last argument of a bulk command as
2226 * a special argument. */
2227 c->bulklen = 0;
2228 /* continue below and process the command */
2229 } else {
2230 c->bulklen = -1;
2231 return 1;
2232 }
2233 }
2234 }
2235 /* -- end of multi bulk commands processing -- */
2236
2237 /* The QUIT command is handled as a special case. Normal command
2238 * procs are unable to close the client connection safely */
2239 if (!strcasecmp(c->argv[0]->ptr,"quit")) {
2240 freeClient(c);
2241 return 0;
2242 }
2243
2244 /* Now lookup the command and check ASAP about trivial error conditions
2245 * such wrong arity, bad command name and so forth. */
2246 cmd = lookupCommand(c->argv[0]->ptr);
2247 if (!cmd) {
2248 addReplySds(c,
2249 sdscatprintf(sdsempty(), "-ERR unknown command '%s'\r\n",
2250 (char*)c->argv[0]->ptr));
2251 resetClient(c);
2252 return 1;
2253 } else if ((cmd->arity > 0 && cmd->arity != c->argc) ||
2254 (c->argc < -cmd->arity)) {
2255 addReplySds(c,
2256 sdscatprintf(sdsempty(),
2257 "-ERR wrong number of arguments for '%s' command\r\n",
2258 cmd->name));
2259 resetClient(c);
2260 return 1;
2261 } else if (cmd->flags & REDIS_CMD_BULK && c->bulklen == -1) {
2262 /* This is a bulk command, we have to read the last argument yet. */
2263 int bulklen = atoi(c->argv[c->argc-1]->ptr);
2264
2265 decrRefCount(c->argv[c->argc-1]);
2266 if (bulklen < 0 || bulklen > 1024*1024*1024) {
2267 c->argc--;
2268 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
2269 resetClient(c);
2270 return 1;
2271 }
2272 c->argc--;
2273 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
2274 /* It is possible that the bulk read is already in the
2275 * buffer. Check this condition and handle it accordingly.
2276 * This is just a fast path, alternative to call processInputBuffer().
2277 * It's a good idea since the code is small and this condition
2278 * happens most of the times. */
2279 if ((signed)sdslen(c->querybuf) >= c->bulklen) {
2280 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
2281 c->argc++;
2282 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
2283 } else {
2284 /* Otherwise return... there is to read the last argument
2285 * from the socket. */
2286 return 1;
2287 }
2288 }
2289 /* Let's try to share objects on the command arguments vector */
2290 if (server.shareobjects) {
2291 int j;
2292 for(j = 1; j < c->argc; j++)
2293 c->argv[j] = tryObjectSharing(c->argv[j]);
2294 }
2295 /* Let's try to encode the bulk object to save space. */
2296 if (cmd->flags & REDIS_CMD_BULK)
2297 tryObjectEncoding(c->argv[c->argc-1]);
2298
2299 /* Check if the user is authenticated */
2300 if (server.requirepass && !c->authenticated && cmd->proc != authCommand) {
2301 addReplySds(c,sdsnew("-ERR operation not permitted\r\n"));
2302 resetClient(c);
2303 return 1;
2304 }
2305
2306 /* Handle the maxmemory directive */
2307 if (server.maxmemory && (cmd->flags & REDIS_CMD_DENYOOM) &&
2308 zmalloc_used_memory() > server.maxmemory)
2309 {
2310 addReplySds(c,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
2311 resetClient(c);
2312 return 1;
2313 }
2314
2315 /* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
2316 if (dictSize(c->pubsub_channels) > 0 &&
2317 cmd->proc != subscribeCommand && cmd->proc != unsubscribeCommand &&
2318 cmd->proc != psubscribeCommand && cmd->proc != punsubscribeCommand) {
2319 addReplySds(c,sdsnew("-ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context\r\n"));
2320 resetClient(c);
2321 return 1;
2322 }
2323
2324 /* Exec the command */
2325 if (c->flags & REDIS_MULTI && cmd->proc != execCommand && cmd->proc != discardCommand) {
2326 queueMultiCommand(c,cmd);
2327 addReply(c,shared.queued);
2328 } else {
2329 if (server.vm_enabled && server.vm_max_threads > 0 &&
2330 blockClientOnSwappedKeys(cmd,c)) return 1;
2331 call(c,cmd);
2332 }
2333
2334 /* Prepare the client for the next command */
2335 resetClient(c);
2336 return 1;
2337 }
2338
2339 static void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc) {
2340 listNode *ln;
2341 listIter li;
2342 int outc = 0, j;
2343 robj **outv;
2344 /* We need 1+(ARGS*3) objects since commands are using the new protocol
2345 * and we one 1 object for the first "*<count>\r\n" multibulk count, then
2346 * for every additional object we have "$<count>\r\n" + object + "\r\n". */
2347 robj *static_outv[REDIS_STATIC_ARGS*3+1];
2348 robj *lenobj;
2349
2350 if (argc <= REDIS_STATIC_ARGS) {
2351 outv = static_outv;
2352 } else {
2353 outv = zmalloc(sizeof(robj*)*(argc*3+1));
2354 }
2355
2356 lenobj = createObject(REDIS_STRING,
2357 sdscatprintf(sdsempty(), "*%d\r\n", argc));
2358 lenobj->refcount = 0;
2359 outv[outc++] = lenobj;
2360 for (j = 0; j < argc; j++) {
2361 lenobj = createObject(REDIS_STRING,
2362 sdscatprintf(sdsempty(),"$%lu\r\n",
2363 (unsigned long) stringObjectLen(argv[j])));
2364 lenobj->refcount = 0;
2365 outv[outc++] = lenobj;
2366 outv[outc++] = argv[j];
2367 outv[outc++] = shared.crlf;
2368 }
2369
2370 /* Increment all the refcounts at start and decrement at end in order to
2371 * be sure to free objects if there is no slave in a replication state
2372 * able to be feed with commands */
2373 for (j = 0; j < outc; j++) incrRefCount(outv[j]);
2374 listRewind(slaves,&li);
2375 while((ln = listNext(&li))) {
2376 redisClient *slave = ln->value;
2377
2378 /* Don't feed slaves that are still waiting for BGSAVE to start */
2379 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) continue;
2380
2381 /* Feed all the other slaves, MONITORs and so on */
2382 if (slave->slaveseldb != dictid) {
2383 robj *selectcmd;
2384
2385 switch(dictid) {
2386 case 0: selectcmd = shared.select0; break;
2387 case 1: selectcmd = shared.select1; break;
2388 case 2: selectcmd = shared.select2; break;
2389 case 3: selectcmd = shared.select3; break;
2390 case 4: selectcmd = shared.select4; break;
2391 case 5: selectcmd = shared.select5; break;
2392 case 6: selectcmd = shared.select6; break;
2393 case 7: selectcmd = shared.select7; break;
2394 case 8: selectcmd = shared.select8; break;
2395 case 9: selectcmd = shared.select9; break;
2396 default:
2397 selectcmd = createObject(REDIS_STRING,
2398 sdscatprintf(sdsempty(),"select %d\r\n",dictid));
2399 selectcmd->refcount = 0;
2400 break;
2401 }
2402 addReply(slave,selectcmd);
2403 slave->slaveseldb = dictid;
2404 }
2405 for (j = 0; j < outc; j++) addReply(slave,outv[j]);
2406 }
2407 for (j = 0; j < outc; j++) decrRefCount(outv[j]);
2408 if (outv != static_outv) zfree(outv);
2409 }
2410
2411 static void processInputBuffer(redisClient *c) {
2412 again:
2413 /* Before to process the input buffer, make sure the client is not
2414 * waitig for a blocking operation such as BLPOP. Note that the first
2415 * iteration the client is never blocked, otherwise the processInputBuffer
2416 * would not be called at all, but after the execution of the first commands
2417 * in the input buffer the client may be blocked, and the "goto again"
2418 * will try to reiterate. The following line will make it return asap. */
2419 if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return;
2420 if (c->bulklen == -1) {
2421 /* Read the first line of the query */
2422 char *p = strchr(c->querybuf,'\n');
2423 size_t querylen;
2424
2425 if (p) {
2426 sds query, *argv;
2427 int argc, j;
2428
2429 query = c->querybuf;
2430 c->querybuf = sdsempty();
2431 querylen = 1+(p-(query));
2432 if (sdslen(query) > querylen) {
2433 /* leave data after the first line of the query in the buffer */
2434 c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
2435 }
2436 *p = '\0'; /* remove "\n" */
2437 if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
2438 sdsupdatelen(query);
2439
2440 /* Now we can split the query in arguments */
2441 argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
2442 sdsfree(query);
2443
2444 if (c->argv) zfree(c->argv);
2445 c->argv = zmalloc(sizeof(robj*)*argc);
2446
2447 for (j = 0; j < argc; j++) {
2448 if (sdslen(argv[j])) {
2449 c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
2450 c->argc++;
2451 } else {
2452 sdsfree(argv[j]);
2453 }
2454 }
2455 zfree(argv);
2456 if (c->argc) {
2457 /* Execute the command. If the client is still valid
2458 * after processCommand() return and there is something
2459 * on the query buffer try to process the next command. */
2460 if (processCommand(c) && sdslen(c->querybuf)) goto again;
2461 } else {
2462 /* Nothing to process, argc == 0. Just process the query
2463 * buffer if it's not empty or return to the caller */
2464 if (sdslen(c->querybuf)) goto again;
2465 }
2466 return;
2467 } else if (sdslen(c->querybuf) >= REDIS_REQUEST_MAX_SIZE) {
2468 redisLog(REDIS_VERBOSE, "Client protocol error");
2469 freeClient(c);
2470 return;
2471 }
2472 } else {
2473 /* Bulk read handling. Note that if we are at this point
2474 the client already sent a command terminated with a newline,
2475 we are reading the bulk data that is actually the last
2476 argument of the command. */
2477 int qbl = sdslen(c->querybuf);
2478
2479 if (c->bulklen <= qbl) {
2480 /* Copy everything but the final CRLF as final argument */
2481 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
2482 c->argc++;
2483 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
2484 /* Process the command. If the client is still valid after
2485 * the processing and there is more data in the buffer
2486 * try to parse it. */
2487 if (processCommand(c) && sdslen(c->querybuf)) goto again;
2488 return;
2489 }
2490 }
2491 }
2492
2493 static void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
2494 redisClient *c = (redisClient*) privdata;
2495 char buf[REDIS_IOBUF_LEN];
2496 int nread;
2497 REDIS_NOTUSED(el);
2498 REDIS_NOTUSED(mask);
2499
2500 nread = read(fd, buf, REDIS_IOBUF_LEN);
2501 if (nread == -1) {
2502 if (errno == EAGAIN) {
2503 nread = 0;
2504 } else {
2505 redisLog(REDIS_VERBOSE, "Reading from client: %s",strerror(errno));
2506 freeClient(c);
2507 return;
2508 }
2509 } else if (nread == 0) {
2510 redisLog(REDIS_VERBOSE, "Client closed connection");
2511 freeClient(c);
2512 return;
2513 }
2514 if (nread) {
2515 c->querybuf = sdscatlen(c->querybuf, buf, nread);
2516 c->lastinteraction = time(NULL);
2517 } else {
2518 return;
2519 }
2520 processInputBuffer(c);
2521 }
2522
2523 static int selectDb(redisClient *c, int id) {
2524 if (id < 0 || id >= server.dbnum)
2525 return REDIS_ERR;
2526 c->db = &server.db[id];
2527 return REDIS_OK;
2528 }
2529
2530 static void *dupClientReplyValue(void *o) {
2531 incrRefCount((robj*)o);
2532 return o;
2533 }
2534
2535 static int listMatchObjects(void *a, void *b) {
2536 return compareStringObjects(a,b) == 0;
2537 }
2538
2539 static redisClient *createClient(int fd) {
2540 redisClient *c = zmalloc(sizeof(*c));
2541
2542 anetNonBlock(NULL,fd);
2543 anetTcpNoDelay(NULL,fd);
2544 if (!c) return NULL;
2545 selectDb(c,0);
2546 c->fd = fd;
2547 c->querybuf = sdsempty();
2548 c->argc = 0;
2549 c->argv = NULL;
2550 c->bulklen = -1;
2551 c->multibulk = 0;
2552 c->mbargc = 0;
2553 c->mbargv = NULL;
2554 c->sentlen = 0;
2555 c->flags = 0;
2556 c->lastinteraction = time(NULL);
2557 c->authenticated = 0;
2558 c->replstate = REDIS_REPL_NONE;
2559 c->reply = listCreate();
2560 listSetFreeMethod(c->reply,decrRefCount);
2561 listSetDupMethod(c->reply,dupClientReplyValue);
2562 c->blockingkeys = NULL;
2563 c->blockingkeysnum = 0;
2564 c->io_keys = listCreate();
2565 listSetFreeMethod(c->io_keys,decrRefCount);
2566 c->pubsub_channels = dictCreate(&setDictType,NULL);
2567 c->pubsub_patterns = listCreate();
2568 listSetFreeMethod(c->pubsub_patterns,decrRefCount);
2569 listSetMatchMethod(c->pubsub_patterns,listMatchObjects);
2570 if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
2571 readQueryFromClient, c) == AE_ERR) {
2572 freeClient(c);
2573 return NULL;
2574 }
2575 listAddNodeTail(server.clients,c);
2576 initClientMultiState(c);
2577 return c;
2578 }
2579
2580 static void addReply(redisClient *c, robj *obj) {
2581 if (listLength(c->reply) == 0 &&
2582 (c->replstate == REDIS_REPL_NONE ||
2583 c->replstate == REDIS_REPL_ONLINE) &&
2584 aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
2585 sendReplyToClient, c) == AE_ERR) return;
2586
2587 if (server.vm_enabled && obj->storage != REDIS_VM_MEMORY) {
2588 obj = dupStringObject(obj);
2589 obj->refcount = 0; /* getDecodedObject() will increment the refcount */
2590 }
2591 listAddNodeTail(c->reply,getDecodedObject(obj));
2592 }
2593
2594 static void addReplySds(redisClient *c, sds s) {
2595 robj *o = createObject(REDIS_STRING,s);
2596 addReply(c,o);
2597 decrRefCount(o);
2598 }
2599
2600 static void addReplyDouble(redisClient *c, double d) {
2601 char buf[128];
2602
2603 snprintf(buf,sizeof(buf),"%.17g",d);
2604 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n%s\r\n",
2605 (unsigned long) strlen(buf),buf));
2606 }
2607
2608 static void addReplyLong(redisClient *c, long l) {
2609 char buf[128];
2610 size_t len;
2611
2612 if (l == 0) {
2613 addReply(c,shared.czero);
2614 return;
2615 } else if (l == 1) {
2616 addReply(c,shared.cone);
2617 return;
2618 }
2619 len = snprintf(buf,sizeof(buf),":%ld\r\n",l);
2620 addReplySds(c,sdsnewlen(buf,len));
2621 }
2622
2623 static void addReplyLongLong(redisClient *c, long long ll) {
2624 char buf[128];
2625 size_t len;
2626
2627 if (ll == 0) {
2628 addReply(c,shared.czero);
2629 return;
2630 } else if (ll == 1) {
2631 addReply(c,shared.cone);
2632 return;
2633 }
2634 len = snprintf(buf,sizeof(buf),":%lld\r\n",ll);
2635 addReplySds(c,sdsnewlen(buf,len));
2636 }
2637
2638 static void addReplyUlong(redisClient *c, unsigned long ul) {
2639 char buf[128];
2640 size_t len;
2641
2642 if (ul == 0) {
2643 addReply(c,shared.czero);
2644 return;
2645 } else if (ul == 1) {
2646 addReply(c,shared.cone);
2647 return;
2648 }
2649 len = snprintf(buf,sizeof(buf),":%lu\r\n",ul);
2650 addReplySds(c,sdsnewlen(buf,len));
2651 }
2652
2653 static void addReplyBulkLen(redisClient *c, robj *obj) {
2654 size_t len;
2655
2656 if (obj->encoding == REDIS_ENCODING_RAW) {
2657 len = sdslen(obj->ptr);
2658 } else {
2659 long n = (long)obj->ptr;
2660
2661 /* Compute how many bytes will take this integer as a radix 10 string */
2662 len = 1;
2663 if (n < 0) {
2664 len++;
2665 n = -n;
2666 }
2667 while((n = n/10) != 0) {
2668 len++;
2669 }
2670 }
2671 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n",(unsigned long)len));
2672 }
2673
2674 static void addReplyBulk(redisClient *c, robj *obj) {
2675 addReplyBulkLen(c,obj);
2676 addReply(c,obj);
2677 addReply(c,shared.crlf);
2678 }
2679
2680 /* In the CONFIG command we need to add vanilla C string as bulk replies */
2681 static void addReplyBulkCString(redisClient *c, char *s) {
2682 if (s == NULL) {
2683 addReply(c,shared.nullbulk);
2684 } else {
2685 robj *o = createStringObject(s,strlen(s));
2686 addReplyBulk(c,o);
2687 decrRefCount(o);
2688 }
2689 }
2690
2691 static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
2692 int cport, cfd;
2693 char cip[128];
2694 redisClient *c;
2695 REDIS_NOTUSED(el);
2696 REDIS_NOTUSED(mask);
2697 REDIS_NOTUSED(privdata);
2698
2699 cfd = anetAccept(server.neterr, fd, cip, &cport);
2700 if (cfd == AE_ERR) {
2701 redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr);
2702 return;
2703 }
2704 redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport);
2705 if ((c = createClient(cfd)) == NULL) {
2706 redisLog(REDIS_WARNING,"Error allocating resoures for the client");
2707 close(cfd); /* May be already closed, just ingore errors */
2708 return;
2709 }
2710 /* If maxclient directive is set and this is one client more... close the
2711 * connection. Note that we create the client instead to check before
2712 * for this condition, since now the socket is already set in nonblocking
2713 * mode and we can send an error for free using the Kernel I/O */
2714 if (server.maxclients && listLength(server.clients) > server.maxclients) {
2715 char *err = "-ERR max number of clients reached\r\n";
2716
2717 /* That's a best effort error message, don't check write errors */
2718 if (write(c->fd,err,strlen(err)) == -1) {
2719 /* Nothing to do, Just to avoid the warning... */
2720 }
2721 freeClient(c);
2722 return;
2723 }
2724 server.stat_numconnections++;
2725 }
2726
2727 /* ======================= Redis objects implementation ===================== */
2728
2729 static robj *createObject(int type, void *ptr) {
2730 robj *o;
2731
2732 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
2733 if (listLength(server.objfreelist)) {
2734 listNode *head = listFirst(server.objfreelist);
2735 o = listNodeValue(head);
2736 listDelNode(server.objfreelist,head);
2737 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
2738 } else {
2739 if (server.vm_enabled) {
2740 pthread_mutex_unlock(&server.obj_freelist_mutex);
2741 o = zmalloc(sizeof(*o));
2742 } else {
2743 o = zmalloc(sizeof(*o)-sizeof(struct redisObjectVM));
2744 }
2745 }
2746 o->type = type;
2747 o->encoding = REDIS_ENCODING_RAW;
2748 o->ptr = ptr;
2749 o->refcount = 1;
2750 if (server.vm_enabled) {
2751 /* Note that this code may run in the context of an I/O thread
2752 * and accessing to server.unixtime in theory is an error
2753 * (no locks). But in practice this is safe, and even if we read
2754 * garbage Redis will not fail, as it's just a statistical info */
2755 o->vm.atime = server.unixtime;
2756 o->storage = REDIS_VM_MEMORY;
2757 }
2758 return o;
2759 }
2760
2761 static robj *createStringObject(char *ptr, size_t len) {
2762 return createObject(REDIS_STRING,sdsnewlen(ptr,len));
2763 }
2764
2765 static robj *dupStringObject(robj *o) {
2766 assert(o->encoding == REDIS_ENCODING_RAW);
2767 return createStringObject(o->ptr,sdslen(o->ptr));
2768 }
2769
2770 static robj *createListObject(void) {
2771 list *l = listCreate();
2772
2773 listSetFreeMethod(l,decrRefCount);
2774 return createObject(REDIS_LIST,l);
2775 }
2776
2777 static robj *createSetObject(void) {
2778 dict *d = dictCreate(&setDictType,NULL);
2779 return createObject(REDIS_SET,d);
2780 }
2781
2782 static robj *createHashObject(void) {
2783 /* All the Hashes start as zipmaps. Will be automatically converted
2784 * into hash tables if there are enough elements or big elements
2785 * inside. */
2786 unsigned char *zm = zipmapNew();
2787 robj *o = createObject(REDIS_HASH,zm);
2788 o->encoding = REDIS_ENCODING_ZIPMAP;
2789 return o;
2790 }
2791
2792 static robj *createZsetObject(void) {
2793 zset *zs = zmalloc(sizeof(*zs));
2794
2795 zs->dict = dictCreate(&zsetDictType,NULL);
2796 zs->zsl = zslCreate();
2797 return createObject(REDIS_ZSET,zs);
2798 }
2799
2800 static void freeStringObject(robj *o) {
2801 if (o->encoding == REDIS_ENCODING_RAW) {
2802 sdsfree(o->ptr);
2803 }
2804 }
2805
2806 static void freeListObject(robj *o) {
2807 listRelease((list*) o->ptr);
2808 }
2809
2810 static void freeSetObject(robj *o) {
2811 dictRelease((dict*) o->ptr);
2812 }
2813
2814 static void freeZsetObject(robj *o) {
2815 zset *zs = o->ptr;
2816
2817 dictRelease(zs->dict);
2818 zslFree(zs->zsl);
2819 zfree(zs);
2820 }
2821
2822 static void freeHashObject(robj *o) {
2823 switch (o->encoding) {
2824 case REDIS_ENCODING_HT:
2825 dictRelease((dict*) o->ptr);
2826 break;
2827 case REDIS_ENCODING_ZIPMAP:
2828 zfree(o->ptr);
2829 break;
2830 default:
2831 redisAssert(0);
2832 break;
2833 }
2834 }
2835
2836 static void incrRefCount(robj *o) {
2837 o->refcount++;
2838 }
2839
2840 static void decrRefCount(void *obj) {
2841 robj *o = obj;
2842
2843 /* Object is a key of a swapped out value, or in the process of being
2844 * loaded. */
2845 if (server.vm_enabled &&
2846 (o->storage == REDIS_VM_SWAPPED || o->storage == REDIS_VM_LOADING))
2847 {
2848 if (o->storage == REDIS_VM_SWAPPED || o->storage == REDIS_VM_LOADING) {
2849 redisAssert(o->refcount == 1);
2850 }
2851 if (o->storage == REDIS_VM_LOADING) vmCancelThreadedIOJob(obj);
2852 redisAssert(o->type == REDIS_STRING);
2853 freeStringObject(o);
2854 vmMarkPagesFree(o->vm.page,o->vm.usedpages);
2855 pthread_mutex_lock(&server.obj_freelist_mutex);
2856 if (listLength(server.objfreelist) > REDIS_OBJFREELIST_MAX ||
2857 !listAddNodeHead(server.objfreelist,o))
2858 zfree(o);
2859 pthread_mutex_unlock(&server.obj_freelist_mutex);
2860 server.vm_stats_swapped_objects--;
2861 return;
2862 }
2863 /* Object is in memory, or in the process of being swapped out. */
2864 if (--(o->refcount) == 0) {
2865 if (server.vm_enabled && o->storage == REDIS_VM_SWAPPING)
2866 vmCancelThreadedIOJob(obj);
2867 switch(o->type) {
2868 case REDIS_STRING: freeStringObject(o); break;
2869 case REDIS_LIST: freeListObject(o); break;
2870 case REDIS_SET: freeSetObject(o); break;
2871 case REDIS_ZSET: freeZsetObject(o); break;
2872 case REDIS_HASH: freeHashObject(o); break;
2873 default: redisAssert(0); break;
2874 }
2875 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
2876 if (listLength(server.objfreelist) > REDIS_OBJFREELIST_MAX ||
2877 !listAddNodeHead(server.objfreelist,o))
2878 zfree(o);
2879 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
2880 }
2881 }
2882
2883 static robj *lookupKey(redisDb *db, robj *key) {
2884 dictEntry *de = dictFind(db->dict,key);
2885 if (de) {
2886 robj *key = dictGetEntryKey(de);
2887 robj *val = dictGetEntryVal(de);
2888
2889 if (server.vm_enabled) {
2890 if (key->storage == REDIS_VM_MEMORY ||
2891 key->storage == REDIS_VM_SWAPPING)
2892 {
2893 /* If we were swapping the object out, stop it, this key
2894 * was requested. */
2895 if (key->storage == REDIS_VM_SWAPPING)
2896 vmCancelThreadedIOJob(key);
2897 /* Update the access time of the key for the aging algorithm. */
2898 key->vm.atime = server.unixtime;
2899 } else {
2900 int notify = (key->storage == REDIS_VM_LOADING);
2901
2902 /* Our value was swapped on disk. Bring it at home. */
2903 redisAssert(val == NULL);
2904 val = vmLoadObject(key);
2905 dictGetEntryVal(de) = val;
2906
2907 /* Clients blocked by the VM subsystem may be waiting for
2908 * this key... */
2909 if (notify) handleClientsBlockedOnSwappedKey(db,key);
2910 }
2911 }
2912 return val;
2913 } else {
2914 return NULL;
2915 }
2916 }
2917
2918 static robj *lookupKeyRead(redisDb *db, robj *key) {
2919 expireIfNeeded(db,key);
2920 return lookupKey(db,key);
2921 }
2922
2923 static robj *lookupKeyWrite(redisDb *db, robj *key) {
2924 deleteIfVolatile(db,key);
2925 return lookupKey(db,key);
2926 }
2927
2928 static robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply) {
2929 robj *o = lookupKeyRead(c->db, key);
2930 if (!o) addReply(c,reply);
2931 return o;
2932 }
2933
2934 static robj *lookupKeyWriteOrReply(redisClient *c, robj *key, robj *reply) {
2935 robj *o = lookupKeyWrite(c->db, key);
2936 if (!o) addReply(c,reply);
2937 return o;
2938 }
2939
2940 static int checkType(redisClient *c, robj *o, int type) {
2941 if (o->type != type) {
2942 addReply(c,shared.wrongtypeerr);
2943 return 1;
2944 }
2945 return 0;
2946 }
2947
2948 static int deleteKey(redisDb *db, robj *key) {
2949 int retval;
2950
2951 /* We need to protect key from destruction: after the first dictDelete()
2952 * it may happen that 'key' is no longer valid if we don't increment
2953 * it's count. This may happen when we get the object reference directly
2954 * from the hash table with dictRandomKey() or dict iterators */
2955 incrRefCount(key);
2956 if (dictSize(db->expires)) dictDelete(db->expires,key);
2957 retval = dictDelete(db->dict,key);
2958 decrRefCount(key);
2959
2960 return retval == DICT_OK;
2961 }
2962
2963 /* Try to share an object against the shared objects pool */
2964 static robj *tryObjectSharing(robj *o) {
2965 struct dictEntry *de;
2966 unsigned long c;
2967
2968 if (o == NULL || server.shareobjects == 0) return o;
2969
2970 redisAssert(o->type == REDIS_STRING);
2971 de = dictFind(server.sharingpool,o);
2972 if (de) {
2973 robj *shared = dictGetEntryKey(de);
2974
2975 c = ((unsigned long) dictGetEntryVal(de))+1;
2976 dictGetEntryVal(de) = (void*) c;
2977 incrRefCount(shared);
2978 decrRefCount(o);
2979 return shared;
2980 } else {
2981 /* Here we are using a stream algorihtm: Every time an object is
2982 * shared we increment its count, everytime there is a miss we
2983 * recrement the counter of a random object. If this object reaches
2984 * zero we remove the object and put the current object instead. */
2985 if (dictSize(server.sharingpool) >=
2986 server.sharingpoolsize) {
2987 de = dictGetRandomKey(server.sharingpool);
2988 redisAssert(de != NULL);
2989 c = ((unsigned long) dictGetEntryVal(de))-1;
2990 dictGetEntryVal(de) = (void*) c;
2991 if (c == 0) {
2992 dictDelete(server.sharingpool,de->key);
2993 }
2994 } else {
2995 c = 0; /* If the pool is empty we want to add this object */
2996 }
2997 if (c == 0) {
2998 int retval;
2999
3000 retval = dictAdd(server.sharingpool,o,(void*)1);
3001 redisAssert(retval == DICT_OK);
3002 incrRefCount(o);
3003 }
3004 return o;
3005 }
3006 }
3007
3008 /* Check if the nul-terminated string 's' can be represented by a long
3009 * (that is, is a number that fits into long without any other space or
3010 * character before or after the digits).
3011 *
3012 * If so, the function returns REDIS_OK and *longval is set to the value
3013 * of the number. Otherwise REDIS_ERR is returned */
3014 static int isStringRepresentableAsLong(sds s, long *longval) {
3015 char buf[32], *endptr;
3016 long value;
3017 int slen;
3018
3019 value = strtol(s, &endptr, 10);
3020 if (endptr[0] != '\0') return REDIS_ERR;
3021 slen = snprintf(buf,32,"%ld",value);
3022
3023 /* If the number converted back into a string is not identical
3024 * then it's not possible to encode the string as integer */
3025 if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR;
3026 if (longval) *longval = value;
3027 return REDIS_OK;
3028 }
3029
3030 /* Try to encode a string object in order to save space */
3031 static int tryObjectEncoding(robj *o) {
3032 long value;
3033 sds s = o->ptr;
3034
3035 if (o->encoding != REDIS_ENCODING_RAW)
3036 return REDIS_ERR; /* Already encoded */
3037
3038 /* It's not save to encode shared objects: shared objects can be shared
3039 * everywhere in the "object space" of Redis. Encoded objects can only
3040 * appear as "values" (and not, for instance, as keys) */
3041 if (o->refcount > 1) return REDIS_ERR;
3042
3043 /* Currently we try to encode only strings */
3044 redisAssert(o->type == REDIS_STRING);
3045
3046 /* Check if we can represent this string as a long integer */
3047 if (isStringRepresentableAsLong(s,&value) == REDIS_ERR) return REDIS_ERR;
3048
3049 /* Ok, this object can be encoded */
3050 o->encoding = REDIS_ENCODING_INT;
3051 sdsfree(o->ptr);
3052 o->ptr = (void*) value;
3053 return REDIS_OK;
3054 }
3055
3056 /* Get a decoded version of an encoded object (returned as a new object).
3057 * If the object is already raw-encoded just increment the ref count. */
3058 static robj *getDecodedObject(robj *o) {
3059 robj *dec;
3060
3061 if (o->encoding == REDIS_ENCODING_RAW) {
3062 incrRefCount(o);
3063 return o;
3064 }
3065 if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) {
3066 char buf[32];
3067
3068 snprintf(buf,32,"%ld",(long)o->ptr);
3069 dec = createStringObject(buf,strlen(buf));
3070 return dec;
3071 } else {
3072 redisAssert(1 != 1);
3073 }
3074 }
3075
3076 /* Compare two string objects via strcmp() or alike.
3077 * Note that the objects may be integer-encoded. In such a case we
3078 * use snprintf() to get a string representation of the numbers on the stack
3079 * and compare the strings, it's much faster than calling getDecodedObject().
3080 *
3081 * Important note: if objects are not integer encoded, but binary-safe strings,
3082 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
3083 * binary safe. */
3084 static int compareStringObjects(robj *a, robj *b) {
3085 redisAssert(a->type == REDIS_STRING && b->type == REDIS_STRING);
3086 char bufa[128], bufb[128], *astr, *bstr;
3087 int bothsds = 1;
3088
3089 if (a == b) return 0;
3090 if (a->encoding != REDIS_ENCODING_RAW) {
3091 snprintf(bufa,sizeof(bufa),"%ld",(long) a->ptr);
3092 astr = bufa;
3093 bothsds = 0;
3094 } else {
3095 astr = a->ptr;
3096 }
3097 if (b->encoding != REDIS_ENCODING_RAW) {
3098 snprintf(bufb,sizeof(bufb),"%ld",(long) b->ptr);
3099 bstr = bufb;
3100 bothsds = 0;
3101 } else {
3102 bstr = b->ptr;
3103 }
3104 return bothsds ? sdscmp(astr,bstr) : strcmp(astr,bstr);
3105 }
3106
3107 static size_t stringObjectLen(robj *o) {
3108 redisAssert(o->type == REDIS_STRING);
3109 if (o->encoding == REDIS_ENCODING_RAW) {
3110 return sdslen(o->ptr);
3111 } else {
3112 char buf[32];
3113
3114 return snprintf(buf,32,"%ld",(long)o->ptr);
3115 }
3116 }
3117
3118 /*============================ RDB saving/loading =========================== */
3119
3120 static int rdbSaveType(FILE *fp, unsigned char type) {
3121 if (fwrite(&type,1,1,fp) == 0) return -1;
3122 return 0;
3123 }
3124
3125 static int rdbSaveTime(FILE *fp, time_t t) {
3126 int32_t t32 = (int32_t) t;
3127 if (fwrite(&t32,4,1,fp) == 0) return -1;
3128 return 0;
3129 }
3130
3131 /* check rdbLoadLen() comments for more info */
3132 static int rdbSaveLen(FILE *fp, uint32_t len) {
3133 unsigned char buf[2];
3134
3135 if (len < (1<<6)) {
3136 /* Save a 6 bit len */
3137 buf[0] = (len&0xFF)|(REDIS_RDB_6BITLEN<<6);
3138 if (fwrite(buf,1,1,fp) == 0) return -1;
3139 } else if (len < (1<<14)) {
3140 /* Save a 14 bit len */
3141 buf[0] = ((len>>8)&0xFF)|(REDIS_RDB_14BITLEN<<6);
3142 buf[1] = len&0xFF;
3143 if (fwrite(buf,2,1,fp) == 0) return -1;
3144 } else {
3145 /* Save a 32 bit len */
3146 buf[0] = (REDIS_RDB_32BITLEN<<6);
3147 if (fwrite(buf,1,1,fp) == 0) return -1;
3148 len = htonl(len);
3149 if (fwrite(&len,4,1,fp) == 0) return -1;
3150 }
3151 return 0;
3152 }
3153
3154 /* String objects in the form "2391" "-100" without any space and with a
3155 * range of values that can fit in an 8, 16 or 32 bit signed value can be
3156 * encoded as integers to save space */
3157 static int rdbTryIntegerEncoding(char *s, size_t len, unsigned char *enc) {
3158 long long value;
3159 char *endptr, buf[32];
3160
3161 /* Check if it's possible to encode this value as a number */
3162 value = strtoll(s, &endptr, 10);
3163 if (endptr[0] != '\0') return 0;
3164 snprintf(buf,32,"%lld",value);
3165
3166 /* If the number converted back into a string is not identical
3167 * then it's not possible to encode the string as integer */
3168 if (strlen(buf) != len || memcmp(buf,s,len)) return 0;
3169
3170 /* Finally check if it fits in our ranges */
3171 if (value >= -(1<<7) && value <= (1<<7)-1) {
3172 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT8;
3173 enc[1] = value&0xFF;
3174 return 2;
3175 } else if (value >= -(1<<15) && value <= (1<<15)-1) {
3176 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT16;
3177 enc[1] = value&0xFF;
3178 enc[2] = (value>>8)&0xFF;
3179 return 3;
3180 } else if (value >= -((long long)1<<31) && value <= ((long long)1<<31)-1) {
3181 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT32;
3182 enc[1] = value&0xFF;
3183 enc[2] = (value>>8)&0xFF;
3184 enc[3] = (value>>16)&0xFF;
3185 enc[4] = (value>>24)&0xFF;
3186 return 5;
3187 } else {
3188 return 0;
3189 }
3190 }
3191
3192 static int rdbSaveLzfStringObject(FILE *fp, unsigned char *s, size_t len) {
3193 size_t comprlen, outlen;
3194 unsigned char byte;
3195 void *out;
3196
3197 /* We require at least four bytes compression for this to be worth it */
3198 if (len <= 4) return 0;
3199 outlen = len-4;
3200 if ((out = zmalloc(outlen+1)) == NULL) return 0;
3201 comprlen = lzf_compress(s, len, out, outlen);
3202 if (comprlen == 0) {
3203 zfree(out);
3204 return 0;
3205 }
3206 /* Data compressed! Let's save it on disk */
3207 byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF;
3208 if (fwrite(&byte,1,1,fp) == 0) goto writeerr;
3209 if (rdbSaveLen(fp,comprlen) == -1) goto writeerr;
3210 if (rdbSaveLen(fp,len) == -1) goto writeerr;
3211 if (fwrite(out,comprlen,1,fp) == 0) goto writeerr;
3212 zfree(out);
3213 return comprlen;
3214
3215 writeerr:
3216 zfree(out);
3217 return -1;
3218 }
3219
3220 /* Save a string objet as [len][data] on disk. If the object is a string
3221 * representation of an integer value we try to safe it in a special form */
3222 static int rdbSaveRawString(FILE *fp, unsigned char *s, size_t len) {
3223 int enclen;
3224
3225 /* Try integer encoding */
3226 if (len <= 11) {
3227 unsigned char buf[5];
3228 if ((enclen = rdbTryIntegerEncoding((char*)s,len,buf)) > 0) {
3229 if (fwrite(buf,enclen,1,fp) == 0) return -1;
3230 return 0;
3231 }
3232 }
3233
3234 /* Try LZF compression - under 20 bytes it's unable to compress even
3235 * aaaaaaaaaaaaaaaaaa so skip it */
3236 if (server.rdbcompression && len > 20) {
3237 int retval;
3238
3239 retval = rdbSaveLzfStringObject(fp,s,len);
3240 if (retval == -1) return -1;
3241 if (retval > 0) return 0;
3242 /* retval == 0 means data can't be compressed, save the old way */
3243 }
3244
3245 /* Store verbatim */
3246 if (rdbSaveLen(fp,len) == -1) return -1;
3247 if (len && fwrite(s,len,1,fp) == 0) return -1;
3248 return 0;
3249 }
3250
3251 /* Like rdbSaveStringObjectRaw() but handle encoded objects */
3252 static int rdbSaveStringObject(FILE *fp, robj *obj) {
3253 int retval;
3254
3255 /* Avoid incr/decr ref count business when possible.
3256 * This plays well with copy-on-write given that we are probably
3257 * in a child process (BGSAVE). Also this makes sure key objects
3258 * of swapped objects are not incRefCount-ed (an assert does not allow
3259 * this in order to avoid bugs) */
3260 if (obj->encoding != REDIS_ENCODING_RAW) {
3261 obj = getDecodedObject(obj);
3262 retval = rdbSaveRawString(fp,obj->ptr,sdslen(obj->ptr));
3263 decrRefCount(obj);
3264 } else {
3265 retval = rdbSaveRawString(fp,obj->ptr,sdslen(obj->ptr));
3266 }
3267 return retval;
3268 }
3269
3270 /* Save a double value. Doubles are saved as strings prefixed by an unsigned
3271 * 8 bit integer specifing the length of the representation.
3272 * This 8 bit integer has special values in order to specify the following
3273 * conditions:
3274 * 253: not a number
3275 * 254: + inf
3276 * 255: - inf
3277 */
3278 static int rdbSaveDoubleValue(FILE *fp, double val) {
3279 unsigned char buf[128];
3280 int len;
3281
3282 if (isnan(val)) {
3283 buf[0] = 253;
3284 len = 1;
3285 } else if (!isfinite(val)) {
3286 len = 1;
3287 buf[0] = (val < 0) ? 255 : 254;
3288 } else {
3289 snprintf((char*)buf+1,sizeof(buf)-1,"%.17g",val);
3290 buf[0] = strlen((char*)buf+1);
3291 len = buf[0]+1;
3292 }
3293 if (fwrite(buf,len,1,fp) == 0) return -1;
3294 return 0;
3295 }
3296
3297 /* Save a Redis object. */
3298 static int rdbSaveObject(FILE *fp, robj *o) {
3299 if (o->type == REDIS_STRING) {
3300 /* Save a string value */
3301 if (rdbSaveStringObject(fp,o) == -1) return -1;
3302 } else if (o->type == REDIS_LIST) {
3303 /* Save a list value */
3304 list *list = o->ptr;
3305 listIter li;
3306 listNode *ln;
3307
3308 if (rdbSaveLen(fp,listLength(list)) == -1) return -1;
3309 listRewind(list,&li);
3310 while((ln = listNext(&li))) {
3311 robj *eleobj = listNodeValue(ln);
3312
3313 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
3314 }
3315 } else if (o->type == REDIS_SET) {
3316 /* Save a set value */
3317 dict *set = o->ptr;
3318 dictIterator *di = dictGetIterator(set);
3319 dictEntry *de;
3320
3321 if (rdbSaveLen(fp,dictSize(set)) == -1) return -1;
3322 while((de = dictNext(di)) != NULL) {
3323 robj *eleobj = dictGetEntryKey(de);
3324
3325 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
3326 }
3327 dictReleaseIterator(di);
3328 } else if (o->type == REDIS_ZSET) {
3329 /* Save a set value */
3330 zset *zs = o->ptr;
3331 dictIterator *di = dictGetIterator(zs->dict);
3332 dictEntry *de;
3333
3334 if (rdbSaveLen(fp,dictSize(zs->dict)) == -1) return -1;
3335 while((de = dictNext(di)) != NULL) {
3336 robj *eleobj = dictGetEntryKey(de);
3337 double *score = dictGetEntryVal(de);
3338
3339 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
3340 if (rdbSaveDoubleValue(fp,*score) == -1) return -1;
3341 }
3342 dictReleaseIterator(di);
3343 } else if (o->type == REDIS_HASH) {
3344 /* Save a hash value */
3345 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
3346 unsigned char *p = zipmapRewind(o->ptr);
3347 unsigned int count = zipmapLen(o->ptr);
3348 unsigned char *key, *val;
3349 unsigned int klen, vlen;
3350
3351 if (rdbSaveLen(fp,count) == -1) return -1;
3352 while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
3353 if (rdbSaveRawString(fp,key,klen) == -1) return -1;
3354 if (rdbSaveRawString(fp,val,vlen) == -1) return -1;
3355 }
3356 } else {
3357 dictIterator *di = dictGetIterator(o->ptr);
3358 dictEntry *de;
3359
3360 if (rdbSaveLen(fp,dictSize((dict*)o->ptr)) == -1) return -1;
3361 while((de = dictNext(di)) != NULL) {
3362 robj *key = dictGetEntryKey(de);
3363 robj *val = dictGetEntryVal(de);
3364
3365 if (rdbSaveStringObject(fp,key) == -1) return -1;
3366 if (rdbSaveStringObject(fp,val) == -1) return -1;
3367 }
3368 dictReleaseIterator(di);
3369 }
3370 } else {
3371 redisAssert(0);
3372 }
3373 return 0;
3374 }
3375
3376 /* Return the length the object will have on disk if saved with
3377 * the rdbSaveObject() function. Currently we use a trick to get
3378 * this length with very little changes to the code. In the future
3379 * we could switch to a faster solution. */
3380 static off_t rdbSavedObjectLen(robj *o, FILE *fp) {
3381 if (fp == NULL) fp = server.devnull;
3382 rewind(fp);
3383 assert(rdbSaveObject(fp,o) != 1);
3384 return ftello(fp);
3385 }
3386
3387 /* Return the number of pages required to save this object in the swap file */
3388 static off_t rdbSavedObjectPages(robj *o, FILE *fp) {
3389 off_t bytes = rdbSavedObjectLen(o,fp);
3390
3391 return (bytes+(server.vm_page_size-1))/server.vm_page_size;
3392 }
3393
3394 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
3395 static int rdbSave(char *filename) {
3396 dictIterator *di = NULL;
3397 dictEntry *de;
3398 FILE *fp;
3399 char tmpfile[256];
3400 int j;
3401 time_t now = time(NULL);
3402
3403 /* Wait for I/O therads to terminate, just in case this is a
3404 * foreground-saving, to avoid seeking the swap file descriptor at the
3405 * same time. */
3406 if (server.vm_enabled)
3407 waitEmptyIOJobsQueue();
3408
3409 snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
3410 fp = fopen(tmpfile,"w");
3411 if (!fp) {
3412 redisLog(REDIS_WARNING, "Failed saving the DB: %s", strerror(errno));
3413 return REDIS_ERR;
3414 }
3415 if (fwrite("REDIS0001",9,1,fp) == 0) goto werr;
3416 for (j = 0; j < server.dbnum; j++) {
3417 redisDb *db = server.db+j;
3418 dict *d = db->dict;
3419 if (dictSize(d) == 0) continue;
3420 di = dictGetIterator(d);
3421 if (!di) {
3422 fclose(fp);
3423 return REDIS_ERR;
3424 }
3425
3426 /* Write the SELECT DB opcode */
3427 if (rdbSaveType(fp,REDIS_SELECTDB) == -1) goto werr;
3428 if (rdbSaveLen(fp,j) == -1) goto werr;
3429
3430 /* Iterate this DB writing every entry */
3431 while((de = dictNext(di)) != NULL) {
3432 robj *key = dictGetEntryKey(de);
3433 robj *o = dictGetEntryVal(de);
3434 time_t expiretime = getExpire(db,key);
3435
3436 /* Save the expire time */
3437 if (expiretime != -1) {
3438 /* If this key is already expired skip it */
3439 if (expiretime < now) continue;
3440 if (rdbSaveType(fp,REDIS_EXPIRETIME) == -1) goto werr;
3441 if (rdbSaveTime(fp,expiretime) == -1) goto werr;
3442 }
3443 /* Save the key and associated value. This requires special
3444 * handling if the value is swapped out. */
3445 if (!server.vm_enabled || key->storage == REDIS_VM_MEMORY ||
3446 key->storage == REDIS_VM_SWAPPING) {
3447 /* Save type, key, value */
3448 if (rdbSaveType(fp,o->type) == -1) goto werr;
3449 if (rdbSaveStringObject(fp,key) == -1) goto werr;
3450 if (rdbSaveObject(fp,o) == -1) goto werr;
3451 } else {
3452 /* REDIS_VM_SWAPPED or REDIS_VM_LOADING */
3453 robj *po;
3454 /* Get a preview of the object in memory */
3455 po = vmPreviewObject(key);
3456 /* Save type, key, value */
3457 if (rdbSaveType(fp,key->vtype) == -1) goto werr;
3458 if (rdbSaveStringObject(fp,key) == -1) goto werr;
3459 if (rdbSaveObject(fp,po) == -1) goto werr;
3460 /* Remove the loaded object from memory */
3461 decrRefCount(po);
3462 }
3463 }
3464 dictReleaseIterator(di);
3465 }
3466 /* EOF opcode */
3467 if (rdbSaveType(fp,REDIS_EOF) == -1) goto werr;
3468
3469 /* Make sure data will not remain on the OS's output buffers */
3470 fflush(fp);
3471 fsync(fileno(fp));
3472 fclose(fp);
3473
3474 /* Use RENAME to make sure the DB file is changed atomically only
3475 * if the generate DB file is ok. */
3476 if (rename(tmpfile,filename) == -1) {
3477 redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
3478 unlink(tmpfile);
3479 return REDIS_ERR;
3480 }
3481 redisLog(REDIS_NOTICE,"DB saved on disk");
3482 server.dirty = 0;
3483 server.lastsave = time(NULL);
3484 return REDIS_OK;
3485
3486 werr:
3487 fclose(fp);
3488 unlink(tmpfile);
3489 redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
3490 if (di) dictReleaseIterator(di);
3491 return REDIS_ERR;
3492 }
3493
3494 static int rdbSaveBackground(char *filename) {
3495 pid_t childpid;
3496
3497 if (server.bgsavechildpid != -1) return REDIS_ERR;
3498 if (server.vm_enabled) waitEmptyIOJobsQueue();
3499 if ((childpid = fork()) == 0) {
3500 /* Child */
3501 if (server.vm_enabled) vmReopenSwapFile();
3502 close(server.fd);
3503 if (rdbSave(filename) == REDIS_OK) {
3504 _exit(0);
3505 } else {
3506 _exit(1);
3507 }
3508 } else {
3509 /* Parent */
3510 if (childpid == -1) {
3511 redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
3512 strerror(errno));
3513 return REDIS_ERR;
3514 }
3515 redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
3516 server.bgsavechildpid = childpid;
3517 updateDictResizePolicy();
3518 return REDIS_OK;
3519 }
3520 return REDIS_OK; /* unreached */
3521 }
3522
3523 static void rdbRemoveTempFile(pid_t childpid) {
3524 char tmpfile[256];
3525
3526 snprintf(tmpfile,256,"temp-%d.rdb", (int) childpid);
3527 unlink(tmpfile);
3528 }
3529
3530 static int rdbLoadType(FILE *fp) {
3531 unsigned char type;
3532 if (fread(&type,1,1,fp) == 0) return -1;
3533 return type;
3534 }
3535
3536 static time_t rdbLoadTime(FILE *fp) {
3537 int32_t t32;
3538 if (fread(&t32,4,1,fp) == 0) return -1;
3539 return (time_t) t32;
3540 }
3541
3542 /* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
3543 * of this file for a description of how this are stored on disk.
3544 *
3545 * isencoded is set to 1 if the readed length is not actually a length but
3546 * an "encoding type", check the above comments for more info */
3547 static uint32_t rdbLoadLen(FILE *fp, int *isencoded) {
3548 unsigned char buf[2];
3549 uint32_t len;
3550 int type;
3551
3552 if (isencoded) *isencoded = 0;
3553 if (fread(buf,1,1,fp) == 0) return REDIS_RDB_LENERR;
3554 type = (buf[0]&0xC0)>>6;
3555 if (type == REDIS_RDB_6BITLEN) {
3556 /* Read a 6 bit len */
3557 return buf[0]&0x3F;
3558 } else if (type == REDIS_RDB_ENCVAL) {
3559 /* Read a 6 bit len encoding type */
3560 if (isencoded) *isencoded = 1;
3561 return buf[0]&0x3F;
3562 } else if (type == REDIS_RDB_14BITLEN) {
3563 /* Read a 14 bit len */
3564 if (fread(buf+1,1,1,fp) == 0) return REDIS_RDB_LENERR;
3565 return ((buf[0]&0x3F)<<8)|buf[1];
3566 } else {
3567 /* Read a 32 bit len */
3568 if (fread(&len,4,1,fp) == 0) return REDIS_RDB_LENERR;
3569 return ntohl(len);
3570 }
3571 }
3572
3573 static robj *rdbLoadIntegerObject(FILE *fp, int enctype) {
3574 unsigned char enc[4];
3575 long long val;
3576
3577 if (enctype == REDIS_RDB_ENC_INT8) {
3578 if (fread(enc,1,1,fp) == 0) return NULL;
3579 val = (signed char)enc[0];
3580 } else if (enctype == REDIS_RDB_ENC_INT16) {
3581 uint16_t v;
3582 if (fread(enc,2,1,fp) == 0) return NULL;
3583 v = enc[0]|(enc[1]<<8);
3584 val = (int16_t)v;
3585 } else if (enctype == REDIS_RDB_ENC_INT32) {
3586 uint32_t v;
3587 if (fread(enc,4,1,fp) == 0) return NULL;
3588 v = enc[0]|(enc[1]<<8)|(enc[2]<<16)|(enc[3]<<24);
3589 val = (int32_t)v;
3590 } else {
3591 val = 0; /* anti-warning */
3592 redisAssert(0);
3593 }
3594 return createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",val));
3595 }
3596
3597 static robj *rdbLoadLzfStringObject(FILE*fp) {
3598 unsigned int len, clen;
3599 unsigned char *c = NULL;
3600 sds val = NULL;
3601
3602 if ((clen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
3603 if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
3604 if ((c = zmalloc(clen)) == NULL) goto err;
3605 if ((val = sdsnewlen(NULL,len)) == NULL) goto err;
3606 if (fread(c,clen,1,fp) == 0) goto err;
3607 if (lzf_decompress(c,clen,val,len) == 0) goto err;
3608 zfree(c);
3609 return createObject(REDIS_STRING,val);
3610 err:
3611 zfree(c);
3612 sdsfree(val);
3613 return NULL;
3614 }
3615
3616 static robj *rdbLoadStringObject(FILE*fp) {
3617 int isencoded;
3618 uint32_t len;
3619 sds val;
3620
3621 len = rdbLoadLen(fp,&isencoded);
3622 if (isencoded) {
3623 switch(len) {
3624 case REDIS_RDB_ENC_INT8:
3625 case REDIS_RDB_ENC_INT16:
3626 case REDIS_RDB_ENC_INT32:
3627 return tryObjectSharing(rdbLoadIntegerObject(fp,len));
3628 case REDIS_RDB_ENC_LZF:
3629 return tryObjectSharing(rdbLoadLzfStringObject(fp));
3630 default:
3631 redisAssert(0);
3632 }
3633 }
3634
3635 if (len == REDIS_RDB_LENERR) return NULL;
3636 val = sdsnewlen(NULL,len);
3637 if (len && fread(val,len,1,fp) == 0) {
3638 sdsfree(val);
3639 return NULL;
3640 }
3641 return tryObjectSharing(createObject(REDIS_STRING,val));
3642 }
3643
3644 /* For information about double serialization check rdbSaveDoubleValue() */
3645 static int rdbLoadDoubleValue(FILE *fp, double *val) {
3646 char buf[128];
3647 unsigned char len;
3648
3649 if (fread(&len,1,1,fp) == 0) return -1;
3650 switch(len) {
3651 case 255: *val = R_NegInf; return 0;
3652 case 254: *val = R_PosInf; return 0;
3653 case 253: *val = R_Nan; return 0;
3654 default:
3655 if (fread(buf,len,1,fp) == 0) return -1;
3656 buf[len] = '\0';
3657 sscanf(buf, "%lg", val);
3658 return 0;
3659 }
3660 }
3661
3662 /* Load a Redis object of the specified type from the specified file.
3663 * On success a newly allocated object is returned, otherwise NULL. */
3664 static robj *rdbLoadObject(int type, FILE *fp) {
3665 robj *o;
3666
3667 redisLog(REDIS_DEBUG,"LOADING OBJECT %d (at %d)\n",type,ftell(fp));
3668 if (type == REDIS_STRING) {
3669 /* Read string value */
3670 if ((o = rdbLoadStringObject(fp)) == NULL) return NULL;
3671 tryObjectEncoding(o);
3672 } else if (type == REDIS_LIST || type == REDIS_SET) {
3673 /* Read list/set value */
3674 uint32_t listlen;
3675
3676 if ((listlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
3677 o = (type == REDIS_LIST) ? createListObject() : createSetObject();
3678 /* It's faster to expand the dict to the right size asap in order
3679 * to avoid rehashing */
3680 if (type == REDIS_SET && listlen > DICT_HT_INITIAL_SIZE)
3681 dictExpand(o->ptr,listlen);
3682 /* Load every single element of the list/set */
3683 while(listlen--) {
3684 robj *ele;
3685
3686 if ((ele = rdbLoadStringObject(fp)) == NULL) return NULL;
3687 tryObjectEncoding(ele);
3688 if (type == REDIS_LIST) {
3689 listAddNodeTail((list*)o->ptr,ele);
3690 } else {
3691 dictAdd((dict*)o->ptr,ele,NULL);
3692 }
3693 }
3694 } else if (type == REDIS_ZSET) {
3695 /* Read list/set value */
3696 size_t zsetlen;
3697 zset *zs;
3698
3699 if ((zsetlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
3700 o = createZsetObject();
3701 zs = o->ptr;
3702 /* Load every single element of the list/set */
3703 while(zsetlen--) {
3704 robj *ele;
3705 double *score = zmalloc(sizeof(double));
3706
3707 if ((ele = rdbLoadStringObject(fp)) == NULL) return NULL;
3708 tryObjectEncoding(ele);
3709 if (rdbLoadDoubleValue(fp,score) == -1) return NULL;
3710 dictAdd(zs->dict,ele,score);
3711 zslInsert(zs->zsl,*score,ele);
3712 incrRefCount(ele); /* added to skiplist */
3713 }
3714 } else if (type == REDIS_HASH) {
3715 size_t hashlen;
3716
3717 if ((hashlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
3718 o = createHashObject();
3719 /* Too many entries? Use an hash table. */
3720 if (hashlen > server.hash_max_zipmap_entries)
3721 convertToRealHash(o);
3722 /* Load every key/value, then set it into the zipmap or hash
3723 * table, as needed. */
3724 while(hashlen--) {
3725 robj *key, *val;
3726
3727 if ((key = rdbLoadStringObject(fp)) == NULL) return NULL;
3728 if ((val = rdbLoadStringObject(fp)) == NULL) return NULL;
3729 /* If we are using a zipmap and there are too big values
3730 * the object is converted to real hash table encoding. */
3731 if (o->encoding != REDIS_ENCODING_HT &&
3732 (sdslen(key->ptr) > server.hash_max_zipmap_value ||
3733 sdslen(val->ptr) > server.hash_max_zipmap_value))
3734 {
3735 convertToRealHash(o);
3736 }
3737
3738 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
3739 unsigned char *zm = o->ptr;
3740
3741 zm = zipmapSet(zm,key->ptr,sdslen(key->ptr),
3742 val->ptr,sdslen(val->ptr),NULL);
3743 o->ptr = zm;
3744 decrRefCount(key);
3745 decrRefCount(val);
3746 } else {
3747 tryObjectEncoding(key);
3748 tryObjectEncoding(val);
3749 dictAdd((dict*)o->ptr,key,val);
3750 }
3751 }
3752 } else {
3753 redisAssert(0);
3754 }
3755 return o;
3756 }
3757
3758 static int rdbLoad(char *filename) {
3759 FILE *fp;
3760 robj *keyobj = NULL;
3761 uint32_t dbid;
3762 int type, retval, rdbver;
3763 dict *d = server.db[0].dict;
3764 redisDb *db = server.db+0;
3765 char buf[1024];
3766 time_t expiretime = -1, now = time(NULL);
3767 long long loadedkeys = 0;
3768
3769 fp = fopen(filename,"r");
3770 if (!fp) return REDIS_ERR;
3771 if (fread(buf,9,1,fp) == 0) goto eoferr;
3772 buf[9] = '\0';
3773 if (memcmp(buf,"REDIS",5) != 0) {
3774 fclose(fp);
3775 redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
3776 return REDIS_ERR;
3777 }
3778 rdbver = atoi(buf+5);
3779 if (rdbver != 1) {
3780 fclose(fp);
3781 redisLog(REDIS_WARNING,"Can't handle RDB format version %d",rdbver);
3782 return REDIS_ERR;
3783 }
3784 while(1) {
3785 robj *o;
3786
3787 /* Read type. */
3788 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
3789 if (type == REDIS_EXPIRETIME) {
3790 if ((expiretime = rdbLoadTime(fp)) == -1) goto eoferr;
3791 /* We read the time so we need to read the object type again */
3792 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
3793 }
3794 if (type == REDIS_EOF) break;
3795 /* Handle SELECT DB opcode as a special case */
3796 if (type == REDIS_SELECTDB) {
3797 if ((dbid = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR)
3798 goto eoferr;
3799 if (dbid >= (unsigned)server.dbnum) {
3800 redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum);
3801 exit(1);
3802 }
3803 db = server.db+dbid;
3804 d = db->dict;
3805 continue;
3806 }
3807 /* Read key */
3808 if ((keyobj = rdbLoadStringObject(fp)) == NULL) goto eoferr;
3809 /* Read value */
3810 if ((o = rdbLoadObject(type,fp)) == NULL) goto eoferr;
3811 /* Add the new object in the hash table */
3812 retval = dictAdd(d,keyobj,o);
3813 if (retval == DICT_ERR) {
3814 redisLog(REDIS_WARNING,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj->ptr);
3815 exit(1);
3816 }
3817 /* Set the expire time if needed */
3818 if (expiretime != -1) {
3819 setExpire(db,keyobj,expiretime);
3820 /* Delete this key if already expired */
3821 if (expiretime < now) deleteKey(db,keyobj);
3822 expiretime = -1;
3823 }
3824 keyobj = o = NULL;
3825 /* Handle swapping while loading big datasets when VM is on */
3826 loadedkeys++;
3827 if (server.vm_enabled && (loadedkeys % 5000) == 0) {
3828 while (zmalloc_used_memory() > server.vm_max_memory) {
3829 if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
3830 }
3831 }
3832 }
3833 fclose(fp);
3834 return REDIS_OK;
3835
3836 eoferr: /* unexpected end of file is handled here with a fatal exit */
3837 if (keyobj) decrRefCount(keyobj);
3838 redisLog(REDIS_WARNING,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
3839 exit(1);
3840 return REDIS_ERR; /* Just to avoid warning */
3841 }
3842
3843 /*================================== Commands =============================== */
3844
3845 static void authCommand(redisClient *c) {
3846 if (!server.requirepass || !strcmp(c->argv[1]->ptr, server.requirepass)) {
3847 c->authenticated = 1;
3848 addReply(c,shared.ok);
3849 } else {
3850 c->authenticated = 0;
3851 addReplySds(c,sdscatprintf(sdsempty(),"-ERR invalid password\r\n"));
3852 }
3853 }
3854
3855 static void pingCommand(redisClient *c) {
3856 addReply(c,shared.pong);
3857 }
3858
3859 static void echoCommand(redisClient *c) {
3860 addReplyBulk(c,c->argv[1]);
3861 }
3862
3863 /*=================================== Strings =============================== */
3864
3865 static void setGenericCommand(redisClient *c, int nx) {
3866 int retval;
3867
3868 if (nx) deleteIfVolatile(c->db,c->argv[1]);
3869 retval = dictAdd(c->db->dict,c->argv[1],c->argv[2]);
3870 if (retval == DICT_ERR) {
3871 if (!nx) {
3872 /* If the key is about a swapped value, we want a new key object
3873 * to overwrite the old. So we delete the old key in the database.
3874 * This will also make sure that swap pages about the old object
3875 * will be marked as free. */
3876 if (server.vm_enabled && deleteIfSwapped(c->db,c->argv[1]))
3877 incrRefCount(c->argv[1]);
3878 dictReplace(c->db->dict,c->argv[1],c->argv[2]);
3879 incrRefCount(c->argv[2]);
3880 } else {
3881 addReply(c,shared.czero);
3882 return;
3883 }
3884 } else {
3885 incrRefCount(c->argv[1]);
3886 incrRefCount(c->argv[2]);
3887 }
3888 server.dirty++;
3889 removeExpire(c->db,c->argv[1]);
3890 addReply(c, nx ? shared.cone : shared.ok);
3891 }
3892
3893 static void setCommand(redisClient *c) {
3894 setGenericCommand(c,0);
3895 }
3896
3897 static void setnxCommand(redisClient *c) {
3898 setGenericCommand(c,1);
3899 }
3900
3901 static int getGenericCommand(redisClient *c) {
3902 robj *o;
3903
3904 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)
3905 return REDIS_OK;
3906
3907 if (o->type != REDIS_STRING) {
3908 addReply(c,shared.wrongtypeerr);
3909 return REDIS_ERR;
3910 } else {
3911 addReplyBulk(c,o);
3912 return REDIS_OK;
3913 }
3914 }
3915
3916 static void getCommand(redisClient *c) {
3917 getGenericCommand(c);
3918 }
3919
3920 static void getsetCommand(redisClient *c) {
3921 if (getGenericCommand(c) == REDIS_ERR) return;
3922 if (dictAdd(c->db->dict,c->argv[1],c->argv[2]) == DICT_ERR) {
3923 dictReplace(c->db->dict,c->argv[1],c->argv[2]);
3924 } else {
3925 incrRefCount(c->argv[1]);
3926 }
3927 incrRefCount(c->argv[2]);
3928 server.dirty++;
3929 removeExpire(c->db,c->argv[1]);
3930 }
3931
3932 static void mgetCommand(redisClient *c) {
3933 int j;
3934
3935 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-1));
3936 for (j = 1; j < c->argc; j++) {
3937 robj *o = lookupKeyRead(c->db,c->argv[j]);
3938 if (o == NULL) {
3939 addReply(c,shared.nullbulk);
3940 } else {
3941 if (o->type != REDIS_STRING) {
3942 addReply(c,shared.nullbulk);
3943 } else {
3944 addReplyBulk(c,o);
3945 }
3946 }
3947 }
3948 }
3949
3950 static void msetGenericCommand(redisClient *c, int nx) {
3951 int j, busykeys = 0;
3952
3953 if ((c->argc % 2) == 0) {
3954 addReplySds(c,sdsnew("-ERR wrong number of arguments for MSET\r\n"));
3955 return;
3956 }
3957 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
3958 * set nothing at all if at least one already key exists. */
3959 if (nx) {
3960 for (j = 1; j < c->argc; j += 2) {
3961 if (lookupKeyWrite(c->db,c->argv[j]) != NULL) {
3962 busykeys++;
3963 }
3964 }
3965 }
3966 if (busykeys) {
3967 addReply(c, shared.czero);
3968 return;
3969 }
3970
3971 for (j = 1; j < c->argc; j += 2) {
3972 int retval;
3973
3974 tryObjectEncoding(c->argv[j+1]);
3975 retval = dictAdd(c->db->dict,c->argv[j],c->argv[j+1]);
3976 if (retval == DICT_ERR) {
3977 dictReplace(c->db->dict,c->argv[j],c->argv[j+1]);
3978 incrRefCount(c->argv[j+1]);
3979 } else {
3980 incrRefCount(c->argv[j]);
3981 incrRefCount(c->argv[j+1]);
3982 }
3983 removeExpire(c->db,c->argv[j]);
3984 }
3985 server.dirty += (c->argc-1)/2;
3986 addReply(c, nx ? shared.cone : shared.ok);
3987 }
3988
3989 static void msetCommand(redisClient *c) {
3990 msetGenericCommand(c,0);
3991 }
3992
3993 static void msetnxCommand(redisClient *c) {
3994 msetGenericCommand(c,1);
3995 }
3996
3997 static void incrDecrCommand(redisClient *c, long long incr) {
3998 long long value;
3999 int retval;
4000 robj *o;
4001
4002 o = lookupKeyWrite(c->db,c->argv[1]);
4003 if (o == NULL) {
4004 value = 0;
4005 } else {
4006 if (o->type != REDIS_STRING) {
4007 value = 0;
4008 } else {
4009 char *eptr;
4010
4011 if (o->encoding == REDIS_ENCODING_RAW)
4012 value = strtoll(o->ptr, &eptr, 10);
4013 else if (o->encoding == REDIS_ENCODING_INT)
4014 value = (long)o->ptr;
4015 else
4016 redisAssert(1 != 1);
4017 }
4018 }
4019
4020 value += incr;
4021 o = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
4022 tryObjectEncoding(o);
4023 retval = dictAdd(c->db->dict,c->argv[1],o);
4024 if (retval == DICT_ERR) {
4025 dictReplace(c->db->dict,c->argv[1],o);
4026 removeExpire(c->db,c->argv[1]);
4027 } else {
4028 incrRefCount(c->argv[1]);
4029 }
4030 server.dirty++;
4031 addReply(c,shared.colon);
4032 addReply(c,o);
4033 addReply(c,shared.crlf);
4034 }
4035
4036 static void incrCommand(redisClient *c) {
4037 incrDecrCommand(c,1);
4038 }
4039
4040 static void decrCommand(redisClient *c) {
4041 incrDecrCommand(c,-1);
4042 }
4043
4044 static void incrbyCommand(redisClient *c) {
4045 long long incr = strtoll(c->argv[2]->ptr, NULL, 10);
4046 incrDecrCommand(c,incr);
4047 }
4048
4049 static void decrbyCommand(redisClient *c) {
4050 long long incr = strtoll(c->argv[2]->ptr, NULL, 10);
4051 incrDecrCommand(c,-incr);
4052 }
4053
4054 static void appendCommand(redisClient *c) {
4055 int retval;
4056 size_t totlen;
4057 robj *o;
4058
4059 o = lookupKeyWrite(c->db,c->argv[1]);
4060 if (o == NULL) {
4061 /* Create the key */
4062 retval = dictAdd(c->db->dict,c->argv[1],c->argv[2]);
4063 incrRefCount(c->argv[1]);
4064 incrRefCount(c->argv[2]);
4065 totlen = stringObjectLen(c->argv[2]);
4066 } else {
4067 dictEntry *de;
4068
4069 de = dictFind(c->db->dict,c->argv[1]);
4070 assert(de != NULL);
4071
4072 o = dictGetEntryVal(de);
4073 if (o->type != REDIS_STRING) {
4074 addReply(c,shared.wrongtypeerr);
4075 return;
4076 }
4077 /* If the object is specially encoded or shared we have to make
4078 * a copy */
4079 if (o->refcount != 1 || o->encoding != REDIS_ENCODING_RAW) {
4080 robj *decoded = getDecodedObject(o);
4081
4082 o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
4083 decrRefCount(decoded);
4084 dictReplace(c->db->dict,c->argv[1],o);
4085 }
4086 /* APPEND! */
4087 if (c->argv[2]->encoding == REDIS_ENCODING_RAW) {
4088 o->ptr = sdscatlen(o->ptr,
4089 c->argv[2]->ptr, sdslen(c->argv[2]->ptr));
4090 } else {
4091 o->ptr = sdscatprintf(o->ptr, "%ld",
4092 (unsigned long) c->argv[2]->ptr);
4093 }
4094 totlen = sdslen(o->ptr);
4095 }
4096 server.dirty++;
4097 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",(unsigned long)totlen));
4098 }
4099
4100 static void substrCommand(redisClient *c) {
4101 robj *o;
4102 long start = atoi(c->argv[2]->ptr);
4103 long end = atoi(c->argv[3]->ptr);
4104 size_t rangelen, strlen;
4105 sds range;
4106
4107 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
4108 checkType(c,o,REDIS_STRING)) return;
4109
4110 o = getDecodedObject(o);
4111 strlen = sdslen(o->ptr);
4112
4113 /* convert negative indexes */
4114 if (start < 0) start = strlen+start;
4115 if (end < 0) end = strlen+end;
4116 if (start < 0) start = 0;
4117 if (end < 0) end = 0;
4118
4119 /* indexes sanity checks */
4120 if (start > end || (size_t)start >= strlen) {
4121 /* Out of range start or start > end result in null reply */
4122 addReply(c,shared.nullbulk);
4123 decrRefCount(o);
4124 return;
4125 }
4126 if ((size_t)end >= strlen) end = strlen-1;
4127 rangelen = (end-start)+1;
4128
4129 /* Return the result */
4130 addReplySds(c,sdscatprintf(sdsempty(),"$%zu\r\n",rangelen));
4131 range = sdsnewlen((char*)o->ptr+start,rangelen);
4132 addReplySds(c,range);
4133 addReply(c,shared.crlf);
4134 decrRefCount(o);
4135 }
4136
4137 /* ========================= Type agnostic commands ========================= */
4138
4139 static void delCommand(redisClient *c) {
4140 int deleted = 0, j;
4141
4142 for (j = 1; j < c->argc; j++) {
4143 if (deleteKey(c->db,c->argv[j])) {
4144 server.dirty++;
4145 deleted++;
4146 }
4147 }
4148 addReplyLong(c,deleted);
4149 }
4150
4151 static void existsCommand(redisClient *c) {
4152 addReply(c,lookupKeyRead(c->db,c->argv[1]) ? shared.cone : shared.czero);
4153 }
4154
4155 static void selectCommand(redisClient *c) {
4156 int id = atoi(c->argv[1]->ptr);
4157
4158 if (selectDb(c,id) == REDIS_ERR) {
4159 addReplySds(c,sdsnew("-ERR invalid DB index\r\n"));
4160 } else {
4161 addReply(c,shared.ok);
4162 }
4163 }
4164
4165 static void randomkeyCommand(redisClient *c) {
4166 dictEntry *de;
4167
4168 while(1) {
4169 de = dictGetRandomKey(c->db->dict);
4170 if (!de || expireIfNeeded(c->db,dictGetEntryKey(de)) == 0) break;
4171 }
4172 if (de == NULL) {
4173 addReply(c,shared.plus);
4174 addReply(c,shared.crlf);
4175 } else {
4176 addReply(c,shared.plus);
4177 addReply(c,dictGetEntryKey(de));
4178 addReply(c,shared.crlf);
4179 }
4180 }
4181
4182 static void keysCommand(redisClient *c) {
4183 dictIterator *di;
4184 dictEntry *de;
4185 sds pattern = c->argv[1]->ptr;
4186 int plen = sdslen(pattern);
4187 unsigned long numkeys = 0;
4188 robj *lenobj = createObject(REDIS_STRING,NULL);
4189
4190 di = dictGetIterator(c->db->dict);
4191 addReply(c,lenobj);
4192 decrRefCount(lenobj);
4193 while((de = dictNext(di)) != NULL) {
4194 robj *keyobj = dictGetEntryKey(de);
4195
4196 sds key = keyobj->ptr;
4197 if ((pattern[0] == '*' && pattern[1] == '\0') ||
4198 stringmatchlen(pattern,plen,key,sdslen(key),0)) {
4199 if (expireIfNeeded(c->db,keyobj) == 0) {
4200 addReplyBulk(c,keyobj);
4201 numkeys++;
4202 }
4203 }
4204 }
4205 dictReleaseIterator(di);
4206 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",numkeys);
4207 }
4208
4209 static void dbsizeCommand(redisClient *c) {
4210 addReplySds(c,
4211 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c->db->dict)));
4212 }
4213
4214 static void lastsaveCommand(redisClient *c) {
4215 addReplySds(c,
4216 sdscatprintf(sdsempty(),":%lu\r\n",server.lastsave));
4217 }
4218
4219 static void typeCommand(redisClient *c) {
4220 robj *o;
4221 char *type;
4222
4223 o = lookupKeyRead(c->db,c->argv[1]);
4224 if (o == NULL) {
4225 type = "+none";
4226 } else {
4227 switch(o->type) {
4228 case REDIS_STRING: type = "+string"; break;
4229 case REDIS_LIST: type = "+list"; break;
4230 case REDIS_SET: type = "+set"; break;
4231 case REDIS_ZSET: type = "+zset"; break;
4232 case REDIS_HASH: type = "+hash"; break;
4233 default: type = "+unknown"; break;
4234 }
4235 }
4236 addReplySds(c,sdsnew(type));
4237 addReply(c,shared.crlf);
4238 }
4239
4240 static void saveCommand(redisClient *c) {
4241 if (server.bgsavechildpid != -1) {
4242 addReplySds(c,sdsnew("-ERR background save in progress\r\n"));
4243 return;
4244 }
4245 if (rdbSave(server.dbfilename) == REDIS_OK) {
4246 addReply(c,shared.ok);
4247 } else {
4248 addReply(c,shared.err);
4249 }
4250 }
4251
4252 static void bgsaveCommand(redisClient *c) {
4253 if (server.bgsavechildpid != -1) {
4254 addReplySds(c,sdsnew("-ERR background save already in progress\r\n"));
4255 return;
4256 }
4257 if (rdbSaveBackground(server.dbfilename) == REDIS_OK) {
4258 char *status = "+Background saving started\r\n";
4259 addReplySds(c,sdsnew(status));
4260 } else {
4261 addReply(c,shared.err);
4262 }
4263 }
4264
4265 static void shutdownCommand(redisClient *c) {
4266 redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
4267 /* Kill the saving child if there is a background saving in progress.
4268 We want to avoid race conditions, for instance our saving child may
4269 overwrite the synchronous saving did by SHUTDOWN. */
4270 if (server.bgsavechildpid != -1) {
4271 redisLog(REDIS_WARNING,"There is a live saving child. Killing it!");
4272 kill(server.bgsavechildpid,SIGKILL);
4273 rdbRemoveTempFile(server.bgsavechildpid);
4274 }
4275 if (server.appendonly) {
4276 /* Append only file: fsync() the AOF and exit */
4277 fsync(server.appendfd);
4278 if (server.vm_enabled) unlink(server.vm_swap_file);
4279 exit(0);
4280 } else {
4281 /* Snapshotting. Perform a SYNC SAVE and exit */
4282 if (rdbSave(server.dbfilename) == REDIS_OK) {
4283 if (server.daemonize)
4284 unlink(server.pidfile);
4285 redisLog(REDIS_WARNING,"%zu bytes used at exit",zmalloc_used_memory());
4286 redisLog(REDIS_WARNING,"Server exit now, bye bye...");
4287 if (server.vm_enabled) unlink(server.vm_swap_file);
4288 exit(0);
4289 } else {
4290 /* Ooops.. error saving! The best we can do is to continue
4291 * operating. Note that if there was a background saving process,
4292 * in the next cron() Redis will be notified that the background
4293 * saving aborted, handling special stuff like slaves pending for
4294 * synchronization... */
4295 redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
4296 addReplySds(c,
4297 sdsnew("-ERR can't quit, problems saving the DB\r\n"));
4298 }
4299 }
4300 }
4301
4302 static void renameGenericCommand(redisClient *c, int nx) {
4303 robj *o;
4304
4305 /* To use the same key as src and dst is probably an error */
4306 if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) {
4307 addReply(c,shared.sameobjecterr);
4308 return;
4309 }
4310
4311 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr)) == NULL)
4312 return;
4313
4314 incrRefCount(o);
4315 deleteIfVolatile(c->db,c->argv[2]);
4316 if (dictAdd(c->db->dict,c->argv[2],o) == DICT_ERR) {
4317 if (nx) {
4318 decrRefCount(o);
4319 addReply(c,shared.czero);
4320 return;
4321 }
4322 dictReplace(c->db->dict,c->argv[2],o);
4323 } else {
4324 incrRefCount(c->argv[2]);
4325 }
4326 deleteKey(c->db,c->argv[1]);
4327 server.dirty++;
4328 addReply(c,nx ? shared.cone : shared.ok);
4329 }
4330
4331 static void renameCommand(redisClient *c) {
4332 renameGenericCommand(c,0);
4333 }
4334
4335 static void renamenxCommand(redisClient *c) {
4336 renameGenericCommand(c,1);
4337 }
4338
4339 static void moveCommand(redisClient *c) {
4340 robj *o;
4341 redisDb *src, *dst;
4342 int srcid;
4343
4344 /* Obtain source and target DB pointers */
4345 src = c->db;
4346 srcid = c->db->id;
4347 if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) {
4348 addReply(c,shared.outofrangeerr);
4349 return;
4350 }
4351 dst = c->db;
4352 selectDb(c,srcid); /* Back to the source DB */
4353
4354 /* If the user is moving using as target the same
4355 * DB as the source DB it is probably an error. */
4356 if (src == dst) {
4357 addReply(c,shared.sameobjecterr);
4358 return;
4359 }
4360
4361 /* Check if the element exists and get a reference */
4362 o = lookupKeyWrite(c->db,c->argv[1]);
4363 if (!o) {
4364 addReply(c,shared.czero);
4365 return;
4366 }
4367
4368 /* Try to add the element to the target DB */
4369 deleteIfVolatile(dst,c->argv[1]);
4370 if (dictAdd(dst->dict,c->argv[1],o) == DICT_ERR) {
4371 addReply(c,shared.czero);
4372 return;
4373 }
4374 incrRefCount(c->argv[1]);
4375 incrRefCount(o);
4376
4377 /* OK! key moved, free the entry in the source DB */
4378 deleteKey(src,c->argv[1]);
4379 server.dirty++;
4380 addReply(c,shared.cone);
4381 }
4382
4383 /* =================================== Lists ================================ */
4384 static void pushGenericCommand(redisClient *c, int where) {
4385 robj *lobj;
4386 list *list;
4387
4388 lobj = lookupKeyWrite(c->db,c->argv[1]);
4389 if (lobj == NULL) {
4390 if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) {
4391 addReply(c,shared.cone);
4392 return;
4393 }
4394 lobj = createListObject();
4395 list = lobj->ptr;
4396 if (where == REDIS_HEAD) {
4397 listAddNodeHead(list,c->argv[2]);
4398 } else {
4399 listAddNodeTail(list,c->argv[2]);
4400 }
4401 dictAdd(c->db->dict,c->argv[1],lobj);
4402 incrRefCount(c->argv[1]);
4403 incrRefCount(c->argv[2]);
4404 } else {
4405 if (lobj->type != REDIS_LIST) {
4406 addReply(c,shared.wrongtypeerr);
4407 return;
4408 }
4409 if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) {
4410 addReply(c,shared.cone);
4411 return;
4412 }
4413 list = lobj->ptr;
4414 if (where == REDIS_HEAD) {
4415 listAddNodeHead(list,c->argv[2]);
4416 } else {
4417 listAddNodeTail(list,c->argv[2]);
4418 }
4419 incrRefCount(c->argv[2]);
4420 }
4421 server.dirty++;
4422 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",listLength(list)));
4423 }
4424
4425 static void lpushCommand(redisClient *c) {
4426 pushGenericCommand(c,REDIS_HEAD);
4427 }
4428
4429 static void rpushCommand(redisClient *c) {
4430 pushGenericCommand(c,REDIS_TAIL);
4431 }
4432
4433 static void llenCommand(redisClient *c) {
4434 robj *o;
4435 list *l;
4436
4437 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
4438 checkType(c,o,REDIS_LIST)) return;
4439
4440 l = o->ptr;
4441 addReplyUlong(c,listLength(l));
4442 }
4443
4444 static void lindexCommand(redisClient *c) {
4445 robj *o;
4446 int index = atoi(c->argv[2]->ptr);
4447 list *list;
4448 listNode *ln;
4449
4450 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
4451 checkType(c,o,REDIS_LIST)) return;
4452 list = o->ptr;
4453
4454 ln = listIndex(list, index);
4455 if (ln == NULL) {
4456 addReply(c,shared.nullbulk);
4457 } else {
4458 robj *ele = listNodeValue(ln);
4459 addReplyBulk(c,ele);
4460 }
4461 }
4462
4463 static void lsetCommand(redisClient *c) {
4464 robj *o;
4465 int index = atoi(c->argv[2]->ptr);
4466 list *list;
4467 listNode *ln;
4468
4469 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr)) == NULL ||
4470 checkType(c,o,REDIS_LIST)) return;
4471 list = o->ptr;
4472
4473 ln = listIndex(list, index);
4474 if (ln == NULL) {
4475 addReply(c,shared.outofrangeerr);
4476 } else {
4477 robj *ele = listNodeValue(ln);
4478
4479 decrRefCount(ele);
4480 listNodeValue(ln) = c->argv[3];
4481 incrRefCount(c->argv[3]);
4482 addReply(c,shared.ok);
4483 server.dirty++;
4484 }
4485 }
4486
4487 static void popGenericCommand(redisClient *c, int where) {
4488 robj *o;
4489 list *list;
4490 listNode *ln;
4491
4492 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
4493 checkType(c,o,REDIS_LIST)) return;
4494 list = o->ptr;
4495
4496 if (where == REDIS_HEAD)
4497 ln = listFirst(list);
4498 else
4499 ln = listLast(list);
4500
4501 if (ln == NULL) {
4502 addReply(c,shared.nullbulk);
4503 } else {
4504 robj *ele = listNodeValue(ln);
4505 addReplyBulk(c,ele);
4506 listDelNode(list,ln);
4507 if (listLength(list) == 0) deleteKey(c->db,c->argv[1]);
4508 server.dirty++;
4509 }
4510 }
4511
4512 static void lpopCommand(redisClient *c) {
4513 popGenericCommand(c,REDIS_HEAD);
4514 }
4515
4516 static void rpopCommand(redisClient *c) {
4517 popGenericCommand(c,REDIS_TAIL);
4518 }
4519
4520 static void lrangeCommand(redisClient *c) {
4521 robj *o;
4522 int start = atoi(c->argv[2]->ptr);
4523 int end = atoi(c->argv[3]->ptr);
4524 int llen;
4525 int rangelen, j;
4526 list *list;
4527 listNode *ln;
4528 robj *ele;
4529
4530 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullmultibulk)) == NULL ||
4531 checkType(c,o,REDIS_LIST)) return;
4532 list = o->ptr;
4533 llen = listLength(list);
4534
4535 /* convert negative indexes */
4536 if (start < 0) start = llen+start;
4537 if (end < 0) end = llen+end;
4538 if (start < 0) start = 0;
4539 if (end < 0) end = 0;
4540
4541 /* indexes sanity checks */
4542 if (start > end || start >= llen) {
4543 /* Out of range start or start > end result in empty list */
4544 addReply(c,shared.emptymultibulk);
4545 return;
4546 }
4547 if (end >= llen) end = llen-1;
4548 rangelen = (end-start)+1;
4549
4550 /* Return the result in form of a multi-bulk reply */
4551 ln = listIndex(list, start);
4552 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen));
4553 for (j = 0; j < rangelen; j++) {
4554 ele = listNodeValue(ln);
4555 addReplyBulk(c,ele);
4556 ln = ln->next;
4557 }
4558 }
4559
4560 static void ltrimCommand(redisClient *c) {
4561 robj *o;
4562 int start = atoi(c->argv[2]->ptr);
4563 int end = atoi(c->argv[3]->ptr);
4564 int llen;
4565 int j, ltrim, rtrim;
4566 list *list;
4567 listNode *ln;
4568
4569 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.ok)) == NULL ||
4570 checkType(c,o,REDIS_LIST)) return;
4571 list = o->ptr;
4572 llen = listLength(list);
4573
4574 /* convert negative indexes */
4575 if (start < 0) start = llen+start;
4576 if (end < 0) end = llen+end;
4577 if (start < 0) start = 0;
4578 if (end < 0) end = 0;
4579
4580 /* indexes sanity checks */
4581 if (start > end || start >= llen) {
4582 /* Out of range start or start > end result in empty list */
4583 ltrim = llen;
4584 rtrim = 0;
4585 } else {
4586 if (end >= llen) end = llen-1;
4587 ltrim = start;
4588 rtrim = llen-end-1;
4589 }
4590
4591 /* Remove list elements to perform the trim */
4592 for (j = 0; j < ltrim; j++) {
4593 ln = listFirst(list);
4594 listDelNode(list,ln);
4595 }
4596 for (j = 0; j < rtrim; j++) {
4597 ln = listLast(list);
4598 listDelNode(list,ln);
4599 }
4600 if (listLength(list) == 0) deleteKey(c->db,c->argv[1]);
4601 server.dirty++;
4602 addReply(c,shared.ok);
4603 }
4604
4605 static void lremCommand(redisClient *c) {
4606 robj *o;
4607 list *list;
4608 listNode *ln, *next;
4609 int toremove = atoi(c->argv[2]->ptr);
4610 int removed = 0;
4611 int fromtail = 0;
4612
4613 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
4614 checkType(c,o,REDIS_LIST)) return;
4615 list = o->ptr;
4616
4617 if (toremove < 0) {
4618 toremove = -toremove;
4619 fromtail = 1;
4620 }
4621 ln = fromtail ? list->tail : list->head;
4622 while (ln) {
4623 robj *ele = listNodeValue(ln);
4624
4625 next = fromtail ? ln->prev : ln->next;
4626 if (compareStringObjects(ele,c->argv[3]) == 0) {
4627 listDelNode(list,ln);
4628 server.dirty++;
4629 removed++;
4630 if (toremove && removed == toremove) break;
4631 }
4632 ln = next;
4633 }
4634 if (listLength(list) == 0) deleteKey(c->db,c->argv[1]);
4635 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",removed));
4636 }
4637
4638 /* This is the semantic of this command:
4639 * RPOPLPUSH srclist dstlist:
4640 * IF LLEN(srclist) > 0
4641 * element = RPOP srclist
4642 * LPUSH dstlist element
4643 * RETURN element
4644 * ELSE
4645 * RETURN nil
4646 * END
4647 * END
4648 *
4649 * The idea is to be able to get an element from a list in a reliable way
4650 * since the element is not just returned but pushed against another list
4651 * as well. This command was originally proposed by Ezra Zygmuntowicz.
4652 */
4653 static void rpoplpushcommand(redisClient *c) {
4654 robj *sobj;
4655 list *srclist;
4656 listNode *ln;
4657
4658 if ((sobj = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
4659 checkType(c,sobj,REDIS_LIST)) return;
4660 srclist = sobj->ptr;
4661 ln = listLast(srclist);
4662
4663 if (ln == NULL) {
4664 addReply(c,shared.nullbulk);
4665 } else {
4666 robj *dobj = lookupKeyWrite(c->db,c->argv[2]);
4667 robj *ele = listNodeValue(ln);
4668 list *dstlist;
4669
4670 if (dobj && dobj->type != REDIS_LIST) {
4671 addReply(c,shared.wrongtypeerr);
4672 return;
4673 }
4674
4675 /* Add the element to the target list (unless it's directly
4676 * passed to some BLPOP-ing client */
4677 if (!handleClientsWaitingListPush(c,c->argv[2],ele)) {
4678 if (dobj == NULL) {
4679 /* Create the list if the key does not exist */
4680 dobj = createListObject();
4681 dictAdd(c->db->dict,c->argv[2],dobj);
4682 incrRefCount(c->argv[2]);
4683 }
4684 dstlist = dobj->ptr;
4685 listAddNodeHead(dstlist,ele);
4686 incrRefCount(ele);
4687 }
4688
4689 /* Send the element to the client as reply as well */
4690 addReplyBulk(c,ele);
4691
4692 /* Finally remove the element from the source list */
4693 listDelNode(srclist,ln);
4694 if (listLength(srclist) == 0) deleteKey(c->db,c->argv[1]);
4695 server.dirty++;
4696 }
4697 }
4698
4699 /* ==================================== Sets ================================ */
4700
4701 static void saddCommand(redisClient *c) {
4702 robj *set;
4703
4704 set = lookupKeyWrite(c->db,c->argv[1]);
4705 if (set == NULL) {
4706 set = createSetObject();
4707 dictAdd(c->db->dict,c->argv[1],set);
4708 incrRefCount(c->argv[1]);
4709 } else {
4710 if (set->type != REDIS_SET) {
4711 addReply(c,shared.wrongtypeerr);
4712 return;
4713 }
4714 }
4715 if (dictAdd(set->ptr,c->argv[2],NULL) == DICT_OK) {
4716 incrRefCount(c->argv[2]);
4717 server.dirty++;
4718 addReply(c,shared.cone);
4719 } else {
4720 addReply(c,shared.czero);
4721 }
4722 }
4723
4724 static void sremCommand(redisClient *c) {
4725 robj *set;
4726
4727 if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
4728 checkType(c,set,REDIS_SET)) return;
4729
4730 if (dictDelete(set->ptr,c->argv[2]) == DICT_OK) {
4731 server.dirty++;
4732 if (htNeedsResize(set->ptr)) dictResize(set->ptr);
4733 if (dictSize((dict*)set->ptr) == 0) deleteKey(c->db,c->argv[1]);
4734 addReply(c,shared.cone);
4735 } else {
4736 addReply(c,shared.czero);
4737 }
4738 }
4739
4740 static void smoveCommand(redisClient *c) {
4741 robj *srcset, *dstset;
4742
4743 srcset = lookupKeyWrite(c->db,c->argv[1]);
4744 dstset = lookupKeyWrite(c->db,c->argv[2]);
4745
4746 /* If the source key does not exist return 0, if it's of the wrong type
4747 * raise an error */
4748 if (srcset == NULL || srcset->type != REDIS_SET) {
4749 addReply(c, srcset ? shared.wrongtypeerr : shared.czero);
4750 return;
4751 }
4752 /* Error if the destination key is not a set as well */
4753 if (dstset && dstset->type != REDIS_SET) {
4754 addReply(c,shared.wrongtypeerr);
4755 return;
4756 }
4757 /* Remove the element from the source set */
4758 if (dictDelete(srcset->ptr,c->argv[3]) == DICT_ERR) {
4759 /* Key not found in the src set! return zero */
4760 addReply(c,shared.czero);
4761 return;
4762 }
4763 if (dictSize((dict*)srcset->ptr) == 0 && srcset != dstset)
4764 deleteKey(c->db,c->argv[1]);
4765 server.dirty++;
4766 /* Add the element to the destination set */
4767 if (!dstset) {
4768 dstset = createSetObject();
4769 dictAdd(c->db->dict,c->argv[2],dstset);
4770 incrRefCount(c->argv[2]);
4771 }
4772 if (dictAdd(dstset->ptr,c->argv[3],NULL) == DICT_OK)
4773 incrRefCount(c->argv[3]);
4774 addReply(c,shared.cone);
4775 }
4776
4777 static void sismemberCommand(redisClient *c) {
4778 robj *set;
4779
4780 if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
4781 checkType(c,set,REDIS_SET)) return;
4782
4783 if (dictFind(set->ptr,c->argv[2]))
4784 addReply(c,shared.cone);
4785 else
4786 addReply(c,shared.czero);
4787 }
4788
4789 static void scardCommand(redisClient *c) {
4790 robj *o;
4791 dict *s;
4792
4793 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
4794 checkType(c,o,REDIS_SET)) return;
4795
4796 s = o->ptr;
4797 addReplyUlong(c,dictSize(s));
4798 }
4799
4800 static void spopCommand(redisClient *c) {
4801 robj *set;
4802 dictEntry *de;
4803
4804 if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
4805 checkType(c,set,REDIS_SET)) return;
4806
4807 de = dictGetRandomKey(set->ptr);
4808 if (de == NULL) {
4809 addReply(c,shared.nullbulk);
4810 } else {
4811 robj *ele = dictGetEntryKey(de);
4812
4813 addReplyBulk(c,ele);
4814 dictDelete(set->ptr,ele);
4815 if (htNeedsResize(set->ptr)) dictResize(set->ptr);
4816 if (dictSize((dict*)set->ptr) == 0) deleteKey(c->db,c->argv[1]);
4817 server.dirty++;
4818 }
4819 }
4820
4821 static void srandmemberCommand(redisClient *c) {
4822 robj *set;
4823 dictEntry *de;
4824
4825 if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
4826 checkType(c,set,REDIS_SET)) return;
4827
4828 de = dictGetRandomKey(set->ptr);
4829 if (de == NULL) {
4830 addReply(c,shared.nullbulk);
4831 } else {
4832 robj *ele = dictGetEntryKey(de);
4833
4834 addReplyBulk(c,ele);
4835 }
4836 }
4837
4838 static int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
4839 dict **d1 = (void*) s1, **d2 = (void*) s2;
4840
4841 return dictSize(*d1)-dictSize(*d2);
4842 }
4843
4844 static void sinterGenericCommand(redisClient *c, robj **setskeys, unsigned long setsnum, robj *dstkey) {
4845 dict **dv = zmalloc(sizeof(dict*)*setsnum);
4846 dictIterator *di;
4847 dictEntry *de;
4848 robj *lenobj = NULL, *dstset = NULL;
4849 unsigned long j, cardinality = 0;
4850
4851 for (j = 0; j < setsnum; j++) {
4852 robj *setobj;
4853
4854 setobj = dstkey ?
4855 lookupKeyWrite(c->db,setskeys[j]) :
4856 lookupKeyRead(c->db,setskeys[j]);
4857 if (!setobj) {
4858 zfree(dv);
4859 if (dstkey) {
4860 if (deleteKey(c->db,dstkey))
4861 server.dirty++;
4862 addReply(c,shared.czero);
4863 } else {
4864 addReply(c,shared.nullmultibulk);
4865 }
4866 return;
4867 }
4868 if (setobj->type != REDIS_SET) {
4869 zfree(dv);
4870 addReply(c,shared.wrongtypeerr);
4871 return;
4872 }
4873 dv[j] = setobj->ptr;
4874 }
4875 /* Sort sets from the smallest to largest, this will improve our
4876 * algorithm's performace */
4877 qsort(dv,setsnum,sizeof(dict*),qsortCompareSetsByCardinality);
4878
4879 /* The first thing we should output is the total number of elements...
4880 * since this is a multi-bulk write, but at this stage we don't know
4881 * the intersection set size, so we use a trick, append an empty object
4882 * to the output list and save the pointer to later modify it with the
4883 * right length */
4884 if (!dstkey) {
4885 lenobj = createObject(REDIS_STRING,NULL);
4886 addReply(c,lenobj);
4887 decrRefCount(lenobj);
4888 } else {
4889 /* If we have a target key where to store the resulting set
4890 * create this key with an empty set inside */
4891 dstset = createSetObject();
4892 }
4893
4894 /* Iterate all the elements of the first (smallest) set, and test
4895 * the element against all the other sets, if at least one set does
4896 * not include the element it is discarded */
4897 di = dictGetIterator(dv[0]);
4898
4899 while((de = dictNext(di)) != NULL) {
4900 robj *ele;
4901
4902 for (j = 1; j < setsnum; j++)
4903 if (dictFind(dv[j],dictGetEntryKey(de)) == NULL) break;
4904 if (j != setsnum)
4905 continue; /* at least one set does not contain the member */
4906 ele = dictGetEntryKey(de);
4907 if (!dstkey) {
4908 addReplyBulk(c,ele);
4909 cardinality++;
4910 } else {
4911 dictAdd(dstset->ptr,ele,NULL);
4912 incrRefCount(ele);
4913 }
4914 }
4915 dictReleaseIterator(di);
4916
4917 if (dstkey) {
4918 /* Store the resulting set into the target, if the intersection
4919 * is not an empty set. */
4920 deleteKey(c->db,dstkey);
4921 if (dictSize((dict*)dstset->ptr) > 0) {
4922 dictAdd(c->db->dict,dstkey,dstset);
4923 incrRefCount(dstkey);
4924 addReplyLong(c,dictSize((dict*)dstset->ptr));
4925 } else {
4926 decrRefCount(dstset);
4927 addReply(c,shared.czero);
4928 }
4929 server.dirty++;
4930 } else {
4931 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",cardinality);
4932 }
4933 zfree(dv);
4934 }
4935
4936 static void sinterCommand(redisClient *c) {
4937 sinterGenericCommand(c,c->argv+1,c->argc-1,NULL);
4938 }
4939
4940 static void sinterstoreCommand(redisClient *c) {
4941 sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
4942 }
4943
4944 #define REDIS_OP_UNION 0
4945 #define REDIS_OP_DIFF 1
4946 #define REDIS_OP_INTER 2
4947
4948 static void sunionDiffGenericCommand(redisClient *c, robj **setskeys, int setsnum, robj *dstkey, int op) {
4949 dict **dv = zmalloc(sizeof(dict*)*setsnum);
4950 dictIterator *di;
4951 dictEntry *de;
4952 robj *dstset = NULL;
4953 int j, cardinality = 0;
4954
4955 for (j = 0; j < setsnum; j++) {
4956 robj *setobj;
4957
4958 setobj = dstkey ?
4959 lookupKeyWrite(c->db,setskeys[j]) :
4960 lookupKeyRead(c->db,setskeys[j]);
4961 if (!setobj) {
4962 dv[j] = NULL;
4963 continue;
4964 }
4965 if (setobj->type != REDIS_SET) {
4966 zfree(dv);
4967 addReply(c,shared.wrongtypeerr);
4968 return;
4969 }
4970 dv[j] = setobj->ptr;
4971 }
4972
4973 /* We need a temp set object to store our union. If the dstkey
4974 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
4975 * this set object will be the resulting object to set into the target key*/
4976 dstset = createSetObject();
4977
4978 /* Iterate all the elements of all the sets, add every element a single
4979 * time to the result set */
4980 for (j = 0; j < setsnum; j++) {
4981 if (op == REDIS_OP_DIFF && j == 0 && !dv[j]) break; /* result set is empty */
4982 if (!dv[j]) continue; /* non existing keys are like empty sets */
4983
4984 di = dictGetIterator(dv[j]);
4985
4986 while((de = dictNext(di)) != NULL) {
4987 robj *ele;
4988
4989 /* dictAdd will not add the same element multiple times */
4990 ele = dictGetEntryKey(de);
4991 if (op == REDIS_OP_UNION || j == 0) {
4992 if (dictAdd(dstset->ptr,ele,NULL) == DICT_OK) {
4993 incrRefCount(ele);
4994 cardinality++;
4995 }
4996 } else if (op == REDIS_OP_DIFF) {
4997 if (dictDelete(dstset->ptr,ele) == DICT_OK) {
4998 cardinality--;
4999 }
5000 }
5001 }
5002 dictReleaseIterator(di);
5003
5004 /* result set is empty? Exit asap. */
5005 if (op == REDIS_OP_DIFF && cardinality == 0) break;
5006 }
5007
5008 /* Output the content of the resulting set, if not in STORE mode */
5009 if (!dstkey) {
5010 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",cardinality));
5011 di = dictGetIterator(dstset->ptr);
5012 while((de = dictNext(di)) != NULL) {
5013 robj *ele;
5014
5015 ele = dictGetEntryKey(de);
5016 addReplyBulk(c,ele);
5017 }
5018 dictReleaseIterator(di);
5019 decrRefCount(dstset);
5020 } else {
5021 /* If we have a target key where to store the resulting set
5022 * create this key with the result set inside */
5023 deleteKey(c->db,dstkey);
5024 if (dictSize((dict*)dstset->ptr) > 0) {
5025 dictAdd(c->db->dict,dstkey,dstset);
5026 incrRefCount(dstkey);
5027 addReplyLong(c,dictSize((dict*)dstset->ptr));
5028 } else {
5029 decrRefCount(dstset);
5030 addReply(c,shared.czero);
5031 }
5032 server.dirty++;
5033 }
5034 zfree(dv);
5035 }
5036
5037 static void sunionCommand(redisClient *c) {
5038 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_UNION);
5039 }
5040
5041 static void sunionstoreCommand(redisClient *c) {
5042 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_UNION);
5043 }
5044
5045 static void sdiffCommand(redisClient *c) {
5046 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_DIFF);
5047 }
5048
5049 static void sdiffstoreCommand(redisClient *c) {
5050 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_DIFF);
5051 }
5052
5053 /* ==================================== ZSets =============================== */
5054
5055 /* ZSETs are ordered sets using two data structures to hold the same elements
5056 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
5057 * data structure.
5058 *
5059 * The elements are added to an hash table mapping Redis objects to scores.
5060 * At the same time the elements are added to a skip list mapping scores
5061 * to Redis objects (so objects are sorted by scores in this "view"). */
5062
5063 /* This skiplist implementation is almost a C translation of the original
5064 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
5065 * Alternative to Balanced Trees", modified in three ways:
5066 * a) this implementation allows for repeated values.
5067 * b) the comparison is not just by key (our 'score') but by satellite data.
5068 * c) there is a back pointer, so it's a doubly linked list with the back
5069 * pointers being only at "level 1". This allows to traverse the list
5070 * from tail to head, useful for ZREVRANGE. */
5071
5072 static zskiplistNode *zslCreateNode(int level, double score, robj *obj) {
5073 zskiplistNode *zn = zmalloc(sizeof(*zn));
5074
5075 zn->forward = zmalloc(sizeof(zskiplistNode*) * level);
5076 if (level > 0)
5077 zn->span = zmalloc(sizeof(unsigned int) * (level - 1));
5078 zn->score = score;
5079 zn->obj = obj;
5080 return zn;
5081 }
5082
5083 static zskiplist *zslCreate(void) {
5084 int j;
5085 zskiplist *zsl;
5086
5087 zsl = zmalloc(sizeof(*zsl));
5088 zsl->level = 1;
5089 zsl->length = 0;
5090 zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
5091 for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
5092 zsl->header->forward[j] = NULL;
5093
5094 /* span has space for ZSKIPLIST_MAXLEVEL-1 elements */
5095 if (j < ZSKIPLIST_MAXLEVEL-1)
5096 zsl->header->span[j] = 0;
5097 }
5098 zsl->header->backward = NULL;
5099 zsl->tail = NULL;
5100 return zsl;
5101 }
5102
5103 static void zslFreeNode(zskiplistNode *node) {
5104 decrRefCount(node->obj);
5105 zfree(node->forward);
5106 zfree(node->span);
5107 zfree(node);
5108 }
5109
5110 static void zslFree(zskiplist *zsl) {
5111 zskiplistNode *node = zsl->header->forward[0], *next;
5112
5113 zfree(zsl->header->forward);
5114 zfree(zsl->header->span);
5115 zfree(zsl->header);
5116 while(node) {
5117 next = node->forward[0];
5118 zslFreeNode(node);
5119 node = next;
5120 }
5121 zfree(zsl);
5122 }
5123
5124 static int zslRandomLevel(void) {
5125 int level = 1;
5126 while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
5127 level += 1;
5128 return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
5129 }
5130
5131 static void zslInsert(zskiplist *zsl, double score, robj *obj) {
5132 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
5133 unsigned int rank[ZSKIPLIST_MAXLEVEL];
5134 int i, level;
5135
5136 x = zsl->header;
5137 for (i = zsl->level-1; i >= 0; i--) {
5138 /* store rank that is crossed to reach the insert position */
5139 rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
5140
5141 while (x->forward[i] &&
5142 (x->forward[i]->score < score ||
5143 (x->forward[i]->score == score &&
5144 compareStringObjects(x->forward[i]->obj,obj) < 0))) {
5145 rank[i] += i > 0 ? x->span[i-1] : 1;
5146 x = x->forward[i];
5147 }
5148 update[i] = x;
5149 }
5150 /* we assume the key is not already inside, since we allow duplicated
5151 * scores, and the re-insertion of score and redis object should never
5152 * happpen since the caller of zslInsert() should test in the hash table
5153 * if the element is already inside or not. */
5154 level = zslRandomLevel();
5155 if (level > zsl->level) {
5156 for (i = zsl->level; i < level; i++) {
5157 rank[i] = 0;
5158 update[i] = zsl->header;
5159 update[i]->span[i-1] = zsl->length;
5160 }
5161 zsl->level = level;
5162 }
5163 x = zslCreateNode(level,score,obj);
5164 for (i = 0; i < level; i++) {
5165 x->forward[i] = update[i]->forward[i];
5166 update[i]->forward[i] = x;
5167
5168 /* update span covered by update[i] as x is inserted here */
5169 if (i > 0) {
5170 x->span[i-1] = update[i]->span[i-1] - (rank[0] - rank[i]);
5171 update[i]->span[i-1] = (rank[0] - rank[i]) + 1;
5172 }
5173 }
5174
5175 /* increment span for untouched levels */
5176 for (i = level; i < zsl->level; i++) {
5177 update[i]->span[i-1]++;
5178 }
5179
5180 x->backward = (update[0] == zsl->header) ? NULL : update[0];
5181 if (x->forward[0])
5182 x->forward[0]->backward = x;
5183 else
5184 zsl->tail = x;
5185 zsl->length++;
5186 }
5187
5188 /* Internal function used by zslDelete, zslDeleteByScore and zslDeleteByRank */
5189 void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) {
5190 int i;
5191 for (i = 0; i < zsl->level; i++) {
5192 if (update[i]->forward[i] == x) {
5193 if (i > 0) {
5194 update[i]->span[i-1] += x->span[i-1] - 1;
5195 }
5196 update[i]->forward[i] = x->forward[i];
5197 } else {
5198 /* invariant: i > 0, because update[0]->forward[0]
5199 * is always equal to x */
5200 update[i]->span[i-1] -= 1;
5201 }
5202 }
5203 if (x->forward[0]) {
5204 x->forward[0]->backward = x->backward;
5205 } else {
5206 zsl->tail = x->backward;
5207 }
5208 while(zsl->level > 1 && zsl->header->forward[zsl->level-1] == NULL)
5209 zsl->level--;
5210 zsl->length--;
5211 }
5212
5213 /* Delete an element with matching score/object from the skiplist. */
5214 static int zslDelete(zskiplist *zsl, double score, robj *obj) {
5215 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
5216 int i;
5217
5218 x = zsl->header;
5219 for (i = zsl->level-1; i >= 0; i--) {
5220 while (x->forward[i] &&
5221 (x->forward[i]->score < score ||
5222 (x->forward[i]->score == score &&
5223 compareStringObjects(x->forward[i]->obj,obj) < 0)))
5224 x = x->forward[i];
5225 update[i] = x;
5226 }
5227 /* We may have multiple elements with the same score, what we need
5228 * is to find the element with both the right score and object. */
5229 x = x->forward[0];
5230 if (x && score == x->score && compareStringObjects(x->obj,obj) == 0) {
5231 zslDeleteNode(zsl, x, update);
5232 zslFreeNode(x);
5233 return 1;
5234 } else {
5235 return 0; /* not found */
5236 }
5237 return 0; /* not found */
5238 }
5239
5240 /* Delete all the elements with score between min and max from the skiplist.
5241 * Min and mx are inclusive, so a score >= min || score <= max is deleted.
5242 * Note that this function takes the reference to the hash table view of the
5243 * sorted set, in order to remove the elements from the hash table too. */
5244 static unsigned long zslDeleteRangeByScore(zskiplist *zsl, double min, double max, dict *dict) {
5245 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
5246 unsigned long removed = 0;
5247 int i;
5248
5249 x = zsl->header;
5250 for (i = zsl->level-1; i >= 0; i--) {
5251 while (x->forward[i] && x->forward[i]->score < min)
5252 x = x->forward[i];
5253 update[i] = x;
5254 }
5255 /* We may have multiple elements with the same score, what we need
5256 * is to find the element with both the right score and object. */
5257 x = x->forward[0];
5258 while (x && x->score <= max) {
5259 zskiplistNode *next = x->forward[0];
5260 zslDeleteNode(zsl, x, update);
5261 dictDelete(dict,x->obj);
5262 zslFreeNode(x);
5263 removed++;
5264 x = next;
5265 }
5266 return removed; /* not found */
5267 }
5268
5269 /* Delete all the elements with rank between start and end from the skiplist.
5270 * Start and end are inclusive. Note that start and end need to be 1-based */
5271 static unsigned long zslDeleteRangeByRank(zskiplist *zsl, unsigned int start, unsigned int end, dict *dict) {
5272 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
5273 unsigned long traversed = 0, removed = 0;
5274 int i;
5275
5276 x = zsl->header;
5277 for (i = zsl->level-1; i >= 0; i--) {
5278 while (x->forward[i] && (traversed + (i > 0 ? x->span[i-1] : 1)) < start) {
5279 traversed += i > 0 ? x->span[i-1] : 1;
5280 x = x->forward[i];
5281 }
5282 update[i] = x;
5283 }
5284
5285 traversed++;
5286 x = x->forward[0];
5287 while (x && traversed <= end) {
5288 zskiplistNode *next = x->forward[0];
5289 zslDeleteNode(zsl, x, update);
5290 dictDelete(dict,x->obj);
5291 zslFreeNode(x);
5292 removed++;
5293 traversed++;
5294 x = next;
5295 }
5296 return removed;
5297 }
5298
5299 /* Find the first node having a score equal or greater than the specified one.
5300 * Returns NULL if there is no match. */
5301 static zskiplistNode *zslFirstWithScore(zskiplist *zsl, double score) {
5302 zskiplistNode *x;
5303 int i;
5304
5305 x = zsl->header;
5306 for (i = zsl->level-1; i >= 0; i--) {
5307 while (x->forward[i] && x->forward[i]->score < score)
5308 x = x->forward[i];
5309 }
5310 /* We may have multiple elements with the same score, what we need
5311 * is to find the element with both the right score and object. */
5312 return x->forward[0];
5313 }
5314
5315 /* Find the rank for an element by both score and key.
5316 * Returns 0 when the element cannot be found, rank otherwise.
5317 * Note that the rank is 1-based due to the span of zsl->header to the
5318 * first element. */
5319 static unsigned long zslGetRank(zskiplist *zsl, double score, robj *o) {
5320 zskiplistNode *x;
5321 unsigned long rank = 0;
5322 int i;
5323
5324 x = zsl->header;
5325 for (i = zsl->level-1; i >= 0; i--) {
5326 while (x->forward[i] &&
5327 (x->forward[i]->score < score ||
5328 (x->forward[i]->score == score &&
5329 compareStringObjects(x->forward[i]->obj,o) <= 0))) {
5330 rank += i > 0 ? x->span[i-1] : 1;
5331 x = x->forward[i];
5332 }
5333
5334 /* x might be equal to zsl->header, so test if obj is non-NULL */
5335 if (x->obj && compareStringObjects(x->obj,o) == 0) {
5336 return rank;
5337 }
5338 }
5339 return 0;
5340 }
5341
5342 /* Finds an element by its rank. The rank argument needs to be 1-based. */
5343 zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsigned long rank) {
5344 zskiplistNode *x;
5345 unsigned long traversed = 0;
5346 int i;
5347
5348 x = zsl->header;
5349 for (i = zsl->level-1; i >= 0; i--) {
5350 while (x->forward[i] && (traversed + (i>0 ? x->span[i-1] : 1)) <= rank)
5351 {
5352 traversed += i > 0 ? x->span[i-1] : 1;
5353 x = x->forward[i];
5354 }
5355 if (traversed == rank) {
5356 return x;
5357 }
5358 }
5359 return NULL;
5360 }
5361
5362 /* The actual Z-commands implementations */
5363
5364 /* This generic command implements both ZADD and ZINCRBY.
5365 * scoreval is the score if the operation is a ZADD (doincrement == 0) or
5366 * the increment if the operation is a ZINCRBY (doincrement == 1). */
5367 static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, int doincrement) {
5368 robj *zsetobj;
5369 zset *zs;
5370 double *score;
5371
5372 zsetobj = lookupKeyWrite(c->db,key);
5373 if (zsetobj == NULL) {
5374 zsetobj = createZsetObject();
5375 dictAdd(c->db->dict,key,zsetobj);
5376 incrRefCount(key);
5377 } else {
5378 if (zsetobj->type != REDIS_ZSET) {
5379 addReply(c,shared.wrongtypeerr);
5380 return;
5381 }
5382 }
5383 zs = zsetobj->ptr;
5384
5385 /* Ok now since we implement both ZADD and ZINCRBY here the code
5386 * needs to handle the two different conditions. It's all about setting
5387 * '*score', that is, the new score to set, to the right value. */
5388 score = zmalloc(sizeof(double));
5389 if (doincrement) {
5390 dictEntry *de;
5391
5392 /* Read the old score. If the element was not present starts from 0 */
5393 de = dictFind(zs->dict,ele);
5394 if (de) {
5395 double *oldscore = dictGetEntryVal(de);
5396 *score = *oldscore + scoreval;
5397 } else {
5398 *score = scoreval;
5399 }
5400 } else {
5401 *score = scoreval;
5402 }
5403
5404 /* What follows is a simple remove and re-insert operation that is common
5405 * to both ZADD and ZINCRBY... */
5406 if (dictAdd(zs->dict,ele,score) == DICT_OK) {
5407 /* case 1: New element */
5408 incrRefCount(ele); /* added to hash */
5409 zslInsert(zs->zsl,*score,ele);
5410 incrRefCount(ele); /* added to skiplist */
5411 server.dirty++;
5412 if (doincrement)
5413 addReplyDouble(c,*score);
5414 else
5415 addReply(c,shared.cone);
5416 } else {
5417 dictEntry *de;
5418 double *oldscore;
5419
5420 /* case 2: Score update operation */
5421 de = dictFind(zs->dict,ele);
5422 redisAssert(de != NULL);
5423 oldscore = dictGetEntryVal(de);
5424 if (*score != *oldscore) {
5425 int deleted;
5426
5427 /* Remove and insert the element in the skip list with new score */
5428 deleted = zslDelete(zs->zsl,*oldscore,ele);
5429 redisAssert(deleted != 0);
5430 zslInsert(zs->zsl,*score,ele);
5431 incrRefCount(ele);
5432 /* Update the score in the hash table */
5433 dictReplace(zs->dict,ele,score);
5434 server.dirty++;
5435 } else {
5436 zfree(score);
5437 }
5438 if (doincrement)
5439 addReplyDouble(c,*score);
5440 else
5441 addReply(c,shared.czero);
5442 }
5443 }
5444
5445 static void zaddCommand(redisClient *c) {
5446 double scoreval;
5447
5448 scoreval = strtod(c->argv[2]->ptr,NULL);
5449 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,0);
5450 }
5451
5452 static void zincrbyCommand(redisClient *c) {
5453 double scoreval;
5454
5455 scoreval = strtod(c->argv[2]->ptr,NULL);
5456 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1);
5457 }
5458
5459 static void zremCommand(redisClient *c) {
5460 robj *zsetobj;
5461 zset *zs;
5462 dictEntry *de;
5463 double *oldscore;
5464 int deleted;
5465
5466 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
5467 checkType(c,zsetobj,REDIS_ZSET)) return;
5468
5469 zs = zsetobj->ptr;
5470 de = dictFind(zs->dict,c->argv[2]);
5471 if (de == NULL) {
5472 addReply(c,shared.czero);
5473 return;
5474 }
5475 /* Delete from the skiplist */
5476 oldscore = dictGetEntryVal(de);
5477 deleted = zslDelete(zs->zsl,*oldscore,c->argv[2]);
5478 redisAssert(deleted != 0);
5479
5480 /* Delete from the hash table */
5481 dictDelete(zs->dict,c->argv[2]);
5482 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
5483 if (dictSize(zs->dict) == 0) deleteKey(c->db,c->argv[1]);
5484 server.dirty++;
5485 addReply(c,shared.cone);
5486 }
5487
5488 static void zremrangebyscoreCommand(redisClient *c) {
5489 double min = strtod(c->argv[2]->ptr,NULL);
5490 double max = strtod(c->argv[3]->ptr,NULL);
5491 long deleted;
5492 robj *zsetobj;
5493 zset *zs;
5494
5495 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
5496 checkType(c,zsetobj,REDIS_ZSET)) return;
5497
5498 zs = zsetobj->ptr;
5499 deleted = zslDeleteRangeByScore(zs->zsl,min,max,zs->dict);
5500 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
5501 if (dictSize(zs->dict) == 0) deleteKey(c->db,c->argv[1]);
5502 server.dirty += deleted;
5503 addReplyLong(c,deleted);
5504 }
5505
5506 static void zremrangebyrankCommand(redisClient *c) {
5507 int start = atoi(c->argv[2]->ptr);
5508 int end = atoi(c->argv[3]->ptr);
5509 int llen;
5510 long deleted;
5511 robj *zsetobj;
5512 zset *zs;
5513
5514 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
5515 checkType(c,zsetobj,REDIS_ZSET)) return;
5516 zs = zsetobj->ptr;
5517 llen = zs->zsl->length;
5518
5519 /* convert negative indexes */
5520 if (start < 0) start = llen+start;
5521 if (end < 0) end = llen+end;
5522 if (start < 0) start = 0;
5523 if (end < 0) end = 0;
5524
5525 /* indexes sanity checks */
5526 if (start > end || start >= llen) {
5527 addReply(c,shared.czero);
5528 return;
5529 }
5530 if (end >= llen) end = llen-1;
5531
5532 /* increment start and end because zsl*Rank functions
5533 * use 1-based rank */
5534 deleted = zslDeleteRangeByRank(zs->zsl,start+1,end+1,zs->dict);
5535 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
5536 if (dictSize(zs->dict) == 0) deleteKey(c->db,c->argv[1]);
5537 server.dirty += deleted;
5538 addReplyLong(c, deleted);
5539 }
5540
5541 typedef struct {
5542 dict *dict;
5543 double weight;
5544 } zsetopsrc;
5545
5546 static int qsortCompareZsetopsrcByCardinality(const void *s1, const void *s2) {
5547 zsetopsrc *d1 = (void*) s1, *d2 = (void*) s2;
5548 unsigned long size1, size2;
5549 size1 = d1->dict ? dictSize(d1->dict) : 0;
5550 size2 = d2->dict ? dictSize(d2->dict) : 0;
5551 return size1 - size2;
5552 }
5553
5554 #define REDIS_AGGR_SUM 1
5555 #define REDIS_AGGR_MIN 2
5556 #define REDIS_AGGR_MAX 3
5557
5558 inline static void zunionInterAggregate(double *target, double val, int aggregate) {
5559 if (aggregate == REDIS_AGGR_SUM) {
5560 *target = *target + val;
5561 } else if (aggregate == REDIS_AGGR_MIN) {
5562 *target = val < *target ? val : *target;
5563 } else if (aggregate == REDIS_AGGR_MAX) {
5564 *target = val > *target ? val : *target;
5565 } else {
5566 /* safety net */
5567 redisAssert(0 != 0);
5568 }
5569 }
5570
5571 static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
5572 int i, j, zsetnum;
5573 int aggregate = REDIS_AGGR_SUM;
5574 zsetopsrc *src;
5575 robj *dstobj;
5576 zset *dstzset;
5577 dictIterator *di;
5578 dictEntry *de;
5579
5580 /* expect zsetnum input keys to be given */
5581 zsetnum = atoi(c->argv[2]->ptr);
5582 if (zsetnum < 1) {
5583 addReplySds(c,sdsnew("-ERR at least 1 input key is needed for ZUNION/ZINTER\r\n"));
5584 return;
5585 }
5586
5587 /* test if the expected number of keys would overflow */
5588 if (3+zsetnum > c->argc) {
5589 addReply(c,shared.syntaxerr);
5590 return;
5591 }
5592
5593 /* read keys to be used for input */
5594 src = zmalloc(sizeof(zsetopsrc) * zsetnum);
5595 for (i = 0, j = 3; i < zsetnum; i++, j++) {
5596 robj *zsetobj = lookupKeyWrite(c->db,c->argv[j]);
5597 if (!zsetobj) {
5598 src[i].dict = NULL;
5599 } else {
5600 if (zsetobj->type != REDIS_ZSET) {
5601 zfree(src);
5602 addReply(c,shared.wrongtypeerr);
5603 return;
5604 }
5605 src[i].dict = ((zset*)zsetobj->ptr)->dict;
5606 }
5607
5608 /* default all weights to 1 */
5609 src[i].weight = 1.0;
5610 }
5611
5612 /* parse optional extra arguments */
5613 if (j < c->argc) {
5614 int remaining = c->argc - j;
5615
5616 while (remaining) {
5617 if (remaining >= (zsetnum + 1) && !strcasecmp(c->argv[j]->ptr,"weights")) {
5618 j++; remaining--;
5619 for (i = 0; i < zsetnum; i++, j++, remaining--) {
5620 src[i].weight = strtod(c->argv[j]->ptr, NULL);
5621 }
5622 } else if (remaining >= 2 && !strcasecmp(c->argv[j]->ptr,"aggregate")) {
5623 j++; remaining--;
5624 if (!strcasecmp(c->argv[j]->ptr,"sum")) {
5625 aggregate = REDIS_AGGR_SUM;
5626 } else if (!strcasecmp(c->argv[j]->ptr,"min")) {
5627 aggregate = REDIS_AGGR_MIN;
5628 } else if (!strcasecmp(c->argv[j]->ptr,"max")) {
5629 aggregate = REDIS_AGGR_MAX;
5630 } else {
5631 zfree(src);
5632 addReply(c,shared.syntaxerr);
5633 return;
5634 }
5635 j++; remaining--;
5636 } else {
5637 zfree(src);
5638 addReply(c,shared.syntaxerr);
5639 return;
5640 }
5641 }
5642 }
5643
5644 /* sort sets from the smallest to largest, this will improve our
5645 * algorithm's performance */
5646 qsort(src,zsetnum,sizeof(zsetopsrc), qsortCompareZsetopsrcByCardinality);
5647
5648 dstobj = createZsetObject();
5649 dstzset = dstobj->ptr;
5650
5651 if (op == REDIS_OP_INTER) {
5652 /* skip going over all entries if the smallest zset is NULL or empty */
5653 if (src[0].dict && dictSize(src[0].dict) > 0) {
5654 /* precondition: as src[0].dict is non-empty and the zsets are ordered
5655 * from small to large, all src[i > 0].dict are non-empty too */
5656 di = dictGetIterator(src[0].dict);
5657 while((de = dictNext(di)) != NULL) {
5658 double *score = zmalloc(sizeof(double)), value;
5659 *score = src[0].weight * (*(double*)dictGetEntryVal(de));
5660
5661 for (j = 1; j < zsetnum; j++) {
5662 dictEntry *other = dictFind(src[j].dict,dictGetEntryKey(de));
5663 if (other) {
5664 value = src[j].weight * (*(double*)dictGetEntryVal(other));
5665 zunionInterAggregate(score, value, aggregate);
5666 } else {
5667 break;
5668 }
5669 }
5670
5671 /* skip entry when not present in every source dict */
5672 if (j != zsetnum) {
5673 zfree(score);
5674 } else {
5675 robj *o = dictGetEntryKey(de);
5676 dictAdd(dstzset->dict,o,score);
5677 incrRefCount(o); /* added to dictionary */
5678 zslInsert(dstzset->zsl,*score,o);
5679 incrRefCount(o); /* added to skiplist */
5680 }
5681 }
5682 dictReleaseIterator(di);
5683 }
5684 } else if (op == REDIS_OP_UNION) {
5685 for (i = 0; i < zsetnum; i++) {
5686 if (!src[i].dict) continue;
5687
5688 di = dictGetIterator(src[i].dict);
5689 while((de = dictNext(di)) != NULL) {
5690 /* skip key when already processed */
5691 if (dictFind(dstzset->dict,dictGetEntryKey(de)) != NULL) continue;
5692
5693 double *score = zmalloc(sizeof(double)), value;
5694 *score = src[i].weight * (*(double*)dictGetEntryVal(de));
5695
5696 /* because the zsets are sorted by size, its only possible
5697 * for sets at larger indices to hold this entry */
5698 for (j = (i+1); j < zsetnum; j++) {
5699 dictEntry *other = dictFind(src[j].dict,dictGetEntryKey(de));
5700 if (other) {
5701 value = src[j].weight * (*(double*)dictGetEntryVal(other));
5702 zunionInterAggregate(score, value, aggregate);
5703 }
5704 }
5705
5706 robj *o = dictGetEntryKey(de);
5707 dictAdd(dstzset->dict,o,score);
5708 incrRefCount(o); /* added to dictionary */
5709 zslInsert(dstzset->zsl,*score,o);
5710 incrRefCount(o); /* added to skiplist */
5711 }
5712 dictReleaseIterator(di);
5713 }
5714 } else {
5715 /* unknown operator */
5716 redisAssert(op == REDIS_OP_INTER || op == REDIS_OP_UNION);
5717 }
5718
5719 deleteKey(c->db,dstkey);
5720 if (dstzset->zsl->length) {
5721 dictAdd(c->db->dict,dstkey,dstobj);
5722 incrRefCount(dstkey);
5723 addReplyLong(c, dstzset->zsl->length);
5724 server.dirty++;
5725 } else {
5726 decrRefCount(dstobj);
5727 addReply(c, shared.czero);
5728 }
5729 zfree(src);
5730 }
5731
5732 static void zunionCommand(redisClient *c) {
5733 zunionInterGenericCommand(c,c->argv[1], REDIS_OP_UNION);
5734 }
5735
5736 static void zinterCommand(redisClient *c) {
5737 zunionInterGenericCommand(c,c->argv[1], REDIS_OP_INTER);
5738 }
5739
5740 static void zrangeGenericCommand(redisClient *c, int reverse) {
5741 robj *o;
5742 int start = atoi(c->argv[2]->ptr);
5743 int end = atoi(c->argv[3]->ptr);
5744 int withscores = 0;
5745 int llen;
5746 int rangelen, j;
5747 zset *zsetobj;
5748 zskiplist *zsl;
5749 zskiplistNode *ln;
5750 robj *ele;
5751
5752 if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) {
5753 withscores = 1;
5754 } else if (c->argc >= 5) {
5755 addReply(c,shared.syntaxerr);
5756 return;
5757 }
5758
5759 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullmultibulk)) == NULL ||
5760 checkType(c,o,REDIS_ZSET)) return;
5761 zsetobj = o->ptr;
5762 zsl = zsetobj->zsl;
5763 llen = zsl->length;
5764
5765 /* convert negative indexes */
5766 if (start < 0) start = llen+start;
5767 if (end < 0) end = llen+end;
5768 if (start < 0) start = 0;
5769 if (end < 0) end = 0;
5770
5771 /* indexes sanity checks */
5772 if (start > end || start >= llen) {
5773 /* Out of range start or start > end result in empty list */
5774 addReply(c,shared.emptymultibulk);
5775 return;
5776 }
5777 if (end >= llen) end = llen-1;
5778 rangelen = (end-start)+1;
5779
5780 /* check if starting point is trivial, before searching
5781 * the element in log(N) time */
5782 if (reverse) {
5783 ln = start == 0 ? zsl->tail : zslGetElementByRank(zsl, llen-start);
5784 } else {
5785 ln = start == 0 ?
5786 zsl->header->forward[0] : zslGetElementByRank(zsl, start+1);
5787 }
5788
5789 /* Return the result in form of a multi-bulk reply */
5790 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",
5791 withscores ? (rangelen*2) : rangelen));
5792 for (j = 0; j < rangelen; j++) {
5793 ele = ln->obj;
5794 addReplyBulk(c,ele);
5795 if (withscores)
5796 addReplyDouble(c,ln->score);
5797 ln = reverse ? ln->backward : ln->forward[0];
5798 }
5799 }
5800
5801 static void zrangeCommand(redisClient *c) {
5802 zrangeGenericCommand(c,0);
5803 }
5804
5805 static void zrevrangeCommand(redisClient *c) {
5806 zrangeGenericCommand(c,1);
5807 }
5808
5809 /* This command implements both ZRANGEBYSCORE and ZCOUNT.
5810 * If justcount is non-zero, just the count is returned. */
5811 static void genericZrangebyscoreCommand(redisClient *c, int justcount) {
5812 robj *o;
5813 double min, max;
5814 int minex = 0, maxex = 0; /* are min or max exclusive? */
5815 int offset = 0, limit = -1;
5816 int withscores = 0;
5817 int badsyntax = 0;
5818
5819 /* Parse the min-max interval. If one of the values is prefixed
5820 * by the "(" character, it's considered "open". For instance
5821 * ZRANGEBYSCORE zset (1.5 (2.5 will match min < x < max
5822 * ZRANGEBYSCORE zset 1.5 2.5 will instead match min <= x <= max */
5823 if (((char*)c->argv[2]->ptr)[0] == '(') {
5824 min = strtod((char*)c->argv[2]->ptr+1,NULL);
5825 minex = 1;
5826 } else {
5827 min = strtod(c->argv[2]->ptr,NULL);
5828 }
5829 if (((char*)c->argv[3]->ptr)[0] == '(') {
5830 max = strtod((char*)c->argv[3]->ptr+1,NULL);
5831 maxex = 1;
5832 } else {
5833 max = strtod(c->argv[3]->ptr,NULL);
5834 }
5835
5836 /* Parse "WITHSCORES": note that if the command was called with
5837 * the name ZCOUNT then we are sure that c->argc == 4, so we'll never
5838 * enter the following paths to parse WITHSCORES and LIMIT. */
5839 if (c->argc == 5 || c->argc == 8) {
5840 if (strcasecmp(c->argv[c->argc-1]->ptr,"withscores") == 0)
5841 withscores = 1;
5842 else
5843 badsyntax = 1;
5844 }
5845 if (c->argc != (4 + withscores) && c->argc != (7 + withscores))
5846 badsyntax = 1;
5847 if (badsyntax) {
5848 addReplySds(c,
5849 sdsnew("-ERR wrong number of arguments for ZRANGEBYSCORE\r\n"));
5850 return;
5851 }
5852
5853 /* Parse "LIMIT" */
5854 if (c->argc == (7 + withscores) && strcasecmp(c->argv[4]->ptr,"limit")) {
5855 addReply(c,shared.syntaxerr);
5856 return;
5857 } else if (c->argc == (7 + withscores)) {
5858 offset = atoi(c->argv[5]->ptr);
5859 limit = atoi(c->argv[6]->ptr);
5860 if (offset < 0) offset = 0;
5861 }
5862
5863 /* Ok, lookup the key and get the range */
5864 o = lookupKeyRead(c->db,c->argv[1]);
5865 if (o == NULL) {
5866 addReply(c,justcount ? shared.czero : shared.nullmultibulk);
5867 } else {
5868 if (o->type != REDIS_ZSET) {
5869 addReply(c,shared.wrongtypeerr);
5870 } else {
5871 zset *zsetobj = o->ptr;
5872 zskiplist *zsl = zsetobj->zsl;
5873 zskiplistNode *ln;
5874 robj *ele, *lenobj = NULL;
5875 unsigned long rangelen = 0;
5876
5877 /* Get the first node with the score >= min, or with
5878 * score > min if 'minex' is true. */
5879 ln = zslFirstWithScore(zsl,min);
5880 while (minex && ln && ln->score == min) ln = ln->forward[0];
5881
5882 if (ln == NULL) {
5883 /* No element matching the speciifed interval */
5884 addReply(c,justcount ? shared.czero : shared.emptymultibulk);
5885 return;
5886 }
5887
5888 /* We don't know in advance how many matching elements there
5889 * are in the list, so we push this object that will represent
5890 * the multi-bulk length in the output buffer, and will "fix"
5891 * it later */
5892 if (!justcount) {
5893 lenobj = createObject(REDIS_STRING,NULL);
5894 addReply(c,lenobj);
5895 decrRefCount(lenobj);
5896 }
5897
5898 while(ln && (maxex ? (ln->score < max) : (ln->score <= max))) {
5899 if (offset) {
5900 offset--;
5901 ln = ln->forward[0];
5902 continue;
5903 }
5904 if (limit == 0) break;
5905 if (!justcount) {
5906 ele = ln->obj;
5907 addReplyBulk(c,ele);
5908 if (withscores)
5909 addReplyDouble(c,ln->score);
5910 }
5911 ln = ln->forward[0];
5912 rangelen++;
5913 if (limit > 0) limit--;
5914 }
5915 if (justcount) {
5916 addReplyLong(c,(long)rangelen);
5917 } else {
5918 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",
5919 withscores ? (rangelen*2) : rangelen);
5920 }
5921 }
5922 }
5923 }
5924
5925 static void zrangebyscoreCommand(redisClient *c) {
5926 genericZrangebyscoreCommand(c,0);
5927 }
5928
5929 static void zcountCommand(redisClient *c) {
5930 genericZrangebyscoreCommand(c,1);
5931 }
5932
5933 static void zcardCommand(redisClient *c) {
5934 robj *o;
5935 zset *zs;
5936
5937 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
5938 checkType(c,o,REDIS_ZSET)) return;
5939
5940 zs = o->ptr;
5941 addReplyUlong(c,zs->zsl->length);
5942 }
5943
5944 static void zscoreCommand(redisClient *c) {
5945 robj *o;
5946 zset *zs;
5947 dictEntry *de;
5948
5949 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
5950 checkType(c,o,REDIS_ZSET)) return;
5951
5952 zs = o->ptr;
5953 de = dictFind(zs->dict,c->argv[2]);
5954 if (!de) {
5955 addReply(c,shared.nullbulk);
5956 } else {
5957 double *score = dictGetEntryVal(de);
5958
5959 addReplyDouble(c,*score);
5960 }
5961 }
5962
5963 static void zrankGenericCommand(redisClient *c, int reverse) {
5964 robj *o;
5965 zset *zs;
5966 zskiplist *zsl;
5967 dictEntry *de;
5968 unsigned long rank;
5969 double *score;
5970
5971 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
5972 checkType(c,o,REDIS_ZSET)) return;
5973
5974 zs = o->ptr;
5975 zsl = zs->zsl;
5976 de = dictFind(zs->dict,c->argv[2]);
5977 if (!de) {
5978 addReply(c,shared.nullbulk);
5979 return;
5980 }
5981
5982 score = dictGetEntryVal(de);
5983 rank = zslGetRank(zsl, *score, c->argv[2]);
5984 if (rank) {
5985 if (reverse) {
5986 addReplyLong(c, zsl->length - rank);
5987 } else {
5988 addReplyLong(c, rank-1);
5989 }
5990 } else {
5991 addReply(c,shared.nullbulk);
5992 }
5993 }
5994
5995 static void zrankCommand(redisClient *c) {
5996 zrankGenericCommand(c, 0);
5997 }
5998
5999 static void zrevrankCommand(redisClient *c) {
6000 zrankGenericCommand(c, 1);
6001 }
6002
6003 /* =================================== Hashes =============================== */
6004 static void hsetCommand(redisClient *c) {
6005 int update = 0;
6006 robj *o = lookupKeyWrite(c->db,c->argv[1]);
6007
6008 if (o == NULL) {
6009 o = createHashObject();
6010 dictAdd(c->db->dict,c->argv[1],o);
6011 incrRefCount(c->argv[1]);
6012 } else {
6013 if (o->type != REDIS_HASH) {
6014 addReply(c,shared.wrongtypeerr);
6015 return;
6016 }
6017 }
6018 /* We want to convert the zipmap into an hash table right now if the
6019 * entry to be added is too big. Note that we check if the object
6020 * is integer encoded before to try fetching the length in the test below.
6021 * This is because integers are small, but currently stringObjectLen()
6022 * performs a slow conversion: not worth it. */
6023 if (o->encoding == REDIS_ENCODING_ZIPMAP &&
6024 ((c->argv[2]->encoding == REDIS_ENCODING_RAW &&
6025 sdslen(c->argv[2]->ptr) > server.hash_max_zipmap_value) ||
6026 (c->argv[3]->encoding == REDIS_ENCODING_RAW &&
6027 sdslen(c->argv[3]->ptr) > server.hash_max_zipmap_value)))
6028 {
6029 convertToRealHash(o);
6030 }
6031
6032 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
6033 unsigned char *zm = o->ptr;
6034 robj *valobj = getDecodedObject(c->argv[3]);
6035
6036 zm = zipmapSet(zm,c->argv[2]->ptr,sdslen(c->argv[2]->ptr),
6037 valobj->ptr,sdslen(valobj->ptr),&update);
6038 decrRefCount(valobj);
6039 o->ptr = zm;
6040
6041 /* And here there is the second check for hash conversion. */
6042 if (zipmapLen(zm) > server.hash_max_zipmap_entries)
6043 convertToRealHash(o);
6044 } else {
6045 tryObjectEncoding(c->argv[2]);
6046 /* note that c->argv[3] is already encoded, as the latest arg
6047 * of a bulk command is always integer encoded if possible. */
6048 if (dictReplace(o->ptr,c->argv[2],c->argv[3])) {
6049 incrRefCount(c->argv[2]);
6050 } else {
6051 update = 1;
6052 }
6053 incrRefCount(c->argv[3]);
6054 }
6055 server.dirty++;
6056 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",update == 0));
6057 }
6058
6059 static void hincrbyCommand(redisClient *c) {
6060 long long value = 0, incr = 0;
6061 robj *o = lookupKeyWrite(c->db,c->argv[1]);
6062
6063 if (o == NULL) {
6064 o = createHashObject();
6065 dictAdd(c->db->dict,c->argv[1],o);
6066 incrRefCount(c->argv[1]);
6067 } else {
6068 if (o->type != REDIS_HASH) {
6069 addReply(c,shared.wrongtypeerr);
6070 return;
6071 }
6072 }
6073
6074 incr = strtoll(c->argv[3]->ptr, NULL, 10);
6075 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
6076 unsigned char *zm = o->ptr;
6077 unsigned char *zval;
6078 unsigned int zvlen;
6079
6080 /* Find value if already present in hash */
6081 if (zipmapGet(zm,c->argv[2]->ptr,sdslen(c->argv[2]->ptr),
6082 &zval,&zvlen)) {
6083 /* strtoll needs the char* to have a trailing \0, but
6084 * the zipmap doesn't include them. */
6085 sds szval = sdsnewlen(zval, zvlen);
6086 value = strtoll(szval,NULL,10);
6087 sdsfree(szval);
6088 }
6089
6090 value += incr;
6091 sds svalue = sdscatprintf(sdsempty(),"%lld",value);
6092 zm = zipmapSet(zm,c->argv[2]->ptr,sdslen(c->argv[2]->ptr),
6093 (unsigned char*)svalue,sdslen(svalue),NULL);
6094 sdsfree(svalue);
6095 o->ptr = zm;
6096
6097 /* Check if the zipmap needs to be converted. */
6098 if (zipmapLen(zm) > server.hash_max_zipmap_entries)
6099 convertToRealHash(o);
6100 } else {
6101 robj *hval;
6102 dictEntry *de;
6103
6104 /* Find value if already present in hash */
6105 de = dictFind(o->ptr,c->argv[2]);
6106 if (de != NULL) {
6107 hval = dictGetEntryVal(de);
6108 if (hval->encoding == REDIS_ENCODING_RAW)
6109 value = strtoll(hval->ptr,NULL,10);
6110 else if (hval->encoding == REDIS_ENCODING_INT)
6111 value = (long)hval->ptr;
6112 else
6113 redisAssert(1 != 1);
6114 }
6115
6116 value += incr;
6117 hval = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
6118 tryObjectEncoding(hval);
6119 if (dictReplace(o->ptr,c->argv[2],hval)) {
6120 incrRefCount(c->argv[2]);
6121 }
6122 }
6123
6124 server.dirty++;
6125 addReplyLongLong(c, value);
6126 }
6127
6128 static void hgetCommand(redisClient *c) {
6129 robj *o;
6130
6131 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
6132 checkType(c,o,REDIS_HASH)) return;
6133
6134 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
6135 unsigned char *zm = o->ptr;
6136 unsigned char *val;
6137 unsigned int vlen;
6138 robj *field;
6139
6140 field = getDecodedObject(c->argv[2]);
6141 if (zipmapGet(zm,field->ptr,sdslen(field->ptr), &val,&vlen)) {
6142 addReplySds(c,sdscatprintf(sdsempty(),"$%u\r\n", vlen));
6143 addReplySds(c,sdsnewlen(val,vlen));
6144 addReply(c,shared.crlf);
6145 decrRefCount(field);
6146 return;
6147 } else {
6148 addReply(c,shared.nullbulk);
6149 decrRefCount(field);
6150 return;
6151 }
6152 } else {
6153 struct dictEntry *de;
6154
6155 de = dictFind(o->ptr,c->argv[2]);
6156 if (de == NULL) {
6157 addReply(c,shared.nullbulk);
6158 } else {
6159 robj *e = dictGetEntryVal(de);
6160
6161 addReplyBulk(c,e);
6162 }
6163 }
6164 }
6165
6166 static void hdelCommand(redisClient *c) {
6167 robj *o;
6168 int deleted = 0;
6169
6170 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
6171 checkType(c,o,REDIS_HASH)) return;
6172
6173 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
6174 robj *field = getDecodedObject(c->argv[2]);
6175
6176 o->ptr = zipmapDel((unsigned char*) o->ptr,
6177 (unsigned char*) field->ptr,
6178 sdslen(field->ptr), &deleted);
6179 decrRefCount(field);
6180 if (zipmapLen((unsigned char*) o->ptr) == 0)
6181 deleteKey(c->db,c->argv[1]);
6182 } else {
6183 deleted = dictDelete((dict*)o->ptr,c->argv[2]) == DICT_OK;
6184 if (htNeedsResize(o->ptr)) dictResize(o->ptr);
6185 if (dictSize((dict*)o->ptr) == 0) deleteKey(c->db,c->argv[1]);
6186 }
6187 if (deleted) server.dirty++;
6188 addReply(c,deleted ? shared.cone : shared.czero);
6189 }
6190
6191 static void hlenCommand(redisClient *c) {
6192 robj *o;
6193 unsigned long len;
6194
6195 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
6196 checkType(c,o,REDIS_HASH)) return;
6197
6198 len = (o->encoding == REDIS_ENCODING_ZIPMAP) ?
6199 zipmapLen((unsigned char*)o->ptr) : dictSize((dict*)o->ptr);
6200 addReplyUlong(c,len);
6201 }
6202
6203 #define REDIS_GETALL_KEYS 1
6204 #define REDIS_GETALL_VALS 2
6205 static void genericHgetallCommand(redisClient *c, int flags) {
6206 robj *o, *lenobj;
6207 unsigned long count = 0;
6208
6209 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullmultibulk)) == NULL
6210 || checkType(c,o,REDIS_HASH)) return;
6211
6212 lenobj = createObject(REDIS_STRING,NULL);
6213 addReply(c,lenobj);
6214 decrRefCount(lenobj);
6215
6216 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
6217 unsigned char *p = zipmapRewind(o->ptr);
6218 unsigned char *field, *val;
6219 unsigned int flen, vlen;
6220
6221 while((p = zipmapNext(p,&field,&flen,&val,&vlen)) != NULL) {
6222 robj *aux;
6223
6224 if (flags & REDIS_GETALL_KEYS) {
6225 aux = createStringObject((char*)field,flen);
6226 addReplyBulk(c,aux);
6227 decrRefCount(aux);
6228 count++;
6229 }
6230 if (flags & REDIS_GETALL_VALS) {
6231 aux = createStringObject((char*)val,vlen);
6232 addReplyBulk(c,aux);
6233 decrRefCount(aux);
6234 count++;
6235 }
6236 }
6237 } else {
6238 dictIterator *di = dictGetIterator(o->ptr);
6239 dictEntry *de;
6240
6241 while((de = dictNext(di)) != NULL) {
6242 robj *fieldobj = dictGetEntryKey(de);
6243 robj *valobj = dictGetEntryVal(de);
6244
6245 if (flags & REDIS_GETALL_KEYS) {
6246 addReplyBulk(c,fieldobj);
6247 count++;
6248 }
6249 if (flags & REDIS_GETALL_VALS) {
6250 addReplyBulk(c,valobj);
6251 count++;
6252 }
6253 }
6254 dictReleaseIterator(di);
6255 }
6256 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",count);
6257 }
6258
6259 static void hkeysCommand(redisClient *c) {
6260 genericHgetallCommand(c,REDIS_GETALL_KEYS);
6261 }
6262
6263 static void hvalsCommand(redisClient *c) {
6264 genericHgetallCommand(c,REDIS_GETALL_VALS);
6265 }
6266
6267 static void hgetallCommand(redisClient *c) {
6268 genericHgetallCommand(c,REDIS_GETALL_KEYS|REDIS_GETALL_VALS);
6269 }
6270
6271 static void hexistsCommand(redisClient *c) {
6272 robj *o;
6273 int exists = 0;
6274
6275 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
6276 checkType(c,o,REDIS_HASH)) return;
6277
6278 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
6279 robj *field;
6280 unsigned char *zm = o->ptr;
6281
6282 field = getDecodedObject(c->argv[2]);
6283 exists = zipmapExists(zm,field->ptr,sdslen(field->ptr));
6284 decrRefCount(field);
6285 } else {
6286 exists = dictFind(o->ptr,c->argv[2]) != NULL;
6287 }
6288 addReply(c,exists ? shared.cone : shared.czero);
6289 }
6290
6291 static void convertToRealHash(robj *o) {
6292 unsigned char *key, *val, *p, *zm = o->ptr;
6293 unsigned int klen, vlen;
6294 dict *dict = dictCreate(&hashDictType,NULL);
6295
6296 assert(o->type == REDIS_HASH && o->encoding != REDIS_ENCODING_HT);
6297 p = zipmapRewind(zm);
6298 while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
6299 robj *keyobj, *valobj;
6300
6301 keyobj = createStringObject((char*)key,klen);
6302 valobj = createStringObject((char*)val,vlen);
6303 tryObjectEncoding(keyobj);
6304 tryObjectEncoding(valobj);
6305 dictAdd(dict,keyobj,valobj);
6306 }
6307 o->encoding = REDIS_ENCODING_HT;
6308 o->ptr = dict;
6309 zfree(zm);
6310 }
6311
6312 /* ========================= Non type-specific commands ==================== */
6313
6314 static void flushdbCommand(redisClient *c) {
6315 server.dirty += dictSize(c->db->dict);
6316 dictEmpty(c->db->dict);
6317 dictEmpty(c->db->expires);
6318 addReply(c,shared.ok);
6319 }
6320
6321 static void flushallCommand(redisClient *c) {
6322 server.dirty += emptyDb();
6323 addReply(c,shared.ok);
6324 if (server.bgsavechildpid != -1) {
6325 kill(server.bgsavechildpid,SIGKILL);
6326 rdbRemoveTempFile(server.bgsavechildpid);
6327 }
6328 rdbSave(server.dbfilename);
6329 server.dirty++;
6330 }
6331
6332 static redisSortOperation *createSortOperation(int type, robj *pattern) {
6333 redisSortOperation *so = zmalloc(sizeof(*so));
6334 so->type = type;
6335 so->pattern = pattern;
6336 return so;
6337 }
6338
6339 /* Return the value associated to the key with a name obtained
6340 * substituting the first occurence of '*' in 'pattern' with 'subst' */
6341 static robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
6342 char *p;
6343 sds spat, ssub;
6344 robj keyobj;
6345 int prefixlen, sublen, postfixlen;
6346 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
6347 struct {
6348 long len;
6349 long free;
6350 char buf[REDIS_SORTKEY_MAX+1];
6351 } keyname;
6352
6353 /* If the pattern is "#" return the substitution object itself in order
6354 * to implement the "SORT ... GET #" feature. */
6355 spat = pattern->ptr;
6356 if (spat[0] == '#' && spat[1] == '\0') {
6357 return subst;
6358 }
6359
6360 /* The substitution object may be specially encoded. If so we create
6361 * a decoded object on the fly. Otherwise getDecodedObject will just
6362 * increment the ref count, that we'll decrement later. */
6363 subst = getDecodedObject(subst);
6364
6365 ssub = subst->ptr;
6366 if (sdslen(spat)+sdslen(ssub)-1 > REDIS_SORTKEY_MAX) return NULL;
6367 p = strchr(spat,'*');
6368 if (!p) {
6369 decrRefCount(subst);
6370 return NULL;
6371 }
6372
6373 prefixlen = p-spat;
6374 sublen = sdslen(ssub);
6375 postfixlen = sdslen(spat)-(prefixlen+1);
6376 memcpy(keyname.buf,spat,prefixlen);
6377 memcpy(keyname.buf+prefixlen,ssub,sublen);
6378 memcpy(keyname.buf+prefixlen+sublen,p+1,postfixlen);
6379 keyname.buf[prefixlen+sublen+postfixlen] = '\0';
6380 keyname.len = prefixlen+sublen+postfixlen;
6381
6382 initStaticStringObject(keyobj,((char*)&keyname)+(sizeof(long)*2))
6383 decrRefCount(subst);
6384
6385 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
6386 return lookupKeyRead(db,&keyobj);
6387 }
6388
6389 /* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
6390 * the additional parameter is not standard but a BSD-specific we have to
6391 * pass sorting parameters via the global 'server' structure */
6392 static int sortCompare(const void *s1, const void *s2) {
6393 const redisSortObject *so1 = s1, *so2 = s2;
6394 int cmp;
6395
6396 if (!server.sort_alpha) {
6397 /* Numeric sorting. Here it's trivial as we precomputed scores */
6398 if (so1->u.score > so2->u.score) {
6399 cmp = 1;
6400 } else if (so1->u.score < so2->u.score) {
6401 cmp = -1;
6402 } else {
6403 cmp = 0;
6404 }
6405 } else {
6406 /* Alphanumeric sorting */
6407 if (server.sort_bypattern) {
6408 if (!so1->u.cmpobj || !so2->u.cmpobj) {
6409 /* At least one compare object is NULL */
6410 if (so1->u.cmpobj == so2->u.cmpobj)
6411 cmp = 0;
6412 else if (so1->u.cmpobj == NULL)
6413 cmp = -1;
6414 else
6415 cmp = 1;
6416 } else {
6417 /* We have both the objects, use strcoll */
6418 cmp = strcoll(so1->u.cmpobj->ptr,so2->u.cmpobj->ptr);
6419 }
6420 } else {
6421 /* Compare elements directly */
6422 robj *dec1, *dec2;
6423
6424 dec1 = getDecodedObject(so1->obj);
6425 dec2 = getDecodedObject(so2->obj);
6426 cmp = strcoll(dec1->ptr,dec2->ptr);
6427 decrRefCount(dec1);
6428 decrRefCount(dec2);
6429 }
6430 }
6431 return server.sort_desc ? -cmp : cmp;
6432 }
6433
6434 /* The SORT command is the most complex command in Redis. Warning: this code
6435 * is optimized for speed and a bit less for readability */
6436 static void sortCommand(redisClient *c) {
6437 list *operations;
6438 int outputlen = 0;
6439 int desc = 0, alpha = 0;
6440 int limit_start = 0, limit_count = -1, start, end;
6441 int j, dontsort = 0, vectorlen;
6442 int getop = 0; /* GET operation counter */
6443 robj *sortval, *sortby = NULL, *storekey = NULL;
6444 redisSortObject *vector; /* Resulting vector to sort */
6445
6446 /* Lookup the key to sort. It must be of the right types */
6447 sortval = lookupKeyRead(c->db,c->argv[1]);
6448 if (sortval == NULL) {
6449 addReply(c,shared.nullmultibulk);
6450 return;
6451 }
6452 if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST &&
6453 sortval->type != REDIS_ZSET)
6454 {
6455 addReply(c,shared.wrongtypeerr);
6456 return;
6457 }
6458
6459 /* Create a list of operations to perform for every sorted element.
6460 * Operations can be GET/DEL/INCR/DECR */
6461 operations = listCreate();
6462 listSetFreeMethod(operations,zfree);
6463 j = 2;
6464
6465 /* Now we need to protect sortval incrementing its count, in the future
6466 * SORT may have options able to overwrite/delete keys during the sorting
6467 * and the sorted key itself may get destroied */
6468 incrRefCount(sortval);
6469
6470 /* The SORT command has an SQL-alike syntax, parse it */
6471 while(j < c->argc) {
6472 int leftargs = c->argc-j-1;
6473 if (!strcasecmp(c->argv[j]->ptr,"asc")) {
6474 desc = 0;
6475 } else if (!strcasecmp(c->argv[j]->ptr,"desc")) {
6476 desc = 1;
6477 } else if (!strcasecmp(c->argv[j]->ptr,"alpha")) {
6478 alpha = 1;
6479 } else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) {
6480 limit_start = atoi(c->argv[j+1]->ptr);
6481 limit_count = atoi(c->argv[j+2]->ptr);
6482 j+=2;
6483 } else if (!strcasecmp(c->argv[j]->ptr,"store") && leftargs >= 1) {
6484 storekey = c->argv[j+1];
6485 j++;
6486 } else if (!strcasecmp(c->argv[j]->ptr,"by") && leftargs >= 1) {
6487 sortby = c->argv[j+1];
6488 /* If the BY pattern does not contain '*', i.e. it is constant,
6489 * we don't need to sort nor to lookup the weight keys. */
6490 if (strchr(c->argv[j+1]->ptr,'*') == NULL) dontsort = 1;
6491 j++;
6492 } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
6493 listAddNodeTail(operations,createSortOperation(
6494 REDIS_SORT_GET,c->argv[j+1]));
6495 getop++;
6496 j++;
6497 } else {
6498 decrRefCount(sortval);
6499 listRelease(operations);
6500 addReply(c,shared.syntaxerr);
6501 return;
6502 }
6503 j++;
6504 }
6505
6506 /* Load the sorting vector with all the objects to sort */
6507 switch(sortval->type) {
6508 case REDIS_LIST: vectorlen = listLength((list*)sortval->ptr); break;
6509 case REDIS_SET: vectorlen = dictSize((dict*)sortval->ptr); break;
6510 case REDIS_ZSET: vectorlen = dictSize(((zset*)sortval->ptr)->dict); break;
6511 default: vectorlen = 0; redisAssert(0); /* Avoid GCC warning */
6512 }
6513 vector = zmalloc(sizeof(redisSortObject)*vectorlen);
6514 j = 0;
6515
6516 if (sortval->type == REDIS_LIST) {
6517 list *list = sortval->ptr;
6518 listNode *ln;
6519 listIter li;
6520
6521 listRewind(list,&li);
6522 while((ln = listNext(&li))) {
6523 robj *ele = ln->value;
6524 vector[j].obj = ele;
6525 vector[j].u.score = 0;
6526 vector[j].u.cmpobj = NULL;
6527 j++;
6528 }
6529 } else {
6530 dict *set;
6531 dictIterator *di;
6532 dictEntry *setele;
6533
6534 if (sortval->type == REDIS_SET) {
6535 set = sortval->ptr;
6536 } else {
6537 zset *zs = sortval->ptr;
6538 set = zs->dict;
6539 }
6540
6541 di = dictGetIterator(set);
6542 while((setele = dictNext(di)) != NULL) {
6543 vector[j].obj = dictGetEntryKey(setele);
6544 vector[j].u.score = 0;
6545 vector[j].u.cmpobj = NULL;
6546 j++;
6547 }
6548 dictReleaseIterator(di);
6549 }
6550 redisAssert(j == vectorlen);
6551
6552 /* Now it's time to load the right scores in the sorting vector */
6553 if (dontsort == 0) {
6554 for (j = 0; j < vectorlen; j++) {
6555 if (sortby) {
6556 robj *byval;
6557
6558 byval = lookupKeyByPattern(c->db,sortby,vector[j].obj);
6559 if (!byval || byval->type != REDIS_STRING) continue;
6560 if (alpha) {
6561 vector[j].u.cmpobj = getDecodedObject(byval);
6562 } else {
6563 if (byval->encoding == REDIS_ENCODING_RAW) {
6564 vector[j].u.score = strtod(byval->ptr,NULL);
6565 } else {
6566 /* Don't need to decode the object if it's
6567 * integer-encoded (the only encoding supported) so
6568 * far. We can just cast it */
6569 if (byval->encoding == REDIS_ENCODING_INT) {
6570 vector[j].u.score = (long)byval->ptr;
6571 } else
6572 redisAssert(1 != 1);
6573 }
6574 }
6575 } else {
6576 if (!alpha) {
6577 if (vector[j].obj->encoding == REDIS_ENCODING_RAW)
6578 vector[j].u.score = strtod(vector[j].obj->ptr,NULL);
6579 else {
6580 if (vector[j].obj->encoding == REDIS_ENCODING_INT)
6581 vector[j].u.score = (long) vector[j].obj->ptr;
6582 else
6583 redisAssert(1 != 1);
6584 }
6585 }
6586 }
6587 }
6588 }
6589
6590 /* We are ready to sort the vector... perform a bit of sanity check
6591 * on the LIMIT option too. We'll use a partial version of quicksort. */
6592 start = (limit_start < 0) ? 0 : limit_start;
6593 end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1;
6594 if (start >= vectorlen) {
6595 start = vectorlen-1;
6596 end = vectorlen-2;
6597 }
6598 if (end >= vectorlen) end = vectorlen-1;
6599
6600 if (dontsort == 0) {
6601 server.sort_desc = desc;
6602 server.sort_alpha = alpha;
6603 server.sort_bypattern = sortby ? 1 : 0;
6604 if (sortby && (start != 0 || end != vectorlen-1))
6605 pqsort(vector,vectorlen,sizeof(redisSortObject),sortCompare, start,end);
6606 else
6607 qsort(vector,vectorlen,sizeof(redisSortObject),sortCompare);
6608 }
6609
6610 /* Send command output to the output buffer, performing the specified
6611 * GET/DEL/INCR/DECR operations if any. */
6612 outputlen = getop ? getop*(end-start+1) : end-start+1;
6613 if (storekey == NULL) {
6614 /* STORE option not specified, sent the sorting result to client */
6615 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",outputlen));
6616 for (j = start; j <= end; j++) {
6617 listNode *ln;
6618 listIter li;
6619
6620 if (!getop) addReplyBulk(c,vector[j].obj);
6621 listRewind(operations,&li);
6622 while((ln = listNext(&li))) {
6623 redisSortOperation *sop = ln->value;
6624 robj *val = lookupKeyByPattern(c->db,sop->pattern,
6625 vector[j].obj);
6626
6627 if (sop->type == REDIS_SORT_GET) {
6628 if (!val || val->type != REDIS_STRING) {
6629 addReply(c,shared.nullbulk);
6630 } else {
6631 addReplyBulk(c,val);
6632 }
6633 } else {
6634 redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
6635 }
6636 }
6637 }
6638 } else {
6639 robj *listObject = createListObject();
6640 list *listPtr = (list*) listObject->ptr;
6641
6642 /* STORE option specified, set the sorting result as a List object */
6643 for (j = start; j <= end; j++) {
6644 listNode *ln;
6645 listIter li;
6646
6647 if (!getop) {
6648 listAddNodeTail(listPtr,vector[j].obj);
6649 incrRefCount(vector[j].obj);
6650 }
6651 listRewind(operations,&li);
6652 while((ln = listNext(&li))) {
6653 redisSortOperation *sop = ln->value;
6654 robj *val = lookupKeyByPattern(c->db,sop->pattern,
6655 vector[j].obj);
6656
6657 if (sop->type == REDIS_SORT_GET) {
6658 if (!val || val->type != REDIS_STRING) {
6659 listAddNodeTail(listPtr,createStringObject("",0));
6660 } else {
6661 listAddNodeTail(listPtr,val);
6662 incrRefCount(val);
6663 }
6664 } else {
6665 redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
6666 }
6667 }
6668 }
6669 if (dictReplace(c->db->dict,storekey,listObject)) {
6670 incrRefCount(storekey);
6671 }
6672 /* Note: we add 1 because the DB is dirty anyway since even if the
6673 * SORT result is empty a new key is set and maybe the old content
6674 * replaced. */
6675 server.dirty += 1+outputlen;
6676 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",outputlen));
6677 }
6678
6679 /* Cleanup */
6680 decrRefCount(sortval);
6681 listRelease(operations);
6682 for (j = 0; j < vectorlen; j++) {
6683 if (sortby && alpha && vector[j].u.cmpobj)
6684 decrRefCount(vector[j].u.cmpobj);
6685 }
6686 zfree(vector);
6687 }
6688
6689 /* Convert an amount of bytes into a human readable string in the form
6690 * of 100B, 2G, 100M, 4K, and so forth. */
6691 static void bytesToHuman(char *s, unsigned long long n) {
6692 double d;
6693
6694 if (n < 1024) {
6695 /* Bytes */
6696 sprintf(s,"%lluB",n);
6697 return;
6698 } else if (n < (1024*1024)) {
6699 d = (double)n/(1024);
6700 sprintf(s,"%.2fK",d);
6701 } else if (n < (1024LL*1024*1024)) {
6702 d = (double)n/(1024*1024);
6703 sprintf(s,"%.2fM",d);
6704 } else if (n < (1024LL*1024*1024*1024)) {
6705 d = (double)n/(1024LL*1024*1024);
6706 sprintf(s,"%.2fG",d);
6707 }
6708 }
6709
6710 /* Create the string returned by the INFO command. This is decoupled
6711 * by the INFO command itself as we need to report the same information
6712 * on memory corruption problems. */
6713 static sds genRedisInfoString(void) {
6714 sds info;
6715 time_t uptime = time(NULL)-server.stat_starttime;
6716 int j;
6717 char hmem[64];
6718
6719 bytesToHuman(hmem,zmalloc_used_memory());
6720 info = sdscatprintf(sdsempty(),
6721 "redis_version:%s\r\n"
6722 "arch_bits:%s\r\n"
6723 "multiplexing_api:%s\r\n"
6724 "process_id:%ld\r\n"
6725 "uptime_in_seconds:%ld\r\n"
6726 "uptime_in_days:%ld\r\n"
6727 "connected_clients:%d\r\n"
6728 "connected_slaves:%d\r\n"
6729 "blocked_clients:%d\r\n"
6730 "used_memory:%zu\r\n"
6731 "used_memory_human:%s\r\n"
6732 "changes_since_last_save:%lld\r\n"
6733 "bgsave_in_progress:%d\r\n"
6734 "last_save_time:%ld\r\n"
6735 "bgrewriteaof_in_progress:%d\r\n"
6736 "total_connections_received:%lld\r\n"
6737 "total_commands_processed:%lld\r\n"
6738 "expired_keys:%lld\r\n"
6739 "hash_max_zipmap_entries:%ld\r\n"
6740 "hash_max_zipmap_value:%ld\r\n"
6741 "pubsub_channels:%ld\r\n"
6742 "pubsub_patterns:%u\r\n"
6743 "vm_enabled:%d\r\n"
6744 "role:%s\r\n"
6745 ,REDIS_VERSION,
6746 (sizeof(long) == 8) ? "64" : "32",
6747 aeGetApiName(),
6748 (long) getpid(),
6749 uptime,
6750 uptime/(3600*24),
6751 listLength(server.clients)-listLength(server.slaves),
6752 listLength(server.slaves),
6753 server.blpop_blocked_clients,
6754 zmalloc_used_memory(),
6755 hmem,
6756 server.dirty,
6757 server.bgsavechildpid != -1,
6758 server.lastsave,
6759 server.bgrewritechildpid != -1,
6760 server.stat_numconnections,
6761 server.stat_numcommands,
6762 server.stat_expiredkeys,
6763 server.hash_max_zipmap_entries,
6764 server.hash_max_zipmap_value,
6765 dictSize(server.pubsub_channels),
6766 listLength(server.pubsub_patterns),
6767 server.vm_enabled != 0,
6768 server.masterhost == NULL ? "master" : "slave"
6769 );
6770 if (server.masterhost) {
6771 info = sdscatprintf(info,
6772 "master_host:%s\r\n"
6773 "master_port:%d\r\n"
6774 "master_link_status:%s\r\n"
6775 "master_last_io_seconds_ago:%d\r\n"
6776 ,server.masterhost,
6777 server.masterport,
6778 (server.replstate == REDIS_REPL_CONNECTED) ?
6779 "up" : "down",
6780 server.master ? ((int)(time(NULL)-server.master->lastinteraction)) : -1
6781 );
6782 }
6783 if (server.vm_enabled) {
6784 lockThreadedIO();
6785 info = sdscatprintf(info,
6786 "vm_conf_max_memory:%llu\r\n"
6787 "vm_conf_page_size:%llu\r\n"
6788 "vm_conf_pages:%llu\r\n"
6789 "vm_stats_used_pages:%llu\r\n"
6790 "vm_stats_swapped_objects:%llu\r\n"
6791 "vm_stats_swappin_count:%llu\r\n"
6792 "vm_stats_swappout_count:%llu\r\n"
6793 "vm_stats_io_newjobs_len:%lu\r\n"
6794 "vm_stats_io_processing_len:%lu\r\n"
6795 "vm_stats_io_processed_len:%lu\r\n"
6796 "vm_stats_io_active_threads:%lu\r\n"
6797 "vm_stats_blocked_clients:%lu\r\n"
6798 ,(unsigned long long) server.vm_max_memory,
6799 (unsigned long long) server.vm_page_size,
6800 (unsigned long long) server.vm_pages,
6801 (unsigned long long) server.vm_stats_used_pages,
6802 (unsigned long long) server.vm_stats_swapped_objects,
6803 (unsigned long long) server.vm_stats_swapins,
6804 (unsigned long long) server.vm_stats_swapouts,
6805 (unsigned long) listLength(server.io_newjobs),
6806 (unsigned long) listLength(server.io_processing),
6807 (unsigned long) listLength(server.io_processed),
6808 (unsigned long) server.io_active_threads,
6809 (unsigned long) server.vm_blocked_clients
6810 );
6811 unlockThreadedIO();
6812 }
6813 for (j = 0; j < server.dbnum; j++) {
6814 long long keys, vkeys;
6815
6816 keys = dictSize(server.db[j].dict);
6817 vkeys = dictSize(server.db[j].expires);
6818 if (keys || vkeys) {
6819 info = sdscatprintf(info, "db%d:keys=%lld,expires=%lld\r\n",
6820 j, keys, vkeys);
6821 }
6822 }
6823 return info;
6824 }
6825
6826 static void infoCommand(redisClient *c) {
6827 sds info = genRedisInfoString();
6828 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n",
6829 (unsigned long)sdslen(info)));
6830 addReplySds(c,info);
6831 addReply(c,shared.crlf);
6832 }
6833
6834 static void monitorCommand(redisClient *c) {
6835 /* ignore MONITOR if aleady slave or in monitor mode */
6836 if (c->flags & REDIS_SLAVE) return;
6837
6838 c->flags |= (REDIS_SLAVE|REDIS_MONITOR);
6839 c->slaveseldb = 0;
6840 listAddNodeTail(server.monitors,c);
6841 addReply(c,shared.ok);
6842 }
6843
6844 /* ================================= Expire ================================= */
6845 static int removeExpire(redisDb *db, robj *key) {
6846 if (dictDelete(db->expires,key) == DICT_OK) {
6847 return 1;
6848 } else {
6849 return 0;
6850 }
6851 }
6852
6853 static int setExpire(redisDb *db, robj *key, time_t when) {
6854 if (dictAdd(db->expires,key,(void*)when) == DICT_ERR) {
6855 return 0;
6856 } else {
6857 incrRefCount(key);
6858 return 1;
6859 }
6860 }
6861
6862 /* Return the expire time of the specified key, or -1 if no expire
6863 * is associated with this key (i.e. the key is non volatile) */
6864 static time_t getExpire(redisDb *db, robj *key) {
6865 dictEntry *de;
6866
6867 /* No expire? return ASAP */
6868 if (dictSize(db->expires) == 0 ||
6869 (de = dictFind(db->expires,key)) == NULL) return -1;
6870
6871 return (time_t) dictGetEntryVal(de);
6872 }
6873
6874 static int expireIfNeeded(redisDb *db, robj *key) {
6875 time_t when;
6876 dictEntry *de;
6877
6878 /* No expire? return ASAP */
6879 if (dictSize(db->expires) == 0 ||
6880 (de = dictFind(db->expires,key)) == NULL) return 0;
6881
6882 /* Lookup the expire */
6883 when = (time_t) dictGetEntryVal(de);
6884 if (time(NULL) <= when) return 0;
6885
6886 /* Delete the key */
6887 dictDelete(db->expires,key);
6888 server.stat_expiredkeys++;
6889 return dictDelete(db->dict,key) == DICT_OK;
6890 }
6891
6892 static int deleteIfVolatile(redisDb *db, robj *key) {
6893 dictEntry *de;
6894
6895 /* No expire? return ASAP */
6896 if (dictSize(db->expires) == 0 ||
6897 (de = dictFind(db->expires,key)) == NULL) return 0;
6898
6899 /* Delete the key */
6900 server.dirty++;
6901 server.stat_expiredkeys++;
6902 dictDelete(db->expires,key);
6903 return dictDelete(db->dict,key) == DICT_OK;
6904 }
6905
6906 static void expireGenericCommand(redisClient *c, robj *key, time_t seconds) {
6907 dictEntry *de;
6908
6909 de = dictFind(c->db->dict,key);
6910 if (de == NULL) {
6911 addReply(c,shared.czero);
6912 return;
6913 }
6914 if (seconds < 0) {
6915 if (deleteKey(c->db,key)) server.dirty++;
6916 addReply(c, shared.cone);
6917 return;
6918 } else {
6919 time_t when = time(NULL)+seconds;
6920 if (setExpire(c->db,key,when)) {
6921 addReply(c,shared.cone);
6922 server.dirty++;
6923 } else {
6924 addReply(c,shared.czero);
6925 }
6926 return;
6927 }
6928 }
6929
6930 static void expireCommand(redisClient *c) {
6931 expireGenericCommand(c,c->argv[1],strtol(c->argv[2]->ptr,NULL,10));
6932 }
6933
6934 static void expireatCommand(redisClient *c) {
6935 expireGenericCommand(c,c->argv[1],strtol(c->argv[2]->ptr,NULL,10)-time(NULL));
6936 }
6937
6938 static void ttlCommand(redisClient *c) {
6939 time_t expire;
6940 int ttl = -1;
6941
6942 expire = getExpire(c->db,c->argv[1]);
6943 if (expire != -1) {
6944 ttl = (int) (expire-time(NULL));
6945 if (ttl < 0) ttl = -1;
6946 }
6947 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",ttl));
6948 }
6949
6950 /* ================================ MULTI/EXEC ============================== */
6951
6952 /* Client state initialization for MULTI/EXEC */
6953 static void initClientMultiState(redisClient *c) {
6954 c->mstate.commands = NULL;
6955 c->mstate.count = 0;
6956 }
6957
6958 /* Release all the resources associated with MULTI/EXEC state */
6959 static void freeClientMultiState(redisClient *c) {
6960 int j;
6961
6962 for (j = 0; j < c->mstate.count; j++) {
6963 int i;
6964 multiCmd *mc = c->mstate.commands+j;
6965
6966 for (i = 0; i < mc->argc; i++)
6967 decrRefCount(mc->argv[i]);
6968 zfree(mc->argv);
6969 }
6970 zfree(c->mstate.commands);
6971 }
6972
6973 /* Add a new command into the MULTI commands queue */
6974 static void queueMultiCommand(redisClient *c, struct redisCommand *cmd) {
6975 multiCmd *mc;
6976 int j;
6977
6978 c->mstate.commands = zrealloc(c->mstate.commands,
6979 sizeof(multiCmd)*(c->mstate.count+1));
6980 mc = c->mstate.commands+c->mstate.count;
6981 mc->cmd = cmd;
6982 mc->argc = c->argc;
6983 mc->argv = zmalloc(sizeof(robj*)*c->argc);
6984 memcpy(mc->argv,c->argv,sizeof(robj*)*c->argc);
6985 for (j = 0; j < c->argc; j++)
6986 incrRefCount(mc->argv[j]);
6987 c->mstate.count++;
6988 }
6989
6990 static void multiCommand(redisClient *c) {
6991 c->flags |= REDIS_MULTI;
6992 addReply(c,shared.ok);
6993 }
6994
6995 static void discardCommand(redisClient *c) {
6996 if (!(c->flags & REDIS_MULTI)) {
6997 addReplySds(c,sdsnew("-ERR DISCARD without MULTI\r\n"));
6998 return;
6999 }
7000
7001 freeClientMultiState(c);
7002 initClientMultiState(c);
7003 c->flags &= (~REDIS_MULTI);
7004 addReply(c,shared.ok);
7005 }
7006
7007 static void execCommand(redisClient *c) {
7008 int j;
7009 robj **orig_argv;
7010 int orig_argc;
7011
7012 if (!(c->flags & REDIS_MULTI)) {
7013 addReplySds(c,sdsnew("-ERR EXEC without MULTI\r\n"));
7014 return;
7015 }
7016
7017 orig_argv = c->argv;
7018 orig_argc = c->argc;
7019 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->mstate.count));
7020 for (j = 0; j < c->mstate.count; j++) {
7021 c->argc = c->mstate.commands[j].argc;
7022 c->argv = c->mstate.commands[j].argv;
7023 call(c,c->mstate.commands[j].cmd);
7024 }
7025 c->argv = orig_argv;
7026 c->argc = orig_argc;
7027 freeClientMultiState(c);
7028 initClientMultiState(c);
7029 c->flags &= (~REDIS_MULTI);
7030 }
7031
7032 /* =========================== Blocking Operations ========================= */
7033
7034 /* Currently Redis blocking operations support is limited to list POP ops,
7035 * so the current implementation is not fully generic, but it is also not
7036 * completely specific so it will not require a rewrite to support new
7037 * kind of blocking operations in the future.
7038 *
7039 * Still it's important to note that list blocking operations can be already
7040 * used as a notification mechanism in order to implement other blocking
7041 * operations at application level, so there must be a very strong evidence
7042 * of usefulness and generality before new blocking operations are implemented.
7043 *
7044 * This is how the current blocking POP works, we use BLPOP as example:
7045 * - If the user calls BLPOP and the key exists and contains a non empty list
7046 * then LPOP is called instead. So BLPOP is semantically the same as LPOP
7047 * if there is not to block.
7048 * - If instead BLPOP is called and the key does not exists or the list is
7049 * empty we need to block. In order to do so we remove the notification for
7050 * new data to read in the client socket (so that we'll not serve new
7051 * requests if the blocking request is not served). Also we put the client
7052 * in a dictionary (db->blockingkeys) mapping keys to a list of clients
7053 * blocking for this keys.
7054 * - If a PUSH operation against a key with blocked clients waiting is
7055 * performed, we serve the first in the list: basically instead to push
7056 * the new element inside the list we return it to the (first / oldest)
7057 * blocking client, unblock the client, and remove it form the list.
7058 *
7059 * The above comment and the source code should be enough in order to understand
7060 * the implementation and modify / fix it later.
7061 */
7062
7063 /* Set a client in blocking mode for the specified key, with the specified
7064 * timeout */
7065 static void blockForKeys(redisClient *c, robj **keys, int numkeys, time_t timeout) {
7066 dictEntry *de;
7067 list *l;
7068 int j;
7069
7070 c->blockingkeys = zmalloc(sizeof(robj*)*numkeys);
7071 c->blockingkeysnum = numkeys;
7072 c->blockingto = timeout;
7073 for (j = 0; j < numkeys; j++) {
7074 /* Add the key in the client structure, to map clients -> keys */
7075 c->blockingkeys[j] = keys[j];
7076 incrRefCount(keys[j]);
7077
7078 /* And in the other "side", to map keys -> clients */
7079 de = dictFind(c->db->blockingkeys,keys[j]);
7080 if (de == NULL) {
7081 int retval;
7082
7083 /* For every key we take a list of clients blocked for it */
7084 l = listCreate();
7085 retval = dictAdd(c->db->blockingkeys,keys[j],l);
7086 incrRefCount(keys[j]);
7087 assert(retval == DICT_OK);
7088 } else {
7089 l = dictGetEntryVal(de);
7090 }
7091 listAddNodeTail(l,c);
7092 }
7093 /* Mark the client as a blocked client */
7094 c->flags |= REDIS_BLOCKED;
7095 server.blpop_blocked_clients++;
7096 }
7097
7098 /* Unblock a client that's waiting in a blocking operation such as BLPOP */
7099 static void unblockClientWaitingData(redisClient *c) {
7100 dictEntry *de;
7101 list *l;
7102 int j;
7103
7104 assert(c->blockingkeys != NULL);
7105 /* The client may wait for multiple keys, so unblock it for every key. */
7106 for (j = 0; j < c->blockingkeysnum; j++) {
7107 /* Remove this client from the list of clients waiting for this key. */
7108 de = dictFind(c->db->blockingkeys,c->blockingkeys[j]);
7109 assert(de != NULL);
7110 l = dictGetEntryVal(de);
7111 listDelNode(l,listSearchKey(l,c));
7112 /* If the list is empty we need to remove it to avoid wasting memory */
7113 if (listLength(l) == 0)
7114 dictDelete(c->db->blockingkeys,c->blockingkeys[j]);
7115 decrRefCount(c->blockingkeys[j]);
7116 }
7117 /* Cleanup the client structure */
7118 zfree(c->blockingkeys);
7119 c->blockingkeys = NULL;
7120 c->flags &= (~REDIS_BLOCKED);
7121 server.blpop_blocked_clients--;
7122 /* We want to process data if there is some command waiting
7123 * in the input buffer. Note that this is safe even if
7124 * unblockClientWaitingData() gets called from freeClient() because
7125 * freeClient() will be smart enough to call this function
7126 * *after* c->querybuf was set to NULL. */
7127 if (c->querybuf && sdslen(c->querybuf) > 0) processInputBuffer(c);
7128 }
7129
7130 /* This should be called from any function PUSHing into lists.
7131 * 'c' is the "pushing client", 'key' is the key it is pushing data against,
7132 * 'ele' is the element pushed.
7133 *
7134 * If the function returns 0 there was no client waiting for a list push
7135 * against this key.
7136 *
7137 * If the function returns 1 there was a client waiting for a list push
7138 * against this key, the element was passed to this client thus it's not
7139 * needed to actually add it to the list and the caller should return asap. */
7140 static int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
7141 struct dictEntry *de;
7142 redisClient *receiver;
7143 list *l;
7144 listNode *ln;
7145
7146 de = dictFind(c->db->blockingkeys,key);
7147 if (de == NULL) return 0;
7148 l = dictGetEntryVal(de);
7149 ln = listFirst(l);
7150 assert(ln != NULL);
7151 receiver = ln->value;
7152
7153 addReplySds(receiver,sdsnew("*2\r\n"));
7154 addReplyBulk(receiver,key);
7155 addReplyBulk(receiver,ele);
7156 unblockClientWaitingData(receiver);
7157 return 1;
7158 }
7159
7160 /* Blocking RPOP/LPOP */
7161 static void blockingPopGenericCommand(redisClient *c, int where) {
7162 robj *o;
7163 time_t timeout;
7164 int j;
7165
7166 for (j = 1; j < c->argc-1; j++) {
7167 o = lookupKeyWrite(c->db,c->argv[j]);
7168 if (o != NULL) {
7169 if (o->type != REDIS_LIST) {
7170 addReply(c,shared.wrongtypeerr);
7171 return;
7172 } else {
7173 list *list = o->ptr;
7174 if (listLength(list) != 0) {
7175 /* If the list contains elements fall back to the usual
7176 * non-blocking POP operation */
7177 robj *argv[2], **orig_argv;
7178 int orig_argc;
7179
7180 /* We need to alter the command arguments before to call
7181 * popGenericCommand() as the command takes a single key. */
7182 orig_argv = c->argv;
7183 orig_argc = c->argc;
7184 argv[1] = c->argv[j];
7185 c->argv = argv;
7186 c->argc = 2;
7187
7188 /* Also the return value is different, we need to output
7189 * the multi bulk reply header and the key name. The
7190 * "real" command will add the last element (the value)
7191 * for us. If this souds like an hack to you it's just
7192 * because it is... */
7193 addReplySds(c,sdsnew("*2\r\n"));
7194 addReplyBulk(c,argv[1]);
7195 popGenericCommand(c,where);
7196
7197 /* Fix the client structure with the original stuff */
7198 c->argv = orig_argv;
7199 c->argc = orig_argc;
7200 return;
7201 }
7202 }
7203 }
7204 }
7205 /* If the list is empty or the key does not exists we must block */
7206 timeout = strtol(c->argv[c->argc-1]->ptr,NULL,10);
7207 if (timeout > 0) timeout += time(NULL);
7208 blockForKeys(c,c->argv+1,c->argc-2,timeout);
7209 }
7210
7211 static void blpopCommand(redisClient *c) {
7212 blockingPopGenericCommand(c,REDIS_HEAD);
7213 }
7214
7215 static void brpopCommand(redisClient *c) {
7216 blockingPopGenericCommand(c,REDIS_TAIL);
7217 }
7218
7219 /* =============================== Replication ============================= */
7220
7221 static int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
7222 ssize_t nwritten, ret = size;
7223 time_t start = time(NULL);
7224
7225 timeout++;
7226 while(size) {
7227 if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
7228 nwritten = write(fd,ptr,size);
7229 if (nwritten == -1) return -1;
7230 ptr += nwritten;
7231 size -= nwritten;
7232 }
7233 if ((time(NULL)-start) > timeout) {
7234 errno = ETIMEDOUT;
7235 return -1;
7236 }
7237 }
7238 return ret;
7239 }
7240
7241 static int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
7242 ssize_t nread, totread = 0;
7243 time_t start = time(NULL);
7244
7245 timeout++;
7246 while(size) {
7247 if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
7248 nread = read(fd,ptr,size);
7249 if (nread == -1) return -1;
7250 ptr += nread;
7251 size -= nread;
7252 totread += nread;
7253 }
7254 if ((time(NULL)-start) > timeout) {
7255 errno = ETIMEDOUT;
7256 return -1;
7257 }
7258 }
7259 return totread;
7260 }
7261
7262 static int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
7263 ssize_t nread = 0;
7264
7265 size--;
7266 while(size) {
7267 char c;
7268
7269 if (syncRead(fd,&c,1,timeout) == -1) return -1;
7270 if (c == '\n') {
7271 *ptr = '\0';
7272 if (nread && *(ptr-1) == '\r') *(ptr-1) = '\0';
7273 return nread;
7274 } else {
7275 *ptr++ = c;
7276 *ptr = '\0';
7277 nread++;
7278 }
7279 }
7280 return nread;
7281 }
7282
7283 static void syncCommand(redisClient *c) {
7284 /* ignore SYNC if aleady slave or in monitor mode */
7285 if (c->flags & REDIS_SLAVE) return;
7286
7287 /* SYNC can't be issued when the server has pending data to send to
7288 * the client about already issued commands. We need a fresh reply
7289 * buffer registering the differences between the BGSAVE and the current
7290 * dataset, so that we can copy to other slaves if needed. */
7291 if (listLength(c->reply) != 0) {
7292 addReplySds(c,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
7293 return;
7294 }
7295
7296 redisLog(REDIS_NOTICE,"Slave ask for synchronization");
7297 /* Here we need to check if there is a background saving operation
7298 * in progress, or if it is required to start one */
7299 if (server.bgsavechildpid != -1) {
7300 /* Ok a background save is in progress. Let's check if it is a good
7301 * one for replication, i.e. if there is another slave that is
7302 * registering differences since the server forked to save */
7303 redisClient *slave;
7304 listNode *ln;
7305 listIter li;
7306
7307 listRewind(server.slaves,&li);
7308 while((ln = listNext(&li))) {
7309 slave = ln->value;
7310 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break;
7311 }
7312 if (ln) {
7313 /* Perfect, the server is already registering differences for
7314 * another slave. Set the right state, and copy the buffer. */
7315 listRelease(c->reply);
7316 c->reply = listDup(slave->reply);
7317 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
7318 redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC");
7319 } else {
7320 /* No way, we need to wait for the next BGSAVE in order to
7321 * register differences */
7322 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
7323 redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
7324 }
7325 } else {
7326 /* Ok we don't have a BGSAVE in progress, let's start one */
7327 redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
7328 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
7329 redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE");
7330 addReplySds(c,sdsnew("-ERR Unalbe to perform background save\r\n"));
7331 return;
7332 }
7333 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
7334 }
7335 c->repldbfd = -1;
7336 c->flags |= REDIS_SLAVE;
7337 c->slaveseldb = 0;
7338 listAddNodeTail(server.slaves,c);
7339 return;
7340 }
7341
7342 static void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
7343 redisClient *slave = privdata;
7344 REDIS_NOTUSED(el);
7345 REDIS_NOTUSED(mask);
7346 char buf[REDIS_IOBUF_LEN];
7347 ssize_t nwritten, buflen;
7348
7349 if (slave->repldboff == 0) {
7350 /* Write the bulk write count before to transfer the DB. In theory here
7351 * we don't know how much room there is in the output buffer of the
7352 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
7353 * operations) will never be smaller than the few bytes we need. */
7354 sds bulkcount;
7355
7356 bulkcount = sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
7357 slave->repldbsize);
7358 if (write(fd,bulkcount,sdslen(bulkcount)) != (signed)sdslen(bulkcount))
7359 {
7360 sdsfree(bulkcount);
7361 freeClient(slave);
7362 return;
7363 }
7364 sdsfree(bulkcount);
7365 }
7366 lseek(slave->repldbfd,slave->repldboff,SEEK_SET);
7367 buflen = read(slave->repldbfd,buf,REDIS_IOBUF_LEN);
7368 if (buflen <= 0) {
7369 redisLog(REDIS_WARNING,"Read error sending DB to slave: %s",
7370 (buflen == 0) ? "premature EOF" : strerror(errno));
7371 freeClient(slave);
7372 return;
7373 }
7374 if ((nwritten = write(fd,buf,buflen)) == -1) {
7375 redisLog(REDIS_VERBOSE,"Write error sending DB to slave: %s",
7376 strerror(errno));
7377 freeClient(slave);
7378 return;
7379 }
7380 slave->repldboff += nwritten;
7381 if (slave->repldboff == slave->repldbsize) {
7382 close(slave->repldbfd);
7383 slave->repldbfd = -1;
7384 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
7385 slave->replstate = REDIS_REPL_ONLINE;
7386 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
7387 sendReplyToClient, slave) == AE_ERR) {
7388 freeClient(slave);
7389 return;
7390 }
7391 addReplySds(slave,sdsempty());
7392 redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
7393 }
7394 }
7395
7396 /* This function is called at the end of every backgrond saving.
7397 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
7398 * otherwise REDIS_ERR is passed to the function.
7399 *
7400 * The goal of this function is to handle slaves waiting for a successful
7401 * background saving in order to perform non-blocking synchronization. */
7402 static void updateSlavesWaitingBgsave(int bgsaveerr) {
7403 listNode *ln;
7404 int startbgsave = 0;
7405 listIter li;
7406
7407 listRewind(server.slaves,&li);
7408 while((ln = listNext(&li))) {
7409 redisClient *slave = ln->value;
7410
7411 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) {
7412 startbgsave = 1;
7413 slave->replstate = REDIS_REPL_WAIT_BGSAVE_END;
7414 } else if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
7415 struct redis_stat buf;
7416
7417 if (bgsaveerr != REDIS_OK) {
7418 freeClient(slave);
7419 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE child returned an error");
7420 continue;
7421 }
7422 if ((slave->repldbfd = open(server.dbfilename,O_RDONLY)) == -1 ||
7423 redis_fstat(slave->repldbfd,&buf) == -1) {
7424 freeClient(slave);
7425 redisLog(REDIS_WARNING,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno));
7426 continue;
7427 }
7428 slave->repldboff = 0;
7429 slave->repldbsize = buf.st_size;
7430 slave->replstate = REDIS_REPL_SEND_BULK;
7431 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
7432 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE, sendBulkToSlave, slave) == AE_ERR) {
7433 freeClient(slave);
7434 continue;
7435 }
7436 }
7437 }
7438 if (startbgsave) {
7439 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
7440 listIter li;
7441
7442 listRewind(server.slaves,&li);
7443 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE failed");
7444 while((ln = listNext(&li))) {
7445 redisClient *slave = ln->value;
7446
7447 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START)
7448 freeClient(slave);
7449 }
7450 }
7451 }
7452 }
7453
7454 static int syncWithMaster(void) {
7455 char buf[1024], tmpfile[256], authcmd[1024];
7456 long dumpsize;
7457 int fd = anetTcpConnect(NULL,server.masterhost,server.masterport);
7458 int dfd, maxtries = 5;
7459
7460 if (fd == -1) {
7461 redisLog(REDIS_WARNING,"Unable to connect to MASTER: %s",
7462 strerror(errno));
7463 return REDIS_ERR;
7464 }
7465
7466 /* AUTH with the master if required. */
7467 if(server.masterauth) {
7468 snprintf(authcmd, 1024, "AUTH %s\r\n", server.masterauth);
7469 if (syncWrite(fd, authcmd, strlen(server.masterauth)+7, 5) == -1) {
7470 close(fd);
7471 redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",
7472 strerror(errno));
7473 return REDIS_ERR;
7474 }
7475 /* Read the AUTH result. */
7476 if (syncReadLine(fd,buf,1024,3600) == -1) {
7477 close(fd);
7478 redisLog(REDIS_WARNING,"I/O error reading auth result from MASTER: %s",
7479 strerror(errno));
7480 return REDIS_ERR;
7481 }
7482 if (buf[0] != '+') {
7483 close(fd);
7484 redisLog(REDIS_WARNING,"Cannot AUTH to MASTER, is the masterauth password correct?");
7485 return REDIS_ERR;
7486 }
7487 }
7488
7489 /* Issue the SYNC command */
7490 if (syncWrite(fd,"SYNC \r\n",7,5) == -1) {
7491 close(fd);
7492 redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
7493 strerror(errno));
7494 return REDIS_ERR;
7495 }
7496 /* Read the bulk write count */
7497 if (syncReadLine(fd,buf,1024,3600) == -1) {
7498 close(fd);
7499 redisLog(REDIS_WARNING,"I/O error reading bulk count from MASTER: %s",
7500 strerror(errno));
7501 return REDIS_ERR;
7502 }
7503 if (buf[0] != '$') {
7504 close(fd);
7505 redisLog(REDIS_WARNING,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
7506 return REDIS_ERR;
7507 }
7508 dumpsize = strtol(buf+1,NULL,10);
7509 redisLog(REDIS_NOTICE,"Receiving %ld bytes data dump from MASTER",dumpsize);
7510 /* Read the bulk write data on a temp file */
7511 while(maxtries--) {
7512 snprintf(tmpfile,256,
7513 "temp-%d.%ld.rdb",(int)time(NULL),(long int)getpid());
7514 dfd = open(tmpfile,O_CREAT|O_WRONLY|O_EXCL,0644);
7515 if (dfd != -1) break;
7516 sleep(1);
7517 }
7518 if (dfd == -1) {
7519 close(fd);
7520 redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
7521 return REDIS_ERR;
7522 }
7523 while(dumpsize) {
7524 int nread, nwritten;
7525
7526 nread = read(fd,buf,(dumpsize < 1024)?dumpsize:1024);
7527 if (nread == -1) {
7528 redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
7529 strerror(errno));
7530 close(fd);
7531 close(dfd);
7532 return REDIS_ERR;
7533 }
7534 nwritten = write(dfd,buf,nread);
7535 if (nwritten == -1) {
7536 redisLog(REDIS_WARNING,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
7537 close(fd);
7538 close(dfd);
7539 return REDIS_ERR;
7540 }
7541 dumpsize -= nread;
7542 }
7543 close(dfd);
7544 if (rename(tmpfile,server.dbfilename) == -1) {
7545 redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
7546 unlink(tmpfile);
7547 close(fd);
7548 return REDIS_ERR;
7549 }
7550 emptyDb();
7551 if (rdbLoad(server.dbfilename) != REDIS_OK) {
7552 redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
7553 close(fd);
7554 return REDIS_ERR;
7555 }
7556 server.master = createClient(fd);
7557 server.master->flags |= REDIS_MASTER;
7558 server.master->authenticated = 1;
7559 server.replstate = REDIS_REPL_CONNECTED;
7560 return REDIS_OK;
7561 }
7562
7563 static void slaveofCommand(redisClient *c) {
7564 if (!strcasecmp(c->argv[1]->ptr,"no") &&
7565 !strcasecmp(c->argv[2]->ptr,"one")) {
7566 if (server.masterhost) {
7567 sdsfree(server.masterhost);
7568 server.masterhost = NULL;
7569 if (server.master) freeClient(server.master);
7570 server.replstate = REDIS_REPL_NONE;
7571 redisLog(REDIS_NOTICE,"MASTER MODE enabled (user request)");
7572 }
7573 } else {
7574 sdsfree(server.masterhost);
7575 server.masterhost = sdsdup(c->argv[1]->ptr);
7576 server.masterport = atoi(c->argv[2]->ptr);
7577 if (server.master) freeClient(server.master);
7578 server.replstate = REDIS_REPL_CONNECT;
7579 redisLog(REDIS_NOTICE,"SLAVE OF %s:%d enabled (user request)",
7580 server.masterhost, server.masterport);
7581 }
7582 addReply(c,shared.ok);
7583 }
7584
7585 /* ============================ Maxmemory directive ======================== */
7586
7587 /* Try to free one object form the pre-allocated objects free list.
7588 * This is useful under low mem conditions as by default we take 1 million
7589 * free objects allocated. On success REDIS_OK is returned, otherwise
7590 * REDIS_ERR. */
7591 static int tryFreeOneObjectFromFreelist(void) {
7592 robj *o;
7593
7594 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
7595 if (listLength(server.objfreelist)) {
7596 listNode *head = listFirst(server.objfreelist);
7597 o = listNodeValue(head);
7598 listDelNode(server.objfreelist,head);
7599 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
7600 zfree(o);
7601 return REDIS_OK;
7602 } else {
7603 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
7604 return REDIS_ERR;
7605 }
7606 }
7607
7608 /* This function gets called when 'maxmemory' is set on the config file to limit
7609 * the max memory used by the server, and we are out of memory.
7610 * This function will try to, in order:
7611 *
7612 * - Free objects from the free list
7613 * - Try to remove keys with an EXPIRE set
7614 *
7615 * It is not possible to free enough memory to reach used-memory < maxmemory
7616 * the server will start refusing commands that will enlarge even more the
7617 * memory usage.
7618 */
7619 static void freeMemoryIfNeeded(void) {
7620 while (server.maxmemory && zmalloc_used_memory() > server.maxmemory) {
7621 int j, k, freed = 0;
7622
7623 if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
7624 for (j = 0; j < server.dbnum; j++) {
7625 int minttl = -1;
7626 robj *minkey = NULL;
7627 struct dictEntry *de;
7628
7629 if (dictSize(server.db[j].expires)) {
7630 freed = 1;
7631 /* From a sample of three keys drop the one nearest to
7632 * the natural expire */
7633 for (k = 0; k < 3; k++) {
7634 time_t t;
7635
7636 de = dictGetRandomKey(server.db[j].expires);
7637 t = (time_t) dictGetEntryVal(de);
7638 if (minttl == -1 || t < minttl) {
7639 minkey = dictGetEntryKey(de);
7640 minttl = t;
7641 }
7642 }
7643 deleteKey(server.db+j,minkey);
7644 }
7645 }
7646 if (!freed) return; /* nothing to free... */
7647 }
7648 }
7649
7650 /* ============================== Append Only file ========================== */
7651
7652 static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {
7653 sds buf = sdsempty();
7654 int j;
7655 ssize_t nwritten;
7656 time_t now;
7657 robj *tmpargv[3];
7658
7659 /* The DB this command was targetting is not the same as the last command
7660 * we appendend. To issue a SELECT command is needed. */
7661 if (dictid != server.appendseldb) {
7662 char seldb[64];
7663
7664 snprintf(seldb,sizeof(seldb),"%d",dictid);
7665 buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
7666 (unsigned long)strlen(seldb),seldb);
7667 server.appendseldb = dictid;
7668 }
7669
7670 /* "Fix" the argv vector if the command is EXPIRE. We want to translate
7671 * EXPIREs into EXPIREATs calls */
7672 if (cmd->proc == expireCommand) {
7673 long when;
7674
7675 tmpargv[0] = createStringObject("EXPIREAT",8);
7676 tmpargv[1] = argv[1];
7677 incrRefCount(argv[1]);
7678 when = time(NULL)+strtol(argv[2]->ptr,NULL,10);
7679 tmpargv[2] = createObject(REDIS_STRING,
7680 sdscatprintf(sdsempty(),"%ld",when));
7681 argv = tmpargv;
7682 }
7683
7684 /* Append the actual command */
7685 buf = sdscatprintf(buf,"*%d\r\n",argc);
7686 for (j = 0; j < argc; j++) {
7687 robj *o = argv[j];
7688
7689 o = getDecodedObject(o);
7690 buf = sdscatprintf(buf,"$%lu\r\n",(unsigned long)sdslen(o->ptr));
7691 buf = sdscatlen(buf,o->ptr,sdslen(o->ptr));
7692 buf = sdscatlen(buf,"\r\n",2);
7693 decrRefCount(o);
7694 }
7695
7696 /* Free the objects from the modified argv for EXPIREAT */
7697 if (cmd->proc == expireCommand) {
7698 for (j = 0; j < 3; j++)
7699 decrRefCount(argv[j]);
7700 }
7701
7702 /* We want to perform a single write. This should be guaranteed atomic
7703 * at least if the filesystem we are writing is a real physical one.
7704 * While this will save us against the server being killed I don't think
7705 * there is much to do about the whole server stopping for power problems
7706 * or alike */
7707 nwritten = write(server.appendfd,buf,sdslen(buf));
7708 if (nwritten != (signed)sdslen(buf)) {
7709 /* Ooops, we are in troubles. The best thing to do for now is
7710 * to simply exit instead to give the illusion that everything is
7711 * working as expected. */
7712 if (nwritten == -1) {
7713 redisLog(REDIS_WARNING,"Exiting on error writing to the append-only file: %s",strerror(errno));
7714 } else {
7715 redisLog(REDIS_WARNING,"Exiting on short write while writing to the append-only file: %s",strerror(errno));
7716 }
7717 exit(1);
7718 }
7719 /* If a background append only file rewriting is in progress we want to
7720 * accumulate the differences between the child DB and the current one
7721 * in a buffer, so that when the child process will do its work we
7722 * can append the differences to the new append only file. */
7723 if (server.bgrewritechildpid != -1)
7724 server.bgrewritebuf = sdscatlen(server.bgrewritebuf,buf,sdslen(buf));
7725
7726 sdsfree(buf);
7727 now = time(NULL);
7728 if (server.appendfsync == APPENDFSYNC_ALWAYS ||
7729 (server.appendfsync == APPENDFSYNC_EVERYSEC &&
7730 now-server.lastfsync > 1))
7731 {
7732 fsync(server.appendfd); /* Let's try to get this data on the disk */
7733 server.lastfsync = now;
7734 }
7735 }
7736
7737 /* In Redis commands are always executed in the context of a client, so in
7738 * order to load the append only file we need to create a fake client. */
7739 static struct redisClient *createFakeClient(void) {
7740 struct redisClient *c = zmalloc(sizeof(*c));
7741
7742 selectDb(c,0);
7743 c->fd = -1;
7744 c->querybuf = sdsempty();
7745 c->argc = 0;
7746 c->argv = NULL;
7747 c->flags = 0;
7748 /* We set the fake client as a slave waiting for the synchronization
7749 * so that Redis will not try to send replies to this client. */
7750 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
7751 c->reply = listCreate();
7752 listSetFreeMethod(c->reply,decrRefCount);
7753 listSetDupMethod(c->reply,dupClientReplyValue);
7754 return c;
7755 }
7756
7757 static void freeFakeClient(struct redisClient *c) {
7758 sdsfree(c->querybuf);
7759 listRelease(c->reply);
7760 zfree(c);
7761 }
7762
7763 /* Replay the append log file. On error REDIS_OK is returned. On non fatal
7764 * error (the append only file is zero-length) REDIS_ERR is returned. On
7765 * fatal error an error message is logged and the program exists. */
7766 int loadAppendOnlyFile(char *filename) {
7767 struct redisClient *fakeClient;
7768 FILE *fp = fopen(filename,"r");
7769 struct redis_stat sb;
7770 unsigned long long loadedkeys = 0;
7771
7772 if (redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0)
7773 return REDIS_ERR;
7774
7775 if (fp == NULL) {
7776 redisLog(REDIS_WARNING,"Fatal error: can't open the append log file for reading: %s",strerror(errno));
7777 exit(1);
7778 }
7779
7780 fakeClient = createFakeClient();
7781 while(1) {
7782 int argc, j;
7783 unsigned long len;
7784 robj **argv;
7785 char buf[128];
7786 sds argsds;
7787 struct redisCommand *cmd;
7788
7789 if (fgets(buf,sizeof(buf),fp) == NULL) {
7790 if (feof(fp))
7791 break;
7792 else
7793 goto readerr;
7794 }
7795 if (buf[0] != '*') goto fmterr;
7796 argc = atoi(buf+1);
7797 argv = zmalloc(sizeof(robj*)*argc);
7798 for (j = 0; j < argc; j++) {
7799 if (fgets(buf,sizeof(buf),fp) == NULL) goto readerr;
7800 if (buf[0] != '$') goto fmterr;
7801 len = strtol(buf+1,NULL,10);
7802 argsds = sdsnewlen(NULL,len);
7803 if (len && fread(argsds,len,1,fp) == 0) goto fmterr;
7804 argv[j] = createObject(REDIS_STRING,argsds);
7805 if (fread(buf,2,1,fp) == 0) goto fmterr; /* discard CRLF */
7806 }
7807
7808 /* Command lookup */
7809 cmd = lookupCommand(argv[0]->ptr);
7810 if (!cmd) {
7811 redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", argv[0]->ptr);
7812 exit(1);
7813 }
7814 /* Try object sharing and encoding */
7815 if (server.shareobjects) {
7816 int j;
7817 for(j = 1; j < argc; j++)
7818 argv[j] = tryObjectSharing(argv[j]);
7819 }
7820 if (cmd->flags & REDIS_CMD_BULK)
7821 tryObjectEncoding(argv[argc-1]);
7822 /* Run the command in the context of a fake client */
7823 fakeClient->argc = argc;
7824 fakeClient->argv = argv;
7825 cmd->proc(fakeClient);
7826 /* Discard the reply objects list from the fake client */
7827 while(listLength(fakeClient->reply))
7828 listDelNode(fakeClient->reply,listFirst(fakeClient->reply));
7829 /* Clean up, ready for the next command */
7830 for (j = 0; j < argc; j++) decrRefCount(argv[j]);
7831 zfree(argv);
7832 /* Handle swapping while loading big datasets when VM is on */
7833 loadedkeys++;
7834 if (server.vm_enabled && (loadedkeys % 5000) == 0) {
7835 while (zmalloc_used_memory() > server.vm_max_memory) {
7836 if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
7837 }
7838 }
7839 }
7840 fclose(fp);
7841 freeFakeClient(fakeClient);
7842 return REDIS_OK;
7843
7844 readerr:
7845 if (feof(fp)) {
7846 redisLog(REDIS_WARNING,"Unexpected end of file reading the append only file");
7847 } else {
7848 redisLog(REDIS_WARNING,"Unrecoverable error reading the append only file: %s", strerror(errno));
7849 }
7850 exit(1);
7851 fmterr:
7852 redisLog(REDIS_WARNING,"Bad file format reading the append only file");
7853 exit(1);
7854 }
7855
7856 /* Write an object into a file in the bulk format $<count>\r\n<payload>\r\n */
7857 static int fwriteBulkObject(FILE *fp, robj *obj) {
7858 char buf[128];
7859 int decrrc = 0;
7860
7861 /* Avoid the incr/decr ref count business if possible to help
7862 * copy-on-write (we are often in a child process when this function
7863 * is called).
7864 * Also makes sure that key objects don't get incrRefCount-ed when VM
7865 * is enabled */
7866 if (obj->encoding != REDIS_ENCODING_RAW) {
7867 obj = getDecodedObject(obj);
7868 decrrc = 1;
7869 }
7870 snprintf(buf,sizeof(buf),"$%ld\r\n",(long)sdslen(obj->ptr));
7871 if (fwrite(buf,strlen(buf),1,fp) == 0) goto err;
7872 if (sdslen(obj->ptr) && fwrite(obj->ptr,sdslen(obj->ptr),1,fp) == 0)
7873 goto err;
7874 if (fwrite("\r\n",2,1,fp) == 0) goto err;
7875 if (decrrc) decrRefCount(obj);
7876 return 1;
7877 err:
7878 if (decrrc) decrRefCount(obj);
7879 return 0;
7880 }
7881
7882 /* Write binary-safe string into a file in the bulkformat
7883 * $<count>\r\n<payload>\r\n */
7884 static int fwriteBulkString(FILE *fp, char *s, unsigned long len) {
7885 char buf[128];
7886
7887 snprintf(buf,sizeof(buf),"$%ld\r\n",(unsigned long)len);
7888 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
7889 if (len && fwrite(s,len,1,fp) == 0) return 0;
7890 if (fwrite("\r\n",2,1,fp) == 0) return 0;
7891 return 1;
7892 }
7893
7894 /* Write a double value in bulk format $<count>\r\n<payload>\r\n */
7895 static int fwriteBulkDouble(FILE *fp, double d) {
7896 char buf[128], dbuf[128];
7897
7898 snprintf(dbuf,sizeof(dbuf),"%.17g\r\n",d);
7899 snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(dbuf)-2);
7900 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
7901 if (fwrite(dbuf,strlen(dbuf),1,fp) == 0) return 0;
7902 return 1;
7903 }
7904
7905 /* Write a long value in bulk format $<count>\r\n<payload>\r\n */
7906 static int fwriteBulkLong(FILE *fp, long l) {
7907 char buf[128], lbuf[128];
7908
7909 snprintf(lbuf,sizeof(lbuf),"%ld\r\n",l);
7910 snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(lbuf)-2);
7911 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
7912 if (fwrite(lbuf,strlen(lbuf),1,fp) == 0) return 0;
7913 return 1;
7914 }
7915
7916 /* Write a sequence of commands able to fully rebuild the dataset into
7917 * "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
7918 static int rewriteAppendOnlyFile(char *filename) {
7919 dictIterator *di = NULL;
7920 dictEntry *de;
7921 FILE *fp;
7922 char tmpfile[256];
7923 int j;
7924 time_t now = time(NULL);
7925
7926 /* Note that we have to use a different temp name here compared to the
7927 * one used by rewriteAppendOnlyFileBackground() function. */
7928 snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid());
7929 fp = fopen(tmpfile,"w");
7930 if (!fp) {
7931 redisLog(REDIS_WARNING, "Failed rewriting the append only file: %s", strerror(errno));
7932 return REDIS_ERR;
7933 }
7934 for (j = 0; j < server.dbnum; j++) {
7935 char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n";
7936 redisDb *db = server.db+j;
7937 dict *d = db->dict;
7938 if (dictSize(d) == 0) continue;
7939 di = dictGetIterator(d);
7940 if (!di) {
7941 fclose(fp);
7942 return REDIS_ERR;
7943 }
7944
7945 /* SELECT the new DB */
7946 if (fwrite(selectcmd,sizeof(selectcmd)-1,1,fp) == 0) goto werr;
7947 if (fwriteBulkLong(fp,j) == 0) goto werr;
7948
7949 /* Iterate this DB writing every entry */
7950 while((de = dictNext(di)) != NULL) {
7951 robj *key, *o;
7952 time_t expiretime;
7953 int swapped;
7954
7955 key = dictGetEntryKey(de);
7956 /* If the value for this key is swapped, load a preview in memory.
7957 * We use a "swapped" flag to remember if we need to free the
7958 * value object instead to just increment the ref count anyway
7959 * in order to avoid copy-on-write of pages if we are forked() */
7960 if (!server.vm_enabled || key->storage == REDIS_VM_MEMORY ||
7961 key->storage == REDIS_VM_SWAPPING) {
7962 o = dictGetEntryVal(de);
7963 swapped = 0;
7964 } else {
7965 o = vmPreviewObject(key);
7966 swapped = 1;
7967 }
7968 expiretime = getExpire(db,key);
7969
7970 /* Save the key and associated value */
7971 if (o->type == REDIS_STRING) {
7972 /* Emit a SET command */
7973 char cmd[]="*3\r\n$3\r\nSET\r\n";
7974 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
7975 /* Key and value */
7976 if (fwriteBulkObject(fp,key) == 0) goto werr;
7977 if (fwriteBulkObject(fp,o) == 0) goto werr;
7978 } else if (o->type == REDIS_LIST) {
7979 /* Emit the RPUSHes needed to rebuild the list */
7980 list *list = o->ptr;
7981 listNode *ln;
7982 listIter li;
7983
7984 listRewind(list,&li);
7985 while((ln = listNext(&li))) {
7986 char cmd[]="*3\r\n$5\r\nRPUSH\r\n";
7987 robj *eleobj = listNodeValue(ln);
7988
7989 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
7990 if (fwriteBulkObject(fp,key) == 0) goto werr;
7991 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
7992 }
7993 } else if (o->type == REDIS_SET) {
7994 /* Emit the SADDs needed to rebuild the set */
7995 dict *set = o->ptr;
7996 dictIterator *di = dictGetIterator(set);
7997 dictEntry *de;
7998
7999 while((de = dictNext(di)) != NULL) {
8000 char cmd[]="*3\r\n$4\r\nSADD\r\n";
8001 robj *eleobj = dictGetEntryKey(de);
8002
8003 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
8004 if (fwriteBulkObject(fp,key) == 0) goto werr;
8005 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
8006 }
8007 dictReleaseIterator(di);
8008 } else if (o->type == REDIS_ZSET) {
8009 /* Emit the ZADDs needed to rebuild the sorted set */
8010 zset *zs = o->ptr;
8011 dictIterator *di = dictGetIterator(zs->dict);
8012 dictEntry *de;
8013
8014 while((de = dictNext(di)) != NULL) {
8015 char cmd[]="*4\r\n$4\r\nZADD\r\n";
8016 robj *eleobj = dictGetEntryKey(de);
8017 double *score = dictGetEntryVal(de);
8018
8019 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
8020 if (fwriteBulkObject(fp,key) == 0) goto werr;
8021 if (fwriteBulkDouble(fp,*score) == 0) goto werr;
8022 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
8023 }
8024 dictReleaseIterator(di);
8025 } else if (o->type == REDIS_HASH) {
8026 char cmd[]="*4\r\n$4\r\nHSET\r\n";
8027
8028 /* Emit the HSETs needed to rebuild the hash */
8029 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
8030 unsigned char *p = zipmapRewind(o->ptr);
8031 unsigned char *field, *val;
8032 unsigned int flen, vlen;
8033
8034 while((p = zipmapNext(p,&field,&flen,&val,&vlen)) != NULL) {
8035 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
8036 if (fwriteBulkObject(fp,key) == 0) goto werr;
8037 if (fwriteBulkString(fp,(char*)field,flen) == -1)
8038 return -1;
8039 if (fwriteBulkString(fp,(char*)val,vlen) == -1)
8040 return -1;
8041 }
8042 } else {
8043 dictIterator *di = dictGetIterator(o->ptr);
8044 dictEntry *de;
8045
8046 while((de = dictNext(di)) != NULL) {
8047 robj *field = dictGetEntryKey(de);
8048 robj *val = dictGetEntryVal(de);
8049
8050 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
8051 if (fwriteBulkObject(fp,key) == 0) goto werr;
8052 if (fwriteBulkObject(fp,field) == -1) return -1;
8053 if (fwriteBulkObject(fp,val) == -1) return -1;
8054 }
8055 dictReleaseIterator(di);
8056 }
8057 } else {
8058 redisAssert(0);
8059 }
8060 /* Save the expire time */
8061 if (expiretime != -1) {
8062 char cmd[]="*3\r\n$8\r\nEXPIREAT\r\n";
8063 /* If this key is already expired skip it */
8064 if (expiretime < now) continue;
8065 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
8066 if (fwriteBulkObject(fp,key) == 0) goto werr;
8067 if (fwriteBulkLong(fp,expiretime) == 0) goto werr;
8068 }
8069 if (swapped) decrRefCount(o);
8070 }
8071 dictReleaseIterator(di);
8072 }
8073
8074 /* Make sure data will not remain on the OS's output buffers */
8075 fflush(fp);
8076 fsync(fileno(fp));
8077 fclose(fp);
8078
8079 /* Use RENAME to make sure the DB file is changed atomically only
8080 * if the generate DB file is ok. */
8081 if (rename(tmpfile,filename) == -1) {
8082 redisLog(REDIS_WARNING,"Error moving temp append only file on the final destination: %s", strerror(errno));
8083 unlink(tmpfile);
8084 return REDIS_ERR;
8085 }
8086 redisLog(REDIS_NOTICE,"SYNC append only file rewrite performed");
8087 return REDIS_OK;
8088
8089 werr:
8090 fclose(fp);
8091 unlink(tmpfile);
8092 redisLog(REDIS_WARNING,"Write error writing append only file on disk: %s", strerror(errno));
8093 if (di) dictReleaseIterator(di);
8094 return REDIS_ERR;
8095 }
8096
8097 /* This is how rewriting of the append only file in background works:
8098 *
8099 * 1) The user calls BGREWRITEAOF
8100 * 2) Redis calls this function, that forks():
8101 * 2a) the child rewrite the append only file in a temp file.
8102 * 2b) the parent accumulates differences in server.bgrewritebuf.
8103 * 3) When the child finished '2a' exists.
8104 * 4) The parent will trap the exit code, if it's OK, will append the
8105 * data accumulated into server.bgrewritebuf into the temp file, and
8106 * finally will rename(2) the temp file in the actual file name.
8107 * The the new file is reopened as the new append only file. Profit!
8108 */
8109 static int rewriteAppendOnlyFileBackground(void) {
8110 pid_t childpid;
8111
8112 if (server.bgrewritechildpid != -1) return REDIS_ERR;
8113 if (server.vm_enabled) waitEmptyIOJobsQueue();
8114 if ((childpid = fork()) == 0) {
8115 /* Child */
8116 char tmpfile[256];
8117
8118 if (server.vm_enabled) vmReopenSwapFile();
8119 close(server.fd);
8120 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
8121 if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
8122 _exit(0);
8123 } else {
8124 _exit(1);
8125 }
8126 } else {
8127 /* Parent */
8128 if (childpid == -1) {
8129 redisLog(REDIS_WARNING,
8130 "Can't rewrite append only file in background: fork: %s",
8131 strerror(errno));
8132 return REDIS_ERR;
8133 }
8134 redisLog(REDIS_NOTICE,
8135 "Background append only file rewriting started by pid %d",childpid);
8136 server.bgrewritechildpid = childpid;
8137 updateDictResizePolicy();
8138 /* We set appendseldb to -1 in order to force the next call to the
8139 * feedAppendOnlyFile() to issue a SELECT command, so the differences
8140 * accumulated by the parent into server.bgrewritebuf will start
8141 * with a SELECT statement and it will be safe to merge. */
8142 server.appendseldb = -1;
8143 return REDIS_OK;
8144 }
8145 return REDIS_OK; /* unreached */
8146 }
8147
8148 static void bgrewriteaofCommand(redisClient *c) {
8149 if (server.bgrewritechildpid != -1) {
8150 addReplySds(c,sdsnew("-ERR background append only file rewriting already in progress\r\n"));
8151 return;
8152 }
8153 if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
8154 char *status = "+Background append only file rewriting started\r\n";
8155 addReplySds(c,sdsnew(status));
8156 } else {
8157 addReply(c,shared.err);
8158 }
8159 }
8160
8161 static void aofRemoveTempFile(pid_t childpid) {
8162 char tmpfile[256];
8163
8164 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) childpid);
8165 unlink(tmpfile);
8166 }
8167
8168 /* Virtual Memory is composed mainly of two subsystems:
8169 * - Blocking Virutal Memory
8170 * - Threaded Virtual Memory I/O
8171 * The two parts are not fully decoupled, but functions are split among two
8172 * different sections of the source code (delimited by comments) in order to
8173 * make more clear what functionality is about the blocking VM and what about
8174 * the threaded (not blocking) VM.
8175 *
8176 * Redis VM design:
8177 *
8178 * Redis VM is a blocking VM (one that blocks reading swapped values from
8179 * disk into memory when a value swapped out is needed in memory) that is made
8180 * unblocking by trying to examine the command argument vector in order to
8181 * load in background values that will likely be needed in order to exec
8182 * the command. The command is executed only once all the relevant keys
8183 * are loaded into memory.
8184 *
8185 * This basically is almost as simple of a blocking VM, but almost as parallel
8186 * as a fully non-blocking VM.
8187 */
8188
8189 /* =================== Virtual Memory - Blocking Side ====================== */
8190
8191 /* substitute the first occurrence of '%p' with the process pid in the
8192 * swap file name. */
8193 static void expandVmSwapFilename(void) {
8194 char *p = strstr(server.vm_swap_file,"%p");
8195 sds new;
8196
8197 if (!p) return;
8198 new = sdsempty();
8199 *p = '\0';
8200 new = sdscat(new,server.vm_swap_file);
8201 new = sdscatprintf(new,"%ld",(long) getpid());
8202 new = sdscat(new,p+2);
8203 zfree(server.vm_swap_file);
8204 server.vm_swap_file = new;
8205 }
8206
8207 static void vmInit(void) {
8208 off_t totsize;
8209 int pipefds[2];
8210 size_t stacksize;
8211
8212 if (server.vm_max_threads != 0)
8213 zmalloc_enable_thread_safeness(); /* we need thread safe zmalloc() */
8214
8215 expandVmSwapFilename();
8216 redisLog(REDIS_NOTICE,"Using '%s' as swap file",server.vm_swap_file);
8217 if ((server.vm_fp = fopen(server.vm_swap_file,"r+b")) == NULL) {
8218 server.vm_fp = fopen(server.vm_swap_file,"w+b");
8219 }
8220 if (server.vm_fp == NULL) {
8221 redisLog(REDIS_WARNING,
8222 "Impossible to open the swap file: %s. Exiting.",
8223 strerror(errno));
8224 exit(1);
8225 }
8226 server.vm_fd = fileno(server.vm_fp);
8227 server.vm_next_page = 0;
8228 server.vm_near_pages = 0;
8229 server.vm_stats_used_pages = 0;
8230 server.vm_stats_swapped_objects = 0;
8231 server.vm_stats_swapouts = 0;
8232 server.vm_stats_swapins = 0;
8233 totsize = server.vm_pages*server.vm_page_size;
8234 redisLog(REDIS_NOTICE,"Allocating %lld bytes of swap file",totsize);
8235 if (ftruncate(server.vm_fd,totsize) == -1) {
8236 redisLog(REDIS_WARNING,"Can't ftruncate swap file: %s. Exiting.",
8237 strerror(errno));
8238 exit(1);
8239 } else {
8240 redisLog(REDIS_NOTICE,"Swap file allocated with success");
8241 }
8242 server.vm_bitmap = zmalloc((server.vm_pages+7)/8);
8243 redisLog(REDIS_VERBOSE,"Allocated %lld bytes page table for %lld pages",
8244 (long long) (server.vm_pages+7)/8, server.vm_pages);
8245 memset(server.vm_bitmap,0,(server.vm_pages+7)/8);
8246
8247 /* Initialize threaded I/O (used by Virtual Memory) */
8248 server.io_newjobs = listCreate();
8249 server.io_processing = listCreate();
8250 server.io_processed = listCreate();
8251 server.io_ready_clients = listCreate();
8252 pthread_mutex_init(&server.io_mutex,NULL);
8253 pthread_mutex_init(&server.obj_freelist_mutex,NULL);
8254 pthread_mutex_init(&server.io_swapfile_mutex,NULL);
8255 server.io_active_threads = 0;
8256 if (pipe(pipefds) == -1) {
8257 redisLog(REDIS_WARNING,"Unable to intialized VM: pipe(2): %s. Exiting."
8258 ,strerror(errno));
8259 exit(1);
8260 }
8261 server.io_ready_pipe_read = pipefds[0];
8262 server.io_ready_pipe_write = pipefds[1];
8263 redisAssert(anetNonBlock(NULL,server.io_ready_pipe_read) != ANET_ERR);
8264 /* LZF requires a lot of stack */
8265 pthread_attr_init(&server.io_threads_attr);
8266 pthread_attr_getstacksize(&server.io_threads_attr, &stacksize);
8267 while (stacksize < REDIS_THREAD_STACK_SIZE) stacksize *= 2;
8268 pthread_attr_setstacksize(&server.io_threads_attr, stacksize);
8269 /* Listen for events in the threaded I/O pipe */
8270 if (aeCreateFileEvent(server.el, server.io_ready_pipe_read, AE_READABLE,
8271 vmThreadedIOCompletedJob, NULL) == AE_ERR)
8272 oom("creating file event");
8273 }
8274
8275 /* Mark the page as used */
8276 static void vmMarkPageUsed(off_t page) {
8277 off_t byte = page/8;
8278 int bit = page&7;
8279 redisAssert(vmFreePage(page) == 1);
8280 server.vm_bitmap[byte] |= 1<<bit;
8281 }
8282
8283 /* Mark N contiguous pages as used, with 'page' being the first. */
8284 static void vmMarkPagesUsed(off_t page, off_t count) {
8285 off_t j;
8286
8287 for (j = 0; j < count; j++)
8288 vmMarkPageUsed(page+j);
8289 server.vm_stats_used_pages += count;
8290 redisLog(REDIS_DEBUG,"Mark USED pages: %lld pages at %lld\n",
8291 (long long)count, (long long)page);
8292 }
8293
8294 /* Mark the page as free */
8295 static void vmMarkPageFree(off_t page) {
8296 off_t byte = page/8;
8297 int bit = page&7;
8298 redisAssert(vmFreePage(page) == 0);
8299 server.vm_bitmap[byte] &= ~(1<<bit);
8300 }
8301
8302 /* Mark N contiguous pages as free, with 'page' being the first. */
8303 static void vmMarkPagesFree(off_t page, off_t count) {
8304 off_t j;
8305
8306 for (j = 0; j < count; j++)
8307 vmMarkPageFree(page+j);
8308 server.vm_stats_used_pages -= count;
8309 redisLog(REDIS_DEBUG,"Mark FREE pages: %lld pages at %lld\n",
8310 (long long)count, (long long)page);
8311 }
8312
8313 /* Test if the page is free */
8314 static int vmFreePage(off_t page) {
8315 off_t byte = page/8;
8316 int bit = page&7;
8317 return (server.vm_bitmap[byte] & (1<<bit)) == 0;
8318 }
8319
8320 /* Find N contiguous free pages storing the first page of the cluster in *first.
8321 * Returns REDIS_OK if it was able to find N contiguous pages, otherwise
8322 * REDIS_ERR is returned.
8323 *
8324 * This function uses a simple algorithm: we try to allocate
8325 * REDIS_VM_MAX_NEAR_PAGES sequentially, when we reach this limit we start
8326 * again from the start of the swap file searching for free spaces.
8327 *
8328 * If it looks pretty clear that there are no free pages near our offset
8329 * we try to find less populated places doing a forward jump of
8330 * REDIS_VM_MAX_RANDOM_JUMP, then we start scanning again a few pages
8331 * without hurry, and then we jump again and so forth...
8332 *
8333 * This function can be improved using a free list to avoid to guess
8334 * too much, since we could collect data about freed pages.
8335 *
8336 * note: I implemented this function just after watching an episode of
8337 * Battlestar Galactica, where the hybrid was continuing to say "JUMP!"
8338 */
8339 static int vmFindContiguousPages(off_t *first, off_t n) {
8340 off_t base, offset = 0, since_jump = 0, numfree = 0;
8341
8342 if (server.vm_near_pages == REDIS_VM_MAX_NEAR_PAGES) {
8343 server.vm_near_pages = 0;
8344 server.vm_next_page = 0;
8345 }
8346 server.vm_near_pages++; /* Yet another try for pages near to the old ones */
8347 base = server.vm_next_page;
8348
8349 while(offset < server.vm_pages) {
8350 off_t this = base+offset;
8351
8352 /* If we overflow, restart from page zero */
8353 if (this >= server.vm_pages) {
8354 this -= server.vm_pages;
8355 if (this == 0) {
8356 /* Just overflowed, what we found on tail is no longer
8357 * interesting, as it's no longer contiguous. */
8358 numfree = 0;
8359 }
8360 }
8361 if (vmFreePage(this)) {
8362 /* This is a free page */
8363 numfree++;
8364 /* Already got N free pages? Return to the caller, with success */
8365 if (numfree == n) {
8366 *first = this-(n-1);
8367 server.vm_next_page = this+1;
8368 redisLog(REDIS_DEBUG, "FOUND CONTIGUOUS PAGES: %lld pages at %lld\n", (long long) n, (long long) *first);
8369 return REDIS_OK;
8370 }
8371 } else {
8372 /* The current one is not a free page */
8373 numfree = 0;
8374 }
8375
8376 /* Fast-forward if the current page is not free and we already
8377 * searched enough near this place. */
8378 since_jump++;
8379 if (!numfree && since_jump >= REDIS_VM_MAX_RANDOM_JUMP/4) {
8380 offset += random() % REDIS_VM_MAX_RANDOM_JUMP;
8381 since_jump = 0;
8382 /* Note that even if we rewind after the jump, we are don't need
8383 * to make sure numfree is set to zero as we only jump *if* it
8384 * is set to zero. */
8385 } else {
8386 /* Otherwise just check the next page */
8387 offset++;
8388 }
8389 }
8390 return REDIS_ERR;
8391 }
8392
8393 /* Write the specified object at the specified page of the swap file */
8394 static int vmWriteObjectOnSwap(robj *o, off_t page) {
8395 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
8396 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
8397 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
8398 redisLog(REDIS_WARNING,
8399 "Critical VM problem in vmWriteObjectOnSwap(): can't seek: %s",
8400 strerror(errno));
8401 return REDIS_ERR;
8402 }
8403 rdbSaveObject(server.vm_fp,o);
8404 fflush(server.vm_fp);
8405 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
8406 return REDIS_OK;
8407 }
8408
8409 /* Swap the 'val' object relative to 'key' into disk. Store all the information
8410 * needed to later retrieve the object into the key object.
8411 * If we can't find enough contiguous empty pages to swap the object on disk
8412 * REDIS_ERR is returned. */
8413 static int vmSwapObjectBlocking(robj *key, robj *val) {
8414 off_t pages = rdbSavedObjectPages(val,NULL);
8415 off_t page;
8416
8417 assert(key->storage == REDIS_VM_MEMORY);
8418 assert(key->refcount == 1);
8419 if (vmFindContiguousPages(&page,pages) == REDIS_ERR) return REDIS_ERR;
8420 if (vmWriteObjectOnSwap(val,page) == REDIS_ERR) return REDIS_ERR;
8421 key->vm.page = page;
8422 key->vm.usedpages = pages;
8423 key->storage = REDIS_VM_SWAPPED;
8424 key->vtype = val->type;
8425 decrRefCount(val); /* Deallocate the object from memory. */
8426 vmMarkPagesUsed(page,pages);
8427 redisLog(REDIS_DEBUG,"VM: object %s swapped out at %lld (%lld pages)",
8428 (unsigned char*) key->ptr,
8429 (unsigned long long) page, (unsigned long long) pages);
8430 server.vm_stats_swapped_objects++;
8431 server.vm_stats_swapouts++;
8432 return REDIS_OK;
8433 }
8434
8435 static robj *vmReadObjectFromSwap(off_t page, int type) {
8436 robj *o;
8437
8438 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
8439 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
8440 redisLog(REDIS_WARNING,
8441 "Unrecoverable VM problem in vmReadObjectFromSwap(): can't seek: %s",
8442 strerror(errno));
8443 _exit(1);
8444 }
8445 o = rdbLoadObject(type,server.vm_fp);
8446 if (o == NULL) {
8447 redisLog(REDIS_WARNING, "Unrecoverable VM problem in vmReadObjectFromSwap(): can't load object from swap file: %s", strerror(errno));
8448 _exit(1);
8449 }
8450 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
8451 return o;
8452 }
8453
8454 /* Load the value object relative to the 'key' object from swap to memory.
8455 * The newly allocated object is returned.
8456 *
8457 * If preview is true the unserialized object is returned to the caller but
8458 * no changes are made to the key object, nor the pages are marked as freed */
8459 static robj *vmGenericLoadObject(robj *key, int preview) {
8460 robj *val;
8461
8462 redisAssert(key->storage == REDIS_VM_SWAPPED || key->storage == REDIS_VM_LOADING);
8463 val = vmReadObjectFromSwap(key->vm.page,key->vtype);
8464 if (!preview) {
8465 key->storage = REDIS_VM_MEMORY;
8466 key->vm.atime = server.unixtime;
8467 vmMarkPagesFree(key->vm.page,key->vm.usedpages);
8468 redisLog(REDIS_DEBUG, "VM: object %s loaded from disk",
8469 (unsigned char*) key->ptr);
8470 server.vm_stats_swapped_objects--;
8471 } else {
8472 redisLog(REDIS_DEBUG, "VM: object %s previewed from disk",
8473 (unsigned char*) key->ptr);
8474 }
8475 server.vm_stats_swapins++;
8476 return val;
8477 }
8478
8479 /* Plain object loading, from swap to memory */
8480 static robj *vmLoadObject(robj *key) {
8481 /* If we are loading the object in background, stop it, we
8482 * need to load this object synchronously ASAP. */
8483 if (key->storage == REDIS_VM_LOADING)
8484 vmCancelThreadedIOJob(key);
8485 return vmGenericLoadObject(key,0);
8486 }
8487
8488 /* Just load the value on disk, without to modify the key.
8489 * This is useful when we want to perform some operation on the value
8490 * without to really bring it from swap to memory, like while saving the
8491 * dataset or rewriting the append only log. */
8492 static robj *vmPreviewObject(robj *key) {
8493 return vmGenericLoadObject(key,1);
8494 }
8495
8496 /* How a good candidate is this object for swapping?
8497 * The better candidate it is, the greater the returned value.
8498 *
8499 * Currently we try to perform a fast estimation of the object size in
8500 * memory, and combine it with aging informations.
8501 *
8502 * Basically swappability = idle-time * log(estimated size)
8503 *
8504 * Bigger objects are preferred over smaller objects, but not
8505 * proportionally, this is why we use the logarithm. This algorithm is
8506 * just a first try and will probably be tuned later. */
8507 static double computeObjectSwappability(robj *o) {
8508 time_t age = server.unixtime - o->vm.atime;
8509 long asize = 0;
8510 list *l;
8511 dict *d;
8512 struct dictEntry *de;
8513 int z;
8514
8515 if (age <= 0) return 0;
8516 switch(o->type) {
8517 case REDIS_STRING:
8518 if (o->encoding != REDIS_ENCODING_RAW) {
8519 asize = sizeof(*o);
8520 } else {
8521 asize = sdslen(o->ptr)+sizeof(*o)+sizeof(long)*2;
8522 }
8523 break;
8524 case REDIS_LIST:
8525 l = o->ptr;
8526 listNode *ln = listFirst(l);
8527
8528 asize = sizeof(list);
8529 if (ln) {
8530 robj *ele = ln->value;
8531 long elesize;
8532
8533 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
8534 (sizeof(*o)+sdslen(ele->ptr)) :
8535 sizeof(*o);
8536 asize += (sizeof(listNode)+elesize)*listLength(l);
8537 }
8538 break;
8539 case REDIS_SET:
8540 case REDIS_ZSET:
8541 z = (o->type == REDIS_ZSET);
8542 d = z ? ((zset*)o->ptr)->dict : o->ptr;
8543
8544 asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
8545 if (z) asize += sizeof(zset)-sizeof(dict);
8546 if (dictSize(d)) {
8547 long elesize;
8548 robj *ele;
8549
8550 de = dictGetRandomKey(d);
8551 ele = dictGetEntryKey(de);
8552 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
8553 (sizeof(*o)+sdslen(ele->ptr)) :
8554 sizeof(*o);
8555 asize += (sizeof(struct dictEntry)+elesize)*dictSize(d);
8556 if (z) asize += sizeof(zskiplistNode)*dictSize(d);
8557 }
8558 break;
8559 case REDIS_HASH:
8560 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
8561 unsigned char *p = zipmapRewind((unsigned char*)o->ptr);
8562 unsigned int len = zipmapLen((unsigned char*)o->ptr);
8563 unsigned int klen, vlen;
8564 unsigned char *key, *val;
8565
8566 if ((p = zipmapNext(p,&key,&klen,&val,&vlen)) == NULL) {
8567 klen = 0;
8568 vlen = 0;
8569 }
8570 asize = len*(klen+vlen+3);
8571 } else if (o->encoding == REDIS_ENCODING_HT) {
8572 d = o->ptr;
8573 asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
8574 if (dictSize(d)) {
8575 long elesize;
8576 robj *ele;
8577
8578 de = dictGetRandomKey(d);
8579 ele = dictGetEntryKey(de);
8580 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
8581 (sizeof(*o)+sdslen(ele->ptr)) :
8582 sizeof(*o);
8583 ele = dictGetEntryVal(de);
8584 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
8585 (sizeof(*o)+sdslen(ele->ptr)) :
8586 sizeof(*o);
8587 asize += (sizeof(struct dictEntry)+elesize)*dictSize(d);
8588 }
8589 }
8590 break;
8591 }
8592 return (double)age*log(1+asize);
8593 }
8594
8595 /* Try to swap an object that's a good candidate for swapping.
8596 * Returns REDIS_OK if the object was swapped, REDIS_ERR if it's not possible
8597 * to swap any object at all.
8598 *
8599 * If 'usethreaded' is true, Redis will try to swap the object in background
8600 * using I/O threads. */
8601 static int vmSwapOneObject(int usethreads) {
8602 int j, i;
8603 struct dictEntry *best = NULL;
8604 double best_swappability = 0;
8605 redisDb *best_db = NULL;
8606 robj *key, *val;
8607
8608 for (j = 0; j < server.dbnum; j++) {
8609 redisDb *db = server.db+j;
8610 /* Why maxtries is set to 100?
8611 * Because this way (usually) we'll find 1 object even if just 1% - 2%
8612 * are swappable objects */
8613 int maxtries = 100;
8614
8615 if (dictSize(db->dict) == 0) continue;
8616 for (i = 0; i < 5; i++) {
8617 dictEntry *de;
8618 double swappability;
8619
8620 if (maxtries) maxtries--;
8621 de = dictGetRandomKey(db->dict);
8622 key = dictGetEntryKey(de);
8623 val = dictGetEntryVal(de);
8624 /* Only swap objects that are currently in memory.
8625 *
8626 * Also don't swap shared objects if threaded VM is on, as we
8627 * try to ensure that the main thread does not touch the
8628 * object while the I/O thread is using it, but we can't
8629 * control other keys without adding additional mutex. */
8630 if (key->storage != REDIS_VM_MEMORY ||
8631 (server.vm_max_threads != 0 && val->refcount != 1)) {
8632 if (maxtries) i--; /* don't count this try */
8633 continue;
8634 }
8635 swappability = computeObjectSwappability(val);
8636 if (!best || swappability > best_swappability) {
8637 best = de;
8638 best_swappability = swappability;
8639 best_db = db;
8640 }
8641 }
8642 }
8643 if (best == NULL) return REDIS_ERR;
8644 key = dictGetEntryKey(best);
8645 val = dictGetEntryVal(best);
8646
8647 redisLog(REDIS_DEBUG,"Key with best swappability: %s, %f",
8648 key->ptr, best_swappability);
8649
8650 /* Unshare the key if needed */
8651 if (key->refcount > 1) {
8652 robj *newkey = dupStringObject(key);
8653 decrRefCount(key);
8654 key = dictGetEntryKey(best) = newkey;
8655 }
8656 /* Swap it */
8657 if (usethreads) {
8658 vmSwapObjectThreaded(key,val,best_db);
8659 return REDIS_OK;
8660 } else {
8661 if (vmSwapObjectBlocking(key,val) == REDIS_OK) {
8662 dictGetEntryVal(best) = NULL;
8663 return REDIS_OK;
8664 } else {
8665 return REDIS_ERR;
8666 }
8667 }
8668 }
8669
8670 static int vmSwapOneObjectBlocking() {
8671 return vmSwapOneObject(0);
8672 }
8673
8674 static int vmSwapOneObjectThreaded() {
8675 return vmSwapOneObject(1);
8676 }
8677
8678 /* Return true if it's safe to swap out objects in a given moment.
8679 * Basically we don't want to swap objects out while there is a BGSAVE
8680 * or a BGAEOREWRITE running in backgroud. */
8681 static int vmCanSwapOut(void) {
8682 return (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1);
8683 }
8684
8685 /* Delete a key if swapped. Returns 1 if the key was found, was swapped
8686 * and was deleted. Otherwise 0 is returned. */
8687 static int deleteIfSwapped(redisDb *db, robj *key) {
8688 dictEntry *de;
8689 robj *foundkey;
8690
8691 if ((de = dictFind(db->dict,key)) == NULL) return 0;
8692 foundkey = dictGetEntryKey(de);
8693 if (foundkey->storage == REDIS_VM_MEMORY) return 0;
8694 deleteKey(db,key);
8695 return 1;
8696 }
8697
8698 /* =================== Virtual Memory - Threaded I/O ======================= */
8699
8700 static void freeIOJob(iojob *j) {
8701 if ((j->type == REDIS_IOJOB_PREPARE_SWAP ||
8702 j->type == REDIS_IOJOB_DO_SWAP ||
8703 j->type == REDIS_IOJOB_LOAD) && j->val != NULL)
8704 decrRefCount(j->val);
8705 /* We don't decrRefCount the j->key field as we did't incremented
8706 * the count creating IO Jobs. This is because the key field here is
8707 * just used as an indentifier and if a key is removed the Job should
8708 * never be touched again. */
8709 zfree(j);
8710 }
8711
8712 /* Every time a thread finished a Job, it writes a byte into the write side
8713 * of an unix pipe in order to "awake" the main thread, and this function
8714 * is called. */
8715 static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
8716 int mask)
8717 {
8718 char buf[1];
8719 int retval, processed = 0, toprocess = -1, trytoswap = 1;
8720 REDIS_NOTUSED(el);
8721 REDIS_NOTUSED(mask);
8722 REDIS_NOTUSED(privdata);
8723
8724 /* For every byte we read in the read side of the pipe, there is one
8725 * I/O job completed to process. */
8726 while((retval = read(fd,buf,1)) == 1) {
8727 iojob *j;
8728 listNode *ln;
8729 robj *key;
8730 struct dictEntry *de;
8731
8732 redisLog(REDIS_DEBUG,"Processing I/O completed job");
8733
8734 /* Get the processed element (the oldest one) */
8735 lockThreadedIO();
8736 assert(listLength(server.io_processed) != 0);
8737 if (toprocess == -1) {
8738 toprocess = (listLength(server.io_processed)*REDIS_MAX_COMPLETED_JOBS_PROCESSED)/100;
8739 if (toprocess <= 0) toprocess = 1;
8740 }
8741 ln = listFirst(server.io_processed);
8742 j = ln->value;
8743 listDelNode(server.io_processed,ln);
8744 unlockThreadedIO();
8745 /* If this job is marked as canceled, just ignore it */
8746 if (j->canceled) {
8747 freeIOJob(j);
8748 continue;
8749 }
8750 /* Post process it in the main thread, as there are things we
8751 * can do just here to avoid race conditions and/or invasive locks */
8752 redisLog(REDIS_DEBUG,"Job %p type: %d, key at %p (%s) refcount: %d\n", (void*) j, j->type, (void*)j->key, (char*)j->key->ptr, j->key->refcount);
8753 de = dictFind(j->db->dict,j->key);
8754 assert(de != NULL);
8755 key = dictGetEntryKey(de);
8756 if (j->type == REDIS_IOJOB_LOAD) {
8757 redisDb *db;
8758
8759 /* Key loaded, bring it at home */
8760 key->storage = REDIS_VM_MEMORY;
8761 key->vm.atime = server.unixtime;
8762 vmMarkPagesFree(key->vm.page,key->vm.usedpages);
8763 redisLog(REDIS_DEBUG, "VM: object %s loaded from disk (threaded)",
8764 (unsigned char*) key->ptr);
8765 server.vm_stats_swapped_objects--;
8766 server.vm_stats_swapins++;
8767 dictGetEntryVal(de) = j->val;
8768 incrRefCount(j->val);
8769 db = j->db;
8770 freeIOJob(j);
8771 /* Handle clients waiting for this key to be loaded. */
8772 handleClientsBlockedOnSwappedKey(db,key);
8773 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
8774 /* Now we know the amount of pages required to swap this object.
8775 * Let's find some space for it, and queue this task again
8776 * rebranded as REDIS_IOJOB_DO_SWAP. */
8777 if (!vmCanSwapOut() ||
8778 vmFindContiguousPages(&j->page,j->pages) == REDIS_ERR)
8779 {
8780 /* Ooops... no space or we can't swap as there is
8781 * a fork()ed Redis trying to save stuff on disk. */
8782 freeIOJob(j);
8783 key->storage = REDIS_VM_MEMORY; /* undo operation */
8784 } else {
8785 /* Note that we need to mark this pages as used now,
8786 * if the job will be canceled, we'll mark them as freed
8787 * again. */
8788 vmMarkPagesUsed(j->page,j->pages);
8789 j->type = REDIS_IOJOB_DO_SWAP;
8790 lockThreadedIO();
8791 queueIOJob(j);
8792 unlockThreadedIO();
8793 }
8794 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
8795 robj *val;
8796
8797 /* Key swapped. We can finally free some memory. */
8798 if (key->storage != REDIS_VM_SWAPPING) {
8799 printf("key->storage: %d\n",key->storage);
8800 printf("key->name: %s\n",(char*)key->ptr);
8801 printf("key->refcount: %d\n",key->refcount);
8802 printf("val: %p\n",(void*)j->val);
8803 printf("val->type: %d\n",j->val->type);
8804 printf("val->ptr: %s\n",(char*)j->val->ptr);
8805 }
8806 redisAssert(key->storage == REDIS_VM_SWAPPING);
8807 val = dictGetEntryVal(de);
8808 key->vm.page = j->page;
8809 key->vm.usedpages = j->pages;
8810 key->storage = REDIS_VM_SWAPPED;
8811 key->vtype = j->val->type;
8812 decrRefCount(val); /* Deallocate the object from memory. */
8813 dictGetEntryVal(de) = NULL;
8814 redisLog(REDIS_DEBUG,
8815 "VM: object %s swapped out at %lld (%lld pages) (threaded)",
8816 (unsigned char*) key->ptr,
8817 (unsigned long long) j->page, (unsigned long long) j->pages);
8818 server.vm_stats_swapped_objects++;
8819 server.vm_stats_swapouts++;
8820 freeIOJob(j);
8821 /* Put a few more swap requests in queue if we are still
8822 * out of memory */
8823 if (trytoswap && vmCanSwapOut() &&
8824 zmalloc_used_memory() > server.vm_max_memory)
8825 {
8826 int more = 1;
8827 while(more) {
8828 lockThreadedIO();
8829 more = listLength(server.io_newjobs) <
8830 (unsigned) server.vm_max_threads;
8831 unlockThreadedIO();
8832 /* Don't waste CPU time if swappable objects are rare. */
8833 if (vmSwapOneObjectThreaded() == REDIS_ERR) {
8834 trytoswap = 0;
8835 break;
8836 }
8837 }
8838 }
8839 }
8840 processed++;
8841 if (processed == toprocess) return;
8842 }
8843 if (retval < 0 && errno != EAGAIN) {
8844 redisLog(REDIS_WARNING,
8845 "WARNING: read(2) error in vmThreadedIOCompletedJob() %s",
8846 strerror(errno));
8847 }
8848 }
8849
8850 static void lockThreadedIO(void) {
8851 pthread_mutex_lock(&server.io_mutex);
8852 }
8853
8854 static void unlockThreadedIO(void) {
8855 pthread_mutex_unlock(&server.io_mutex);
8856 }
8857
8858 /* Remove the specified object from the threaded I/O queue if still not
8859 * processed, otherwise make sure to flag it as canceled. */
8860 static void vmCancelThreadedIOJob(robj *o) {
8861 list *lists[3] = {
8862 server.io_newjobs, /* 0 */
8863 server.io_processing, /* 1 */
8864 server.io_processed /* 2 */
8865 };
8866 int i;
8867
8868 assert(o->storage == REDIS_VM_LOADING || o->storage == REDIS_VM_SWAPPING);
8869 again:
8870 lockThreadedIO();
8871 /* Search for a matching key in one of the queues */
8872 for (i = 0; i < 3; i++) {
8873 listNode *ln;
8874 listIter li;
8875
8876 listRewind(lists[i],&li);
8877 while ((ln = listNext(&li)) != NULL) {
8878 iojob *job = ln->value;
8879
8880 if (job->canceled) continue; /* Skip this, already canceled. */
8881 if (job->key == o) {
8882 redisLog(REDIS_DEBUG,"*** CANCELED %p (%s) (type %d) (LIST ID %d)\n",
8883 (void*)job, (char*)o->ptr, job->type, i);
8884 /* Mark the pages as free since the swap didn't happened
8885 * or happened but is now discarded. */
8886 if (i != 1 && job->type == REDIS_IOJOB_DO_SWAP)
8887 vmMarkPagesFree(job->page,job->pages);
8888 /* Cancel the job. It depends on the list the job is
8889 * living in. */
8890 switch(i) {
8891 case 0: /* io_newjobs */
8892 /* If the job was yet not processed the best thing to do
8893 * is to remove it from the queue at all */
8894 freeIOJob(job);
8895 listDelNode(lists[i],ln);
8896 break;
8897 case 1: /* io_processing */
8898 /* Oh Shi- the thread is messing with the Job:
8899 *
8900 * Probably it's accessing the object if this is a
8901 * PREPARE_SWAP or DO_SWAP job.
8902 * If it's a LOAD job it may be reading from disk and
8903 * if we don't wait for the job to terminate before to
8904 * cancel it, maybe in a few microseconds data can be
8905 * corrupted in this pages. So the short story is:
8906 *
8907 * Better to wait for the job to move into the
8908 * next queue (processed)... */
8909
8910 /* We try again and again until the job is completed. */
8911 unlockThreadedIO();
8912 /* But let's wait some time for the I/O thread
8913 * to finish with this job. After all this condition
8914 * should be very rare. */
8915 usleep(1);
8916 goto again;
8917 case 2: /* io_processed */
8918 /* The job was already processed, that's easy...
8919 * just mark it as canceled so that we'll ignore it
8920 * when processing completed jobs. */
8921 job->canceled = 1;
8922 break;
8923 }
8924 /* Finally we have to adjust the storage type of the object
8925 * in order to "UNDO" the operaiton. */
8926 if (o->storage == REDIS_VM_LOADING)
8927 o->storage = REDIS_VM_SWAPPED;
8928 else if (o->storage == REDIS_VM_SWAPPING)
8929 o->storage = REDIS_VM_MEMORY;
8930 unlockThreadedIO();
8931 return;
8932 }
8933 }
8934 }
8935 unlockThreadedIO();
8936 assert(1 != 1); /* We should never reach this */
8937 }
8938
8939 static void *IOThreadEntryPoint(void *arg) {
8940 iojob *j;
8941 listNode *ln;
8942 REDIS_NOTUSED(arg);
8943
8944 pthread_detach(pthread_self());
8945 while(1) {
8946 /* Get a new job to process */
8947 lockThreadedIO();
8948 if (listLength(server.io_newjobs) == 0) {
8949 /* No new jobs in queue, exit. */
8950 redisLog(REDIS_DEBUG,"Thread %ld exiting, nothing to do",
8951 (long) pthread_self());
8952 server.io_active_threads--;
8953 unlockThreadedIO();
8954 return NULL;
8955 }
8956 ln = listFirst(server.io_newjobs);
8957 j = ln->value;
8958 listDelNode(server.io_newjobs,ln);
8959 /* Add the job in the processing queue */
8960 j->thread = pthread_self();
8961 listAddNodeTail(server.io_processing,j);
8962 ln = listLast(server.io_processing); /* We use ln later to remove it */
8963 unlockThreadedIO();
8964 redisLog(REDIS_DEBUG,"Thread %ld got a new job (type %d): %p about key '%s'",
8965 (long) pthread_self(), j->type, (void*)j, (char*)j->key->ptr);
8966
8967 /* Process the Job */
8968 if (j->type == REDIS_IOJOB_LOAD) {
8969 j->val = vmReadObjectFromSwap(j->page,j->key->vtype);
8970 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
8971 FILE *fp = fopen("/dev/null","w+");
8972 j->pages = rdbSavedObjectPages(j->val,fp);
8973 fclose(fp);
8974 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
8975 if (vmWriteObjectOnSwap(j->val,j->page) == REDIS_ERR)
8976 j->canceled = 1;
8977 }
8978
8979 /* Done: insert the job into the processed queue */
8980 redisLog(REDIS_DEBUG,"Thread %ld completed the job: %p (key %s)",
8981 (long) pthread_self(), (void*)j, (char*)j->key->ptr);
8982 lockThreadedIO();
8983 listDelNode(server.io_processing,ln);
8984 listAddNodeTail(server.io_processed,j);
8985 unlockThreadedIO();
8986
8987 /* Signal the main thread there is new stuff to process */
8988 assert(write(server.io_ready_pipe_write,"x",1) == 1);
8989 }
8990 return NULL; /* never reached */
8991 }
8992
8993 static void spawnIOThread(void) {
8994 pthread_t thread;
8995 sigset_t mask, omask;
8996 int err;
8997
8998 sigemptyset(&mask);
8999 sigaddset(&mask,SIGCHLD);
9000 sigaddset(&mask,SIGHUP);
9001 sigaddset(&mask,SIGPIPE);
9002 pthread_sigmask(SIG_SETMASK, &mask, &omask);
9003 while ((err = pthread_create(&thread,&server.io_threads_attr,IOThreadEntryPoint,NULL)) != 0) {
9004 redisLog(REDIS_WARNING,"Unable to spawn an I/O thread: %s",
9005 strerror(err));
9006 usleep(1000000);
9007 }
9008 pthread_sigmask(SIG_SETMASK, &omask, NULL);
9009 server.io_active_threads++;
9010 }
9011
9012 /* We need to wait for the last thread to exit before we are able to
9013 * fork() in order to BGSAVE or BGREWRITEAOF. */
9014 static void waitEmptyIOJobsQueue(void) {
9015 while(1) {
9016 int io_processed_len;
9017
9018 lockThreadedIO();
9019 if (listLength(server.io_newjobs) == 0 &&
9020 listLength(server.io_processing) == 0 &&
9021 server.io_active_threads == 0)
9022 {
9023 unlockThreadedIO();
9024 return;
9025 }
9026 /* While waiting for empty jobs queue condition we post-process some
9027 * finshed job, as I/O threads may be hanging trying to write against
9028 * the io_ready_pipe_write FD but there are so much pending jobs that
9029 * it's blocking. */
9030 io_processed_len = listLength(server.io_processed);
9031 unlockThreadedIO();
9032 if (io_processed_len) {
9033 vmThreadedIOCompletedJob(NULL,server.io_ready_pipe_read,NULL,0);
9034 usleep(1000); /* 1 millisecond */
9035 } else {
9036 usleep(10000); /* 10 milliseconds */
9037 }
9038 }
9039 }
9040
9041 static void vmReopenSwapFile(void) {
9042 /* Note: we don't close the old one as we are in the child process
9043 * and don't want to mess at all with the original file object. */
9044 server.vm_fp = fopen(server.vm_swap_file,"r+b");
9045 if (server.vm_fp == NULL) {
9046 redisLog(REDIS_WARNING,"Can't re-open the VM swap file: %s. Exiting.",
9047 server.vm_swap_file);
9048 _exit(1);
9049 }
9050 server.vm_fd = fileno(server.vm_fp);
9051 }
9052
9053 /* This function must be called while with threaded IO locked */
9054 static void queueIOJob(iojob *j) {
9055 redisLog(REDIS_DEBUG,"Queued IO Job %p type %d about key '%s'\n",
9056 (void*)j, j->type, (char*)j->key->ptr);
9057 listAddNodeTail(server.io_newjobs,j);
9058 if (server.io_active_threads < server.vm_max_threads)
9059 spawnIOThread();
9060 }
9061
9062 static int vmSwapObjectThreaded(robj *key, robj *val, redisDb *db) {
9063 iojob *j;
9064
9065 assert(key->storage == REDIS_VM_MEMORY);
9066 assert(key->refcount == 1);
9067
9068 j = zmalloc(sizeof(*j));
9069 j->type = REDIS_IOJOB_PREPARE_SWAP;
9070 j->db = db;
9071 j->key = key;
9072 j->val = val;
9073 incrRefCount(val);
9074 j->canceled = 0;
9075 j->thread = (pthread_t) -1;
9076 key->storage = REDIS_VM_SWAPPING;
9077
9078 lockThreadedIO();
9079 queueIOJob(j);
9080 unlockThreadedIO();
9081 return REDIS_OK;
9082 }
9083
9084 /* ============ Virtual Memory - Blocking clients on missing keys =========== */
9085
9086 /* This function makes the clinet 'c' waiting for the key 'key' to be loaded.
9087 * If there is not already a job loading the key, it is craeted.
9088 * The key is added to the io_keys list in the client structure, and also
9089 * in the hash table mapping swapped keys to waiting clients, that is,
9090 * server.io_waited_keys. */
9091 static int waitForSwappedKey(redisClient *c, robj *key) {
9092 struct dictEntry *de;
9093 robj *o;
9094 list *l;
9095
9096 /* If the key does not exist or is already in RAM we don't need to
9097 * block the client at all. */
9098 de = dictFind(c->db->dict,key);
9099 if (de == NULL) return 0;
9100 o = dictGetEntryKey(de);
9101 if (o->storage == REDIS_VM_MEMORY) {
9102 return 0;
9103 } else if (o->storage == REDIS_VM_SWAPPING) {
9104 /* We were swapping the key, undo it! */
9105 vmCancelThreadedIOJob(o);
9106 return 0;
9107 }
9108
9109 /* OK: the key is either swapped, or being loaded just now. */
9110
9111 /* Add the key to the list of keys this client is waiting for.
9112 * This maps clients to keys they are waiting for. */
9113 listAddNodeTail(c->io_keys,key);
9114 incrRefCount(key);
9115
9116 /* Add the client to the swapped keys => clients waiting map. */
9117 de = dictFind(c->db->io_keys,key);
9118 if (de == NULL) {
9119 int retval;
9120
9121 /* For every key we take a list of clients blocked for it */
9122 l = listCreate();
9123 retval = dictAdd(c->db->io_keys,key,l);
9124 incrRefCount(key);
9125 assert(retval == DICT_OK);
9126 } else {
9127 l = dictGetEntryVal(de);
9128 }
9129 listAddNodeTail(l,c);
9130
9131 /* Are we already loading the key from disk? If not create a job */
9132 if (o->storage == REDIS_VM_SWAPPED) {
9133 iojob *j;
9134
9135 o->storage = REDIS_VM_LOADING;
9136 j = zmalloc(sizeof(*j));
9137 j->type = REDIS_IOJOB_LOAD;
9138 j->db = c->db;
9139 j->key = o;
9140 j->key->vtype = o->vtype;
9141 j->page = o->vm.page;
9142 j->val = NULL;
9143 j->canceled = 0;
9144 j->thread = (pthread_t) -1;
9145 lockThreadedIO();
9146 queueIOJob(j);
9147 unlockThreadedIO();
9148 }
9149 return 1;
9150 }
9151
9152 /* Preload keys needed for the ZUNION and ZINTER commands. */
9153 static void zunionInterBlockClientOnSwappedKeys(redisClient *c) {
9154 int i, num;
9155 num = atoi(c->argv[2]->ptr);
9156 for (i = 0; i < num; i++) {
9157 waitForSwappedKey(c,c->argv[3+i]);
9158 }
9159 }
9160
9161 /* Is this client attempting to run a command against swapped keys?
9162 * If so, block it ASAP, load the keys in background, then resume it.
9163 *
9164 * The important idea about this function is that it can fail! If keys will
9165 * still be swapped when the client is resumed, this key lookups will
9166 * just block loading keys from disk. In practical terms this should only
9167 * happen with SORT BY command or if there is a bug in this function.
9168 *
9169 * Return 1 if the client is marked as blocked, 0 if the client can
9170 * continue as the keys it is going to access appear to be in memory. */
9171 static int blockClientOnSwappedKeys(struct redisCommand *cmd, redisClient *c) {
9172 int j, last;
9173
9174 if (cmd->vm_preload_proc != NULL) {
9175 cmd->vm_preload_proc(c);
9176 } else {
9177 if (cmd->vm_firstkey == 0) return 0;
9178 last = cmd->vm_lastkey;
9179 if (last < 0) last = c->argc+last;
9180 for (j = cmd->vm_firstkey; j <= last; j += cmd->vm_keystep)
9181 waitForSwappedKey(c,c->argv[j]);
9182 }
9183
9184 /* If the client was blocked for at least one key, mark it as blocked. */
9185 if (listLength(c->io_keys)) {
9186 c->flags |= REDIS_IO_WAIT;
9187 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
9188 server.vm_blocked_clients++;
9189 return 1;
9190 } else {
9191 return 0;
9192 }
9193 }
9194
9195 /* Remove the 'key' from the list of blocked keys for a given client.
9196 *
9197 * The function returns 1 when there are no longer blocking keys after
9198 * the current one was removed (and the client can be unblocked). */
9199 static int dontWaitForSwappedKey(redisClient *c, robj *key) {
9200 list *l;
9201 listNode *ln;
9202 listIter li;
9203 struct dictEntry *de;
9204
9205 /* Remove the key from the list of keys this client is waiting for. */
9206 listRewind(c->io_keys,&li);
9207 while ((ln = listNext(&li)) != NULL) {
9208 if (compareStringObjects(ln->value,key) == 0) {
9209 listDelNode(c->io_keys,ln);
9210 break;
9211 }
9212 }
9213 assert(ln != NULL);
9214
9215 /* Remove the client form the key => waiting clients map. */
9216 de = dictFind(c->db->io_keys,key);
9217 assert(de != NULL);
9218 l = dictGetEntryVal(de);
9219 ln = listSearchKey(l,c);
9220 assert(ln != NULL);
9221 listDelNode(l,ln);
9222 if (listLength(l) == 0)
9223 dictDelete(c->db->io_keys,key);
9224
9225 return listLength(c->io_keys) == 0;
9226 }
9227
9228 static void handleClientsBlockedOnSwappedKey(redisDb *db, robj *key) {
9229 struct dictEntry *de;
9230 list *l;
9231 listNode *ln;
9232 int len;
9233
9234 de = dictFind(db->io_keys,key);
9235 if (!de) return;
9236
9237 l = dictGetEntryVal(de);
9238 len = listLength(l);
9239 /* Note: we can't use something like while(listLength(l)) as the list
9240 * can be freed by the calling function when we remove the last element. */
9241 while (len--) {
9242 ln = listFirst(l);
9243 redisClient *c = ln->value;
9244
9245 if (dontWaitForSwappedKey(c,key)) {
9246 /* Put the client in the list of clients ready to go as we
9247 * loaded all the keys about it. */
9248 listAddNodeTail(server.io_ready_clients,c);
9249 }
9250 }
9251 }
9252
9253 /* =========================== Remote Configuration ========================= */
9254
9255 static void configSetCommand(redisClient *c) {
9256 robj *o = getDecodedObject(c->argv[3]);
9257 if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) {
9258 zfree(server.dbfilename);
9259 server.dbfilename = zstrdup(o->ptr);
9260 } else if (!strcasecmp(c->argv[2]->ptr,"requirepass")) {
9261 zfree(server.requirepass);
9262 server.requirepass = zstrdup(o->ptr);
9263 } else if (!strcasecmp(c->argv[2]->ptr,"masterauth")) {
9264 zfree(server.masterauth);
9265 server.masterauth = zstrdup(o->ptr);
9266 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory")) {
9267 server.maxmemory = strtoll(o->ptr, NULL, 10);
9268 } else {
9269 addReplySds(c,sdscatprintf(sdsempty(),
9270 "-ERR not supported CONFIG parameter %s\r\n",
9271 (char*)c->argv[2]->ptr));
9272 decrRefCount(o);
9273 return;
9274 }
9275 decrRefCount(o);
9276 addReply(c,shared.ok);
9277 }
9278
9279 static void configGetCommand(redisClient *c) {
9280 robj *o = getDecodedObject(c->argv[2]);
9281 robj *lenobj = createObject(REDIS_STRING,NULL);
9282 char *pattern = o->ptr;
9283 int matches = 0;
9284
9285 addReply(c,lenobj);
9286 decrRefCount(lenobj);
9287
9288 if (stringmatch(pattern,"dbfilename",0)) {
9289 addReplyBulkCString(c,"dbfilename");
9290 addReplyBulkCString(c,server.dbfilename);
9291 matches++;
9292 }
9293 if (stringmatch(pattern,"requirepass",0)) {
9294 addReplyBulkCString(c,"requirepass");
9295 addReplyBulkCString(c,server.requirepass);
9296 matches++;
9297 }
9298 if (stringmatch(pattern,"masterauth",0)) {
9299 addReplyBulkCString(c,"masterauth");
9300 addReplyBulkCString(c,server.masterauth);
9301 matches++;
9302 }
9303 if (stringmatch(pattern,"maxmemory",0)) {
9304 char buf[128];
9305
9306 snprintf(buf,128,"%llu\n",server.maxmemory);
9307 addReplyBulkCString(c,"maxmemory");
9308 addReplyBulkCString(c,buf);
9309 matches++;
9310 }
9311 decrRefCount(o);
9312 lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",matches*2);
9313 }
9314
9315 static void configCommand(redisClient *c) {
9316 if (!strcasecmp(c->argv[1]->ptr,"set")) {
9317 if (c->argc != 4) goto badarity;
9318 configSetCommand(c);
9319 } else if (!strcasecmp(c->argv[1]->ptr,"get")) {
9320 if (c->argc != 3) goto badarity;
9321 configGetCommand(c);
9322 } else if (!strcasecmp(c->argv[1]->ptr,"resetstat")) {
9323 if (c->argc != 2) goto badarity;
9324 server.stat_numcommands = 0;
9325 server.stat_numconnections = 0;
9326 server.stat_expiredkeys = 0;
9327 server.stat_starttime = time(NULL);
9328 addReply(c,shared.ok);
9329 } else {
9330 addReplySds(c,sdscatprintf(sdsempty(),
9331 "-ERR CONFIG subcommand must be one of GET, SET, RESETSTAT\r\n"));
9332 }
9333 return;
9334
9335 badarity:
9336 addReplySds(c,sdscatprintf(sdsempty(),
9337 "-ERR Wrong number of arguments for CONFIG %s\r\n",
9338 (char*) c->argv[1]->ptr));
9339 }
9340
9341 /* =========================== Pubsub implementation ======================== */
9342
9343 static void freePubsubPattern(void *p) {
9344 pubsubPattern *pat = p;
9345
9346 decrRefCount(pat->pattern);
9347 zfree(pat);
9348 }
9349
9350 static int listMatchPubsubPattern(void *a, void *b) {
9351 pubsubPattern *pa = a, *pb = b;
9352
9353 return (pa->client == pb->client) &&
9354 (compareStringObjects(pa->pattern,pb->pattern) == 0);
9355 }
9356
9357 /* Subscribe a client to a channel. Returns 1 if the operation succeeded, or
9358 * 0 if the client was already subscribed to that channel. */
9359 static int pubsubSubscribeChannel(redisClient *c, robj *channel) {
9360 struct dictEntry *de;
9361 list *clients = NULL;
9362 int retval = 0;
9363
9364 /* Add the channel to the client -> channels hash table */
9365 if (dictAdd(c->pubsub_channels,channel,NULL) == DICT_OK) {
9366 retval = 1;
9367 incrRefCount(channel);
9368 /* Add the client to the channel -> list of clients hash table */
9369 de = dictFind(server.pubsub_channels,channel);
9370 if (de == NULL) {
9371 clients = listCreate();
9372 dictAdd(server.pubsub_channels,channel,clients);
9373 incrRefCount(channel);
9374 } else {
9375 clients = dictGetEntryVal(de);
9376 }
9377 listAddNodeTail(clients,c);
9378 }
9379 /* Notify the client */
9380 addReply(c,shared.mbulk3);
9381 addReply(c,shared.subscribebulk);
9382 addReplyBulk(c,channel);
9383 addReplyLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns));
9384 return retval;
9385 }
9386
9387 /* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
9388 * 0 if the client was not subscribed to the specified channel. */
9389 static int pubsubUnsubscribeChannel(redisClient *c, robj *channel, int notify) {
9390 struct dictEntry *de;
9391 list *clients;
9392 listNode *ln;
9393 int retval = 0;
9394
9395 /* Remove the channel from the client -> channels hash table */
9396 incrRefCount(channel); /* channel may be just a pointer to the same object
9397 we have in the hash tables. Protect it... */
9398 if (dictDelete(c->pubsub_channels,channel) == DICT_OK) {
9399 retval = 1;
9400 /* Remove the client from the channel -> clients list hash table */
9401 de = dictFind(server.pubsub_channels,channel);
9402 assert(de != NULL);
9403 clients = dictGetEntryVal(de);
9404 ln = listSearchKey(clients,c);
9405 assert(ln != NULL);
9406 listDelNode(clients,ln);
9407 if (listLength(clients) == 0) {
9408 /* Free the list and associated hash entry at all if this was
9409 * the latest client, so that it will be possible to abuse
9410 * Redis PUBSUB creating millions of channels. */
9411 dictDelete(server.pubsub_channels,channel);
9412 }
9413 }
9414 /* Notify the client */
9415 if (notify) {
9416 addReply(c,shared.mbulk3);
9417 addReply(c,shared.unsubscribebulk);
9418 addReplyBulk(c,channel);
9419 addReplyLong(c,dictSize(c->pubsub_channels)+
9420 listLength(c->pubsub_patterns));
9421
9422 }
9423 decrRefCount(channel); /* it is finally safe to release it */
9424 return retval;
9425 }
9426
9427 /* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the clinet was already subscribed to that pattern. */
9428 static int pubsubSubscribePattern(redisClient *c, robj *pattern) {
9429 int retval = 0;
9430
9431 if (listSearchKey(c->pubsub_patterns,pattern) == NULL) {
9432 retval = 1;
9433 pubsubPattern *pat;
9434 listAddNodeTail(c->pubsub_patterns,pattern);
9435 incrRefCount(pattern);
9436 pat = zmalloc(sizeof(*pat));
9437 pat->pattern = getDecodedObject(pattern);
9438 pat->client = c;
9439 listAddNodeTail(server.pubsub_patterns,pat);
9440 }
9441 /* Notify the client */
9442 addReply(c,shared.mbulk3);
9443 addReply(c,shared.psubscribebulk);
9444 addReplyBulk(c,pattern);
9445 addReplyLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns));
9446 return retval;
9447 }
9448
9449 /* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
9450 * 0 if the client was not subscribed to the specified channel. */
9451 static int pubsubUnsubscribePattern(redisClient *c, robj *pattern, int notify) {
9452 listNode *ln;
9453 pubsubPattern pat;
9454 int retval = 0;
9455
9456 incrRefCount(pattern); /* Protect the object. May be the same we remove */
9457 if ((ln = listSearchKey(c->pubsub_patterns,pattern)) != NULL) {
9458 retval = 1;
9459 listDelNode(c->pubsub_patterns,ln);
9460 pat.client = c;
9461 pat.pattern = pattern;
9462 ln = listSearchKey(server.pubsub_patterns,&pat);
9463 listDelNode(server.pubsub_patterns,ln);
9464 }
9465 /* Notify the client */
9466 if (notify) {
9467 addReply(c,shared.mbulk3);
9468 addReply(c,shared.punsubscribebulk);
9469 addReplyBulk(c,pattern);
9470 addReplyLong(c,dictSize(c->pubsub_channels)+
9471 listLength(c->pubsub_patterns));
9472 }
9473 decrRefCount(pattern);
9474 return retval;
9475 }
9476
9477 /* Unsubscribe from all the channels. Return the number of channels the
9478 * client was subscribed from. */
9479 static int pubsubUnsubscribeAllChannels(redisClient *c, int notify) {
9480 dictIterator *di = dictGetIterator(c->pubsub_channels);
9481 dictEntry *de;
9482 int count = 0;
9483
9484 while((de = dictNext(di)) != NULL) {
9485 robj *channel = dictGetEntryKey(de);
9486
9487 count += pubsubUnsubscribeChannel(c,channel,notify);
9488 }
9489 dictReleaseIterator(di);
9490 return count;
9491 }
9492
9493 /* Unsubscribe from all the patterns. Return the number of patterns the
9494 * client was subscribed from. */
9495 static int pubsubUnsubscribeAllPatterns(redisClient *c, int notify) {
9496 listNode *ln;
9497 listIter li;
9498 int count = 0;
9499
9500 listRewind(c->pubsub_patterns,&li);
9501 while ((ln = listNext(&li)) != NULL) {
9502 robj *pattern = ln->value;
9503
9504 count += pubsubUnsubscribePattern(c,pattern,notify);
9505 }
9506 return count;
9507 }
9508
9509 /* Publish a message */
9510 static int pubsubPublishMessage(robj *channel, robj *message) {
9511 int receivers = 0;
9512 struct dictEntry *de;
9513 listNode *ln;
9514 listIter li;
9515
9516 /* Send to clients listening for that channel */
9517 de = dictFind(server.pubsub_channels,channel);
9518 if (de) {
9519 list *list = dictGetEntryVal(de);
9520 listNode *ln;
9521 listIter li;
9522
9523 listRewind(list,&li);
9524 while ((ln = listNext(&li)) != NULL) {
9525 redisClient *c = ln->value;
9526
9527 addReply(c,shared.mbulk3);
9528 addReply(c,shared.messagebulk);
9529 addReplyBulk(c,channel);
9530 addReplyBulk(c,message);
9531 receivers++;
9532 }
9533 }
9534 /* Send to clients listening to matching channels */
9535 if (listLength(server.pubsub_patterns)) {
9536 listRewind(server.pubsub_patterns,&li);
9537 channel = getDecodedObject(channel);
9538 while ((ln = listNext(&li)) != NULL) {
9539 pubsubPattern *pat = ln->value;
9540
9541 if (stringmatchlen((char*)pat->pattern->ptr,
9542 sdslen(pat->pattern->ptr),
9543 (char*)channel->ptr,
9544 sdslen(channel->ptr),0)) {
9545 addReply(pat->client,shared.mbulk3);
9546 addReply(pat->client,shared.messagebulk);
9547 addReplyBulk(pat->client,channel);
9548 addReplyBulk(pat->client,message);
9549 receivers++;
9550 }
9551 }
9552 decrRefCount(channel);
9553 }
9554 return receivers;
9555 }
9556
9557 static void subscribeCommand(redisClient *c) {
9558 int j;
9559
9560 for (j = 1; j < c->argc; j++)
9561 pubsubSubscribeChannel(c,c->argv[j]);
9562 }
9563
9564 static void unsubscribeCommand(redisClient *c) {
9565 if (c->argc == 1) {
9566 pubsubUnsubscribeAllChannels(c,1);
9567 return;
9568 } else {
9569 int j;
9570
9571 for (j = 1; j < c->argc; j++)
9572 pubsubUnsubscribeChannel(c,c->argv[j],1);
9573 }
9574 }
9575
9576 static void psubscribeCommand(redisClient *c) {
9577 int j;
9578
9579 for (j = 1; j < c->argc; j++)
9580 pubsubSubscribePattern(c,c->argv[j]);
9581 }
9582
9583 static void punsubscribeCommand(redisClient *c) {
9584 if (c->argc == 1) {
9585 pubsubUnsubscribeAllPatterns(c,1);
9586 return;
9587 } else {
9588 int j;
9589
9590 for (j = 1; j < c->argc; j++)
9591 pubsubUnsubscribePattern(c,c->argv[j],1);
9592 }
9593 }
9594
9595 static void publishCommand(redisClient *c) {
9596 int receivers = pubsubPublishMessage(c->argv[1],c->argv[2]);
9597 addReplyLong(c,receivers);
9598 }
9599
9600 /* ================================= Debugging ============================== */
9601
9602 static void debugCommand(redisClient *c) {
9603 if (!strcasecmp(c->argv[1]->ptr,"segfault")) {
9604 *((char*)-1) = 'x';
9605 } else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
9606 if (rdbSave(server.dbfilename) != REDIS_OK) {
9607 addReply(c,shared.err);
9608 return;
9609 }
9610 emptyDb();
9611 if (rdbLoad(server.dbfilename) != REDIS_OK) {
9612 addReply(c,shared.err);
9613 return;
9614 }
9615 redisLog(REDIS_WARNING,"DB reloaded by DEBUG RELOAD");
9616 addReply(c,shared.ok);
9617 } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) {
9618 emptyDb();
9619 if (loadAppendOnlyFile(server.appendfilename) != REDIS_OK) {
9620 addReply(c,shared.err);
9621 return;
9622 }
9623 redisLog(REDIS_WARNING,"Append Only File loaded by DEBUG LOADAOF");
9624 addReply(c,shared.ok);
9625 } else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
9626 dictEntry *de = dictFind(c->db->dict,c->argv[2]);
9627 robj *key, *val;
9628
9629 if (!de) {
9630 addReply(c,shared.nokeyerr);
9631 return;
9632 }
9633 key = dictGetEntryKey(de);
9634 val = dictGetEntryVal(de);
9635 if (!server.vm_enabled || (key->storage == REDIS_VM_MEMORY ||
9636 key->storage == REDIS_VM_SWAPPING)) {
9637 char *strenc;
9638 char buf[128];
9639
9640 if (val->encoding < (sizeof(strencoding)/sizeof(char*))) {
9641 strenc = strencoding[val->encoding];
9642 } else {
9643 snprintf(buf,64,"unknown encoding %d\n", val->encoding);
9644 strenc = buf;
9645 }
9646 addReplySds(c,sdscatprintf(sdsempty(),
9647 "+Key at:%p refcount:%d, value at:%p refcount:%d "
9648 "encoding:%s serializedlength:%lld\r\n",
9649 (void*)key, key->refcount, (void*)val, val->refcount,
9650 strenc, (long long) rdbSavedObjectLen(val,NULL)));
9651 } else {
9652 addReplySds(c,sdscatprintf(sdsempty(),
9653 "+Key at:%p refcount:%d, value swapped at: page %llu "
9654 "using %llu pages\r\n",
9655 (void*)key, key->refcount, (unsigned long long) key->vm.page,
9656 (unsigned long long) key->vm.usedpages));
9657 }
9658 } else if (!strcasecmp(c->argv[1]->ptr,"swapin") && c->argc == 3) {
9659 lookupKeyRead(c->db,c->argv[2]);
9660 addReply(c,shared.ok);
9661 } else if (!strcasecmp(c->argv[1]->ptr,"swapout") && c->argc == 3) {
9662 dictEntry *de = dictFind(c->db->dict,c->argv[2]);
9663 robj *key, *val;
9664
9665 if (!server.vm_enabled) {
9666 addReplySds(c,sdsnew("-ERR Virtual Memory is disabled\r\n"));
9667 return;
9668 }
9669 if (!de) {
9670 addReply(c,shared.nokeyerr);
9671 return;
9672 }
9673 key = dictGetEntryKey(de);
9674 val = dictGetEntryVal(de);
9675 /* If the key is shared we want to create a copy */
9676 if (key->refcount > 1) {
9677 robj *newkey = dupStringObject(key);
9678 decrRefCount(key);
9679 key = dictGetEntryKey(de) = newkey;
9680 }
9681 /* Swap it */
9682 if (key->storage != REDIS_VM_MEMORY) {
9683 addReplySds(c,sdsnew("-ERR This key is not in memory\r\n"));
9684 } else if (vmSwapObjectBlocking(key,val) == REDIS_OK) {
9685 dictGetEntryVal(de) = NULL;
9686 addReply(c,shared.ok);
9687 } else {
9688 addReply(c,shared.err);
9689 }
9690 } else {
9691 addReplySds(c,sdsnew(
9692 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPIN <key<|SWAPOUT <key>|RELOAD]\r\n"));
9693 }
9694 }
9695
9696 static void _redisAssert(char *estr, char *file, int line) {
9697 redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
9698 redisLog(REDIS_WARNING,"==> %s:%d '%s' is not true\n",file,line,estr);
9699 #ifdef HAVE_BACKTRACE
9700 redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
9701 *((char*)-1) = 'x';
9702 #endif
9703 }
9704
9705 /* =================================== Main! ================================ */
9706
9707 #ifdef __linux__
9708 int linuxOvercommitMemoryValue(void) {
9709 FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
9710 char buf[64];
9711
9712 if (!fp) return -1;
9713 if (fgets(buf,64,fp) == NULL) {
9714 fclose(fp);
9715 return -1;
9716 }
9717 fclose(fp);
9718
9719 return atoi(buf);
9720 }
9721
9722 void linuxOvercommitMemoryWarning(void) {
9723 if (linuxOvercommitMemoryValue() == 0) {
9724 redisLog(REDIS_WARNING,"WARNING overcommit_memory is set to 0! Background save may fail under low condition memory. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.");
9725 }
9726 }
9727 #endif /* __linux__ */
9728
9729 static void daemonize(void) {
9730 int fd;
9731 FILE *fp;
9732
9733 if (fork() != 0) exit(0); /* parent exits */
9734 setsid(); /* create a new session */
9735
9736 /* Every output goes to /dev/null. If Redis is daemonized but
9737 * the 'logfile' is set to 'stdout' in the configuration file
9738 * it will not log at all. */
9739 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
9740 dup2(fd, STDIN_FILENO);
9741 dup2(fd, STDOUT_FILENO);
9742 dup2(fd, STDERR_FILENO);
9743 if (fd > STDERR_FILENO) close(fd);
9744 }
9745 /* Try to write the pid file */
9746 fp = fopen(server.pidfile,"w");
9747 if (fp) {
9748 fprintf(fp,"%d\n",getpid());
9749 fclose(fp);
9750 }
9751 }
9752
9753 static void version() {
9754 printf("Redis server version %s\n", REDIS_VERSION);
9755 exit(0);
9756 }
9757
9758 static void usage() {
9759 fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
9760 fprintf(stderr," ./redis-server - (read config from stdin)\n");
9761 exit(1);
9762 }
9763
9764 int main(int argc, char **argv) {
9765 time_t start;
9766
9767 initServerConfig();
9768 if (argc == 2) {
9769 if (strcmp(argv[1], "-v") == 0 ||
9770 strcmp(argv[1], "--version") == 0) version();
9771 if (strcmp(argv[1], "--help") == 0) usage();
9772 resetServerSaveParams();
9773 loadServerConfig(argv[1]);
9774 } else if ((argc > 2)) {
9775 usage();
9776 } else {
9777 redisLog(REDIS_WARNING,"Warning: no config file specified, using the default config. In order to specify a config file use 'redis-server /path/to/redis.conf'");
9778 }
9779 if (server.daemonize) daemonize();
9780 initServer();
9781 redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
9782 #ifdef __linux__
9783 linuxOvercommitMemoryWarning();
9784 #endif
9785 start = time(NULL);
9786 if (server.appendonly) {
9787 if (loadAppendOnlyFile(server.appendfilename) == REDIS_OK)
9788 redisLog(REDIS_NOTICE,"DB loaded from append only file: %ld seconds",time(NULL)-start);
9789 } else {
9790 if (rdbLoad(server.dbfilename) == REDIS_OK)
9791 redisLog(REDIS_NOTICE,"DB loaded from disk: %ld seconds",time(NULL)-start);
9792 }
9793 redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
9794 aeSetBeforeSleepProc(server.el,beforeSleep);
9795 aeMain(server.el);
9796 aeDeleteEventLoop(server.el);
9797 return 0;
9798 }
9799
9800 /* ============================= Backtrace support ========================= */
9801
9802 #ifdef HAVE_BACKTRACE
9803 static char *findFuncName(void *pointer, unsigned long *offset);
9804
9805 static void *getMcontextEip(ucontext_t *uc) {
9806 #if defined(__FreeBSD__)
9807 return (void*) uc->uc_mcontext.mc_eip;
9808 #elif defined(__dietlibc__)
9809 return (void*) uc->uc_mcontext.eip;
9810 #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
9811 #if __x86_64__
9812 return (void*) uc->uc_mcontext->__ss.__rip;
9813 #else
9814 return (void*) uc->uc_mcontext->__ss.__eip;
9815 #endif
9816 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
9817 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
9818 return (void*) uc->uc_mcontext->__ss.__rip;
9819 #else
9820 return (void*) uc->uc_mcontext->__ss.__eip;
9821 #endif
9822 #elif defined(__i386__) || defined(__X86_64__) || defined(__x86_64__)
9823 return (void*) uc->uc_mcontext.gregs[REG_EIP]; /* Linux 32/64 bit */
9824 #elif defined(__ia64__) /* Linux IA64 */
9825 return (void*) uc->uc_mcontext.sc_ip;
9826 #else
9827 return NULL;
9828 #endif
9829 }
9830
9831 static void segvHandler(int sig, siginfo_t *info, void *secret) {
9832 void *trace[100];
9833 char **messages = NULL;
9834 int i, trace_size = 0;
9835 unsigned long offset=0;
9836 ucontext_t *uc = (ucontext_t*) secret;
9837 sds infostring;
9838 REDIS_NOTUSED(info);
9839
9840 redisLog(REDIS_WARNING,
9841 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION, sig);
9842 infostring = genRedisInfoString();
9843 redisLog(REDIS_WARNING, "%s",infostring);
9844 /* It's not safe to sdsfree() the returned string under memory
9845 * corruption conditions. Let it leak as we are going to abort */
9846
9847 trace_size = backtrace(trace, 100);
9848 /* overwrite sigaction with caller's address */
9849 if (getMcontextEip(uc) != NULL) {
9850 trace[1] = getMcontextEip(uc);
9851 }
9852 messages = backtrace_symbols(trace, trace_size);
9853
9854 for (i=1; i<trace_size; ++i) {
9855 char *fn = findFuncName(trace[i], &offset), *p;
9856
9857 p = strchr(messages[i],'+');
9858 if (!fn || (p && ((unsigned long)strtol(p+1,NULL,10)) < offset)) {
9859 redisLog(REDIS_WARNING,"%s", messages[i]);
9860 } else {
9861 redisLog(REDIS_WARNING,"%d redis-server %p %s + %d", i, trace[i], fn, (unsigned int)offset);
9862 }
9863 }
9864 /* free(messages); Don't call free() with possibly corrupted memory. */
9865 _exit(0);
9866 }
9867
9868 static void setupSigSegvAction(void) {
9869 struct sigaction act;
9870
9871 sigemptyset (&act.sa_mask);
9872 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
9873 * is used. Otherwise, sa_handler is used */
9874 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
9875 act.sa_sigaction = segvHandler;
9876 sigaction (SIGSEGV, &act, NULL);
9877 sigaction (SIGBUS, &act, NULL);
9878 sigaction (SIGFPE, &act, NULL);
9879 sigaction (SIGILL, &act, NULL);
9880 sigaction (SIGBUS, &act, NULL);
9881 return;
9882 }
9883
9884 #include "staticsymbols.h"
9885 /* This function try to convert a pointer into a function name. It's used in
9886 * oreder to provide a backtrace under segmentation fault that's able to
9887 * display functions declared as static (otherwise the backtrace is useless). */
9888 static char *findFuncName(void *pointer, unsigned long *offset){
9889 int i, ret = -1;
9890 unsigned long off, minoff = 0;
9891
9892 /* Try to match against the Symbol with the smallest offset */
9893 for (i=0; symsTable[i].pointer; i++) {
9894 unsigned long lp = (unsigned long) pointer;
9895
9896 if (lp != (unsigned long)-1 && lp >= symsTable[i].pointer) {
9897 off=lp-symsTable[i].pointer;
9898 if (ret < 0 || off < minoff) {
9899 minoff=off;
9900 ret=i;
9901 }
9902 }
9903 }
9904 if (ret == -1) return NULL;
9905 *offset = minoff;
9906 return symsTable[ret].name;
9907 }
9908 #else /* HAVE_BACKTRACE */
9909 static void setupSigSegvAction(void) {
9910 }
9911 #endif /* HAVE_BACKTRACE */
9912
9913
9914
9915 /* The End */
9916
9917
9918