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