]> git.saurik.com Git - redis.git/blame - redis.c
intset encoding for sets, refactored set tests to test both encodings
[redis.git] / redis.c
CommitLineData
ed9b544e 1/*
12d090d2 2 * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
ed9b544e 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
9005896c 30#define REDIS_VERSION "2.1.1"
23d4709d 31
32#include "fmacros.h"
fbf9bcdb 33#include "config.h"
ed9b544e 34
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <time.h>
39#include <unistd.h>
40#include <signal.h>
fbf9bcdb 41
42#ifdef HAVE_BACKTRACE
c9468bcf 43#include <execinfo.h>
44#include <ucontext.h>
fbf9bcdb 45#endif /* HAVE_BACKTRACE */
46
ed9b544e 47#include <sys/wait.h>
48#include <errno.h>
49#include <assert.h>
50#include <ctype.h>
51#include <stdarg.h>
52#include <inttypes.h>
53#include <arpa/inet.h>
54#include <sys/stat.h>
55#include <fcntl.h>
56#include <sys/time.h>
57#include <sys/resource.h>
2895e862 58#include <sys/uio.h>
f78fd11b 59#include <limits.h>
fb82e75c 60#include <float.h>
a7866db6 61#include <math.h>
92f8e882 62#include <pthread.h>
0bc1b2f6 63
64#if defined(__sun)
5043dff3 65#include "solarisfixes.h"
66#endif
ed9b544e 67
c9468bcf 68#include "redis.h"
ed9b544e 69#include "ae.h" /* Event driven programming library */
70#include "sds.h" /* Dynamic safe strings */
71#include "anet.h" /* Networking the easy way */
72#include "dict.h" /* Hash tables */
73#include "adlist.h" /* Linked lists */
74#include "zmalloc.h" /* total memory usage aware version of malloc/free */
5f5b9840 75#include "lzf.h" /* LZF compression library */
76#include "pqsort.h" /* Partial qsort for SORT+LIMIT */
ba798261 77#include "zipmap.h" /* Compact dictionary-alike data structure */
c7d9d662 78#include "ziplist.h" /* Compact list data structure */
d0b58d53 79#include "intset.h" /* Compact integer set structure */
ba798261 80#include "sha1.h" /* SHA1 is used for DEBUG DIGEST */
5436146c 81#include "release.h" /* Release and/or git repository information */
ed9b544e 82
83/* Error codes */
84#define REDIS_OK 0
85#define REDIS_ERR -1
86
87/* Static server configuration */
88#define REDIS_SERVERPORT 6379 /* TCP port */
89#define REDIS_MAXIDLETIME (60*5) /* default client timeout */
6208b3a7 90#define REDIS_IOBUF_LEN 1024
ed9b544e 91#define REDIS_LOADBUF_LEN 1024
248ea310 92#define REDIS_STATIC_ARGS 8
ed9b544e 93#define REDIS_DEFAULT_DBNUM 16
94#define REDIS_CONFIGLINE_MAX 1024
95#define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
96#define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
8ca3e9d1 97#define REDIS_EXPIRELOOKUPS_PER_CRON 10 /* lookup 10 expires per loop */
6f376729 98#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
2895e862 99#define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
100
101/* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
102#define REDIS_WRITEV_THRESHOLD 3
103/* Max number of iovecs used for each writev call */
104#define REDIS_WRITEV_IOVEC_COUNT 256
ed9b544e 105
106/* Hash table parameters */
107#define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
ed9b544e 108
109/* Command flags */
3fd78bcd 110#define REDIS_CMD_BULK 1 /* Bulk write command */
111#define REDIS_CMD_INLINE 2 /* Inline command */
112/* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
113 this flags will return an error when the 'maxmemory' option is set in the
114 config file and the server is using more than maxmemory bytes of memory.
115 In short this commands are denied on low memory conditions. */
116#define REDIS_CMD_DENYOOM 4
4005fef1 117#define REDIS_CMD_FORCE_REPLICATION 8 /* Force replication even if dirty is 0 */
ed9b544e 118
119/* Object types */
120#define REDIS_STRING 0
121#define REDIS_LIST 1
122#define REDIS_SET 2
1812e024 123#define REDIS_ZSET 3
124#define REDIS_HASH 4
560db612 125#define REDIS_VMPOINTER 8
f78fd11b 126
5234952b 127/* Objects encoding. Some kind of objects like Strings and Hashes can be
128 * internally represented in multiple ways. The 'encoding' field of the object
129 * is set to one of this fields for this object. */
c7d9d662
PN
130#define REDIS_ENCODING_RAW 0 /* Raw representation */
131#define REDIS_ENCODING_INT 1 /* Encoded as integer */
132#define REDIS_ENCODING_HT 2 /* Encoded as hash table */
133#define REDIS_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
134#define REDIS_ENCODING_LIST 4 /* Encoded as zipmap */
135#define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
d0b58d53 136#define REDIS_ENCODING_INTSET 6 /* Encoded as intset */
942a3961 137
07efaf74 138static char* strencoding[] = {
d0b58d53 139 "raw", "int", "hashtable", "zipmap", "list", "ziplist", "intset"
07efaf74 140};
141
f78fd11b 142/* Object types only used for dumping to disk */
bb32ede5 143#define REDIS_EXPIRETIME 253
ed9b544e 144#define REDIS_SELECTDB 254
145#define REDIS_EOF 255
146
f78fd11b 147/* Defines related to the dump file format. To store 32 bits lengths for short
148 * keys requires a lot of space, so we check the most significant 2 bits of
149 * the first byte to interpreter the length:
150 *
151 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
152 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
153 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
a4d1ba9a 154 * 11|000000 this means: specially encoded object will follow. The six bits
155 * number specify the kind of object that follows.
156 * See the REDIS_RDB_ENC_* defines.
f78fd11b 157 *
10c43610 158 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
159 * values, will fit inside. */
f78fd11b 160#define REDIS_RDB_6BITLEN 0
161#define REDIS_RDB_14BITLEN 1
162#define REDIS_RDB_32BITLEN 2
17be1a4a 163#define REDIS_RDB_ENCVAL 3
f78fd11b 164#define REDIS_RDB_LENERR UINT_MAX
165
a4d1ba9a 166/* When a length of a string object stored on disk has the first two bits
167 * set, the remaining two bits specify a special encoding for the object
168 * accordingly to the following defines: */
169#define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
170#define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
171#define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
774e3047 172#define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
a4d1ba9a 173
75680a3c 174/* Virtual memory object->where field. */
175#define REDIS_VM_MEMORY 0 /* The object is on memory */
176#define REDIS_VM_SWAPPED 1 /* The object is on disk */
177#define REDIS_VM_SWAPPING 2 /* Redis is swapping this object on disk */
178#define REDIS_VM_LOADING 3 /* Redis is loading this object from disk */
179
06224fec 180/* Virtual memory static configuration stuff.
181 * Check vmFindContiguousPages() to know more about this magic numbers. */
182#define REDIS_VM_MAX_NEAR_PAGES 65536
183#define REDIS_VM_MAX_RANDOM_JUMP 4096
92f8e882 184#define REDIS_VM_MAX_THREADS 32
bcaa7a4f 185#define REDIS_THREAD_STACK_SIZE (1024*1024*4)
f6c0bba8 186/* The following is the *percentage* of completed I/O jobs to process when the
187 * handelr is called. While Virtual Memory I/O operations are performed by
188 * threads, this operations must be processed by the main thread when completed
189 * in order to take effect. */
c953f24b 190#define REDIS_MAX_COMPLETED_JOBS_PROCESSED 1
06224fec 191
ed9b544e 192/* Client flags */
d5d55fc3 193#define REDIS_SLAVE 1 /* This client is a slave server */
194#define REDIS_MASTER 2 /* This client is a master server */
195#define REDIS_MONITOR 4 /* This client is a slave monitor, see MONITOR */
196#define REDIS_MULTI 8 /* This client is in a MULTI context */
197#define REDIS_BLOCKED 16 /* The client is waiting in a blocking operation */
198#define REDIS_IO_WAIT 32 /* The client is waiting for Virtual Memory I/O */
37ab76c9 199#define REDIS_DIRTY_CAS 64 /* Watched keys modified. EXEC will fail. */
ed9b544e 200
40d224a9 201/* Slave replication state - slave side */
ed9b544e 202#define REDIS_REPL_NONE 0 /* No active replication */
203#define REDIS_REPL_CONNECT 1 /* Must connect to master */
204#define REDIS_REPL_CONNECTED 2 /* Connected to master */
205
40d224a9 206/* Slave replication state - from the point of view of master
207 * Note that in SEND_BULK and ONLINE state the slave receives new updates
208 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
209 * to start the next background saving in order to send updates to it. */
210#define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
211#define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
212#define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
213#define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
214
ed9b544e 215/* List related stuff */
216#define REDIS_HEAD 0
217#define REDIS_TAIL 1
218
219/* Sort operations */
220#define REDIS_SORT_GET 0
443c6409 221#define REDIS_SORT_ASC 1
222#define REDIS_SORT_DESC 2
ed9b544e 223#define REDIS_SORTKEY_MAX 1024
224
225/* Log levels */
226#define REDIS_DEBUG 0
f870935d 227#define REDIS_VERBOSE 1
228#define REDIS_NOTICE 2
229#define REDIS_WARNING 3
ed9b544e 230
231/* Anti-warning macro... */
232#define REDIS_NOTUSED(V) ((void) V)
233
6b47e12e 234#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
235#define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
ed9b544e 236
48f0308a 237/* Append only defines */
238#define APPENDFSYNC_NO 0
239#define APPENDFSYNC_ALWAYS 1
240#define APPENDFSYNC_EVERYSEC 2
241
d0686e07 242/* Zip structure related defaults */
cbba7dd7 243#define REDIS_HASH_MAX_ZIPMAP_ENTRIES 64
244#define REDIS_HASH_MAX_ZIPMAP_VALUE 512
d0686e07
PN
245#define REDIS_LIST_MAX_ZIPLIST_ENTRIES 1024
246#define REDIS_LIST_MAX_ZIPLIST_VALUE 32
cbba7dd7 247
dfc5e96c 248/* We can print the stacktrace, so our assert is defined this way: */
478c2c6f 249#define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),_exit(1)))
c651fd9e 250#define redisPanic(_e) _redisPanic(#_e,__FILE__,__LINE__),_exit(1)
6c96ba7d 251static void _redisAssert(char *estr, char *file, int line);
c651fd9e 252static void _redisPanic(char *msg, char *file, int line);
dfc5e96c 253
ed9b544e 254/*================================= Data types ============================== */
255
256/* A redis object, that is a type able to hold a string / list / set */
75680a3c 257
75680a3c 258/* The actual Redis Object */
ed9b544e 259typedef struct redisObject {
560db612 260 unsigned type:4;
261 unsigned storage:2; /* REDIS_VM_MEMORY or REDIS_VM_SWAPPING */
262 unsigned encoding:4;
263 unsigned lru:22; /* lru time (relative to server.lruclock) */
ed9b544e 264 int refcount;
560db612 265 void *ptr;
75680a3c 266 /* VM fields, this are only allocated if VM is active, otherwise the
267 * object allocation function will just allocate
268 * sizeof(redisObjct) minus sizeof(redisObjectVM), so using
269 * Redis without VM active will not have any overhead. */
ed9b544e 270} robj;
271
560db612 272/* The VM pointer structure - identifies an object in the swap file.
273 *
274 * This object is stored in place of the value
275 * object in the main key->value hash table representing a database.
276 * Note that the first fields (type, storage) are the same as the redisObject
277 * structure so that vmPointer strucuters can be accessed even when casted
278 * as redisObject structures.
279 *
280 * This is useful as we don't know if a value object is or not on disk, but we
169dd6b7 281 * are always able to read obj->storage to check this. For vmPointer
560db612 282 * structures "type" is set to REDIS_VMPOINTER (even if without this field
283 * is still possible to check the kind of object from the value of 'storage').*/
284typedef struct vmPointer {
285 unsigned type:4;
286 unsigned storage:2; /* REDIS_VM_SWAPPED or REDIS_VM_LOADING */
287 unsigned notused:26;
288 unsigned int vtype; /* type of the object stored in the swap file */
289 off_t page; /* the page at witch the object is stored on disk */
290 off_t usedpages; /* number of pages used on disk */
291} vmpointer;
292
dfc5e96c 293/* Macro used to initalize a Redis object allocated on the stack.
294 * Note that this macro is taken near the structure definition to make sure
295 * we'll update it when the structure is changed, to avoid bugs like
296 * bug #85 introduced exactly in this way. */
297#define initStaticStringObject(_var,_ptr) do { \
298 _var.refcount = 1; \
299 _var.type = REDIS_STRING; \
300 _var.encoding = REDIS_ENCODING_RAW; \
301 _var.ptr = _ptr; \
560db612 302 _var.storage = REDIS_VM_MEMORY; \
dfc5e96c 303} while(0);
304
3305306f 305typedef struct redisDb {
4409877e 306 dict *dict; /* The keyspace for this DB */
307 dict *expires; /* Timeout of keys with a timeout set */
37ab76c9 308 dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) */
d5d55fc3 309 dict *io_keys; /* Keys with clients waiting for VM I/O */
37ab76c9 310 dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
3305306f 311 int id;
312} redisDb;
313
6e469882 314/* Client MULTI/EXEC state */
315typedef struct multiCmd {
316 robj **argv;
317 int argc;
318 struct redisCommand *cmd;
319} multiCmd;
320
321typedef struct multiState {
322 multiCmd *commands; /* Array of MULTI commands */
323 int count; /* Total number of MULTI commands */
324} multiState;
325
ed9b544e 326/* With multiplexing we need to take per-clinet state.
327 * Clients are taken in a liked list. */
328typedef struct redisClient {
329 int fd;
3305306f 330 redisDb *db;
ed9b544e 331 int dictid;
332 sds querybuf;
e8a74421 333 robj **argv, **mbargv;
334 int argc, mbargc;
40d224a9 335 int bulklen; /* bulk read len. -1 if not in bulk read mode */
e8a74421 336 int multibulk; /* multi bulk command format active */
ed9b544e 337 list *reply;
338 int sentlen;
339 time_t lastinteraction; /* time of the last interaction, used for timeout */
d5d55fc3 340 int flags; /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
40d224a9 341 int slaveseldb; /* slave selected db, if this client is a slave */
342 int authenticated; /* when requirepass is non-NULL */
343 int replstate; /* replication state if this is a slave */
344 int repldbfd; /* replication DB file descriptor */
6e469882 345 long repldboff; /* replication DB file offset */
40d224a9 346 off_t repldbsize; /* replication DB file size */
6e469882 347 multiState mstate; /* MULTI/EXEC state */
37ab76c9 348 robj **blocking_keys; /* The key we are waiting to terminate a blocking
4409877e 349 * operation such as BLPOP. Otherwise NULL. */
37ab76c9 350 int blocking_keys_num; /* Number of blocking keys */
4409877e 351 time_t blockingto; /* Blocking operation timeout. If UNIX current time
352 * is >= blockingto then the operation timed out. */
92f8e882 353 list *io_keys; /* Keys this client is waiting to be loaded from the
354 * swap file in order to continue. */
37ab76c9 355 list *watched_keys; /* Keys WATCHED for MULTI/EXEC CAS */
ffc6b7f8 356 dict *pubsub_channels; /* channels a client is interested in (SUBSCRIBE) */
357 list *pubsub_patterns; /* patterns a client is interested in (SUBSCRIBE) */
ed9b544e 358} redisClient;
359
360struct saveparam {
361 time_t seconds;
362 int changes;
363};
364
365/* Global server state structure */
366struct redisServer {
367 int port;
368 int fd;
3305306f 369 redisDb *db;
ed9b544e 370 long long dirty; /* changes to DB from the last save */
371 list *clients;
87eca727 372 list *slaves, *monitors;
ed9b544e 373 char neterr[ANET_ERR_LEN];
374 aeEventLoop *el;
375 int cronloops; /* number of times the cron function run */
376 list *objfreelist; /* A list of freed objects to avoid malloc() */
377 time_t lastsave; /* Unix time of last save succeeede */
ed9b544e 378 /* Fields used only for stats */
379 time_t stat_starttime; /* server start time */
380 long long stat_numcommands; /* number of processed commands */
381 long long stat_numconnections; /* number of connections received */
2a6a2ed1 382 long long stat_expiredkeys; /* number of expired keys */
ed9b544e 383 /* Configuration */
384 int verbosity;
385 int glueoutputbuf;
386 int maxidletime;
387 int dbnum;
388 int daemonize;
44b38ef4 389 int appendonly;
48f0308a 390 int appendfsync;
38db9171 391 int no_appendfsync_on_rewrite;
fab43727 392 int shutdown_asap;
48f0308a 393 time_t lastfsync;
44b38ef4 394 int appendfd;
395 int appendseldb;
ed329fcf 396 char *pidfile;
9f3c422c 397 pid_t bgsavechildpid;
9d65a1bb 398 pid_t bgrewritechildpid;
399 sds bgrewritebuf; /* buffer taken by parent during oppend only rewrite */
28ed1f33 400 sds aofbuf; /* AOF buffer, written before entering the event loop */
ed9b544e 401 struct saveparam *saveparams;
402 int saveparamslen;
403 char *logfile;
404 char *bindaddr;
405 char *dbfilename;
44b38ef4 406 char *appendfilename;
abcb223e 407 char *requirepass;
121f70cf 408 int rdbcompression;
8ca3e9d1 409 int activerehashing;
ed9b544e 410 /* Replication related */
411 int isslave;
d0ccebcf 412 char *masterauth;
ed9b544e 413 char *masterhost;
414 int masterport;
40d224a9 415 redisClient *master; /* client that is master for this slave */
ed9b544e 416 int replstate;
285add55 417 unsigned int maxclients;
4ef8de8a 418 unsigned long long maxmemory;
d5d55fc3 419 unsigned int blpop_blocked_clients;
420 unsigned int vm_blocked_clients;
ed9b544e 421 /* Sort parameters - qsort_r() is only available under BSD so we
422 * have to take this state global, in order to pass it to sortCompare() */
423 int sort_desc;
424 int sort_alpha;
425 int sort_bypattern;
75680a3c 426 /* Virtual memory configuration */
427 int vm_enabled;
054e426d 428 char *vm_swap_file;
75680a3c 429 off_t vm_page_size;
430 off_t vm_pages;
4ef8de8a 431 unsigned long long vm_max_memory;
d0686e07 432 /* Zip structure config */
cbba7dd7 433 size_t hash_max_zipmap_entries;
434 size_t hash_max_zipmap_value;
d0686e07
PN
435 size_t list_max_ziplist_entries;
436 size_t list_max_ziplist_value;
75680a3c 437 /* Virtual memory state */
438 FILE *vm_fp;
439 int vm_fd;
440 off_t vm_next_page; /* Next probably empty page */
441 off_t vm_near_pages; /* Number of pages allocated sequentially */
06224fec 442 unsigned char *vm_bitmap; /* Bitmap of free/used pages */
3a66edc7 443 time_t unixtime; /* Unix time sampled every second. */
92f8e882 444 /* Virtual memory I/O threads stuff */
92f8e882 445 /* An I/O thread process an element taken from the io_jobs queue and
996cb5f7 446 * put the result of the operation in the io_done list. While the
447 * job is being processed, it's put on io_processing queue. */
448 list *io_newjobs; /* List of VM I/O jobs yet to be processed */
449 list *io_processing; /* List of VM I/O jobs being processed */
450 list *io_processed; /* List of VM I/O jobs already processed */
d5d55fc3 451 list *io_ready_clients; /* Clients ready to be unblocked. All keys loaded */
996cb5f7 452 pthread_mutex_t io_mutex; /* lock to access io_jobs/io_done/io_thread_job */
a5819310 453 pthread_mutex_t obj_freelist_mutex; /* safe redis objects creation/free */
454 pthread_mutex_t io_swapfile_mutex; /* So we can lseek + write */
bcaa7a4f 455 pthread_attr_t io_threads_attr; /* attributes for threads creation */
92f8e882 456 int io_active_threads; /* Number of running I/O threads */
457 int vm_max_threads; /* Max number of I/O threads running at the same time */
996cb5f7 458 /* Our main thread is blocked on the event loop, locking for sockets ready
459 * to be read or written, so when a threaded I/O operation is ready to be
460 * processed by the main thread, the I/O thread will use a unix pipe to
461 * awake the main thread. The followings are the two pipe FDs. */
462 int io_ready_pipe_read;
463 int io_ready_pipe_write;
7d98e08c 464 /* Virtual memory stats */
465 unsigned long long vm_stats_used_pages;
466 unsigned long long vm_stats_swapped_objects;
467 unsigned long long vm_stats_swapouts;
468 unsigned long long vm_stats_swapins;
befec3cd 469 /* Pubsub */
ffc6b7f8 470 dict *pubsub_channels; /* Map channels to list of subscribed clients */
471 list *pubsub_patterns; /* A list of pubsub_patterns */
befec3cd 472 /* Misc */
b9bc0eef 473 FILE *devnull;
560db612 474 unsigned lruclock:22; /* clock incrementing every minute, for LRU */
475 unsigned lruclock_padding:10;
ed9b544e 476};
477
ffc6b7f8 478typedef struct pubsubPattern {
479 redisClient *client;
480 robj *pattern;
481} pubsubPattern;
482
ed9b544e 483typedef void redisCommandProc(redisClient *c);
ca1788b5 484typedef void redisVmPreloadProc(redisClient *c, struct redisCommand *cmd, int argc, robj **argv);
ed9b544e 485struct redisCommand {
486 char *name;
487 redisCommandProc *proc;
488 int arity;
489 int flags;
76583ea4
PN
490 /* Use a function to determine which keys need to be loaded
491 * in the background prior to executing this command. Takes precedence
492 * over vm_firstkey and others, ignored when NULL */
ca1788b5 493 redisVmPreloadProc *vm_preload_proc;
7c775e09 494 /* What keys should be loaded in background when calling this command? */
495 int vm_firstkey; /* The first argument that's a key (0 = no keys) */
496 int vm_lastkey; /* THe last argument that's a key */
497 int vm_keystep; /* The step between first and last key */
ed9b544e 498};
499
de96dbfe 500struct redisFunctionSym {
501 char *name;
56906eef 502 unsigned long pointer;
de96dbfe 503};
504
ed9b544e 505typedef struct _redisSortObject {
506 robj *obj;
507 union {
508 double score;
509 robj *cmpobj;
510 } u;
511} redisSortObject;
512
513typedef struct _redisSortOperation {
514 int type;
515 robj *pattern;
516} redisSortOperation;
517
6b47e12e 518/* ZSETs use a specialized version of Skiplists */
519
520typedef struct zskiplistNode {
521 struct zskiplistNode **forward;
e3870fab 522 struct zskiplistNode *backward;
912b9165 523 unsigned int *span;
6b47e12e 524 double score;
525 robj *obj;
526} zskiplistNode;
527
528typedef struct zskiplist {
e3870fab 529 struct zskiplistNode *header, *tail;
d13f767c 530 unsigned long length;
6b47e12e 531 int level;
532} zskiplist;
533
1812e024 534typedef struct zset {
535 dict *dict;
6b47e12e 536 zskiplist *zsl;
1812e024 537} zset;
538
6b47e12e 539/* Our shared "common" objects */
540
05df7621 541#define REDIS_SHARED_INTEGERS 10000
ed9b544e 542struct sharedObjectsStruct {
c937aa89 543 robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *pong, *space,
6e469882 544 *colon, *nullbulk, *nullmultibulk, *queued,
c937aa89 545 *emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr,
546 *outofrangeerr, *plus,
ed9b544e 547 *select0, *select1, *select2, *select3, *select4,
befec3cd 548 *select5, *select6, *select7, *select8, *select9,
c8d0ea0e 549 *messagebulk, *pmessagebulk, *subscribebulk, *unsubscribebulk, *mbulk3,
550 *mbulk4, *psubscribebulk, *punsubscribebulk,
551 *integers[REDIS_SHARED_INTEGERS];
ed9b544e 552} shared;
553
a7866db6 554/* Global vars that are actally used as constants. The following double
555 * values are used for double on-disk serialization, and are initialized
556 * at runtime to avoid strange compiler optimizations. */
557
558static double R_Zero, R_PosInf, R_NegInf, R_Nan;
559
92f8e882 560/* VM threaded I/O request message */
b9bc0eef 561#define REDIS_IOJOB_LOAD 0 /* Load from disk to memory */
562#define REDIS_IOJOB_PREPARE_SWAP 1 /* Compute needed pages */
563#define REDIS_IOJOB_DO_SWAP 2 /* Swap from memory to disk */
d5d55fc3 564typedef struct iojob {
996cb5f7 565 int type; /* Request type, REDIS_IOJOB_* */
b9bc0eef 566 redisDb *db;/* Redis database */
92f8e882 567 robj *key; /* This I/O request is about swapping this key */
560db612 568 robj *id; /* Unique identifier of this job:
569 this is the object to swap for REDIS_IOREQ_*_SWAP, or the
570 vmpointer objct for REDIS_IOREQ_LOAD. */
b9bc0eef 571 robj *val; /* the value to swap for REDIS_IOREQ_*_SWAP, otherwise this
92f8e882 572 * field is populated by the I/O thread for REDIS_IOREQ_LOAD. */
573 off_t page; /* Swap page where to read/write the object */
248ea310 574 off_t pages; /* Swap pages needed to save object. PREPARE_SWAP return val */
996cb5f7 575 int canceled; /* True if this command was canceled by blocking side of VM */
576 pthread_t thread; /* ID of the thread processing this entry */
577} iojob;
92f8e882 578
ed9b544e 579/*================================ Prototypes =============================== */
580
581static void freeStringObject(robj *o);
582static void freeListObject(robj *o);
583static void freeSetObject(robj *o);
584static void decrRefCount(void *o);
585static robj *createObject(int type, void *ptr);
586static void freeClient(redisClient *c);
f78fd11b 587static int rdbLoad(char *filename);
ed9b544e 588static void addReply(redisClient *c, robj *obj);
589static void addReplySds(redisClient *c, sds s);
590static void incrRefCount(robj *o);
f78fd11b 591static int rdbSaveBackground(char *filename);
ed9b544e 592static robj *createStringObject(char *ptr, size_t len);
4ef8de8a 593static robj *dupStringObject(robj *o);
248ea310 594static void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc);
dd142b9c 595static void replicationFeedMonitors(list *monitors, int dictid, robj **argv, int argc);
28ed1f33 596static void flushAppendOnlyFile(void);
44b38ef4 597static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc);
ed9b544e 598static int syncWithMaster(void);
05df7621 599static robj *tryObjectEncoding(robj *o);
9d65a1bb 600static robj *getDecodedObject(robj *o);
3305306f 601static int removeExpire(redisDb *db, robj *key);
602static int expireIfNeeded(redisDb *db, robj *key);
603static int deleteIfVolatile(redisDb *db, robj *key);
09241813 604static int dbDelete(redisDb *db, robj *key);
bb32ede5 605static time_t getExpire(redisDb *db, robj *key);
606static int setExpire(redisDb *db, robj *key, time_t when);
a3b21203 607static void updateSlavesWaitingBgsave(int bgsaveerr);
3fd78bcd 608static void freeMemoryIfNeeded(void);
de96dbfe 609static int processCommand(redisClient *c);
56906eef 610static void setupSigSegvAction(void);
a3b21203 611static void rdbRemoveTempFile(pid_t childpid);
9d65a1bb 612static void aofRemoveTempFile(pid_t childpid);
0ea663ea 613static size_t stringObjectLen(robj *o);
638e42ac 614static void processInputBuffer(redisClient *c);
6b47e12e 615static zskiplist *zslCreate(void);
fd8ccf44 616static void zslFree(zskiplist *zsl);
2b59cfdf 617static void zslInsert(zskiplist *zsl, double score, robj *obj);
2895e862 618static void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask);
6e469882 619static void initClientMultiState(redisClient *c);
620static void freeClientMultiState(redisClient *c);
621static void queueMultiCommand(redisClient *c, struct redisCommand *cmd);
b0d8747d 622static void unblockClientWaitingData(redisClient *c);
4409877e 623static int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele);
75680a3c 624static void vmInit(void);
a35ddf12 625static void vmMarkPagesFree(off_t page, off_t count);
560db612 626static robj *vmLoadObject(robj *o);
627static robj *vmPreviewObject(robj *o);
a69a0c9c 628static int vmSwapOneObjectBlocking(void);
629static int vmSwapOneObjectThreaded(void);
7e69548d 630static int vmCanSwapOut(void);
a5819310 631static int tryFreeOneObjectFromFreelist(void);
996cb5f7 632static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask);
633static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata, int mask);
634static void vmCancelThreadedIOJob(robj *o);
b9bc0eef 635static void lockThreadedIO(void);
636static void unlockThreadedIO(void);
637static int vmSwapObjectThreaded(robj *key, robj *val, redisDb *db);
638static void freeIOJob(iojob *j);
639static void queueIOJob(iojob *j);
a5819310 640static int vmWriteObjectOnSwap(robj *o, off_t page);
641static robj *vmReadObjectFromSwap(off_t page, int type);
054e426d 642static void waitEmptyIOJobsQueue(void);
643static void vmReopenSwapFile(void);
970e10bb 644static int vmFreePage(off_t page);
ca1788b5 645static void zunionInterBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv);
3805e04f 646static void execBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv);
0a6f3f0f 647static int blockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd);
d5d55fc3 648static int dontWaitForSwappedKey(redisClient *c, robj *key);
649static void handleClientsBlockedOnSwappedKey(redisDb *db, robj *key);
650static void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask);
651static struct redisCommand *lookupCommand(char *name);
652static void call(redisClient *c, struct redisCommand *cmd);
653static void resetClient(redisClient *c);
ada386b2 654static void convertToRealHash(robj *o);
003f0840 655static void listTypeConvert(robj *o, int enc);
d0b58d53 656static void setTypeConvert(robj *o, int enc);
ffc6b7f8 657static int pubsubUnsubscribeAllChannels(redisClient *c, int notify);
658static int pubsubUnsubscribeAllPatterns(redisClient *c, int notify);
659static void freePubsubPattern(void *p);
660static int listMatchPubsubPattern(void *a, void *b);
661static int compareStringObjects(robj *a, robj *b);
bf028098 662static int equalStringObjects(robj *a, robj *b);
befec3cd 663static void usage();
8f63ddca 664static int rewriteAppendOnlyFileBackground(void);
560db612 665static vmpointer *vmSwapObjectBlocking(robj *val);
fab43727 666static int prepareForShutdown();
37ab76c9 667static void touchWatchedKey(redisDb *db, robj *key);
9b30e1a2 668static void touchWatchedKeysOnFlush(int dbid);
37ab76c9 669static void unwatchAllKeys(redisClient *c);
ed9b544e 670
abcb223e 671static void authCommand(redisClient *c);
ed9b544e 672static void pingCommand(redisClient *c);
673static void echoCommand(redisClient *c);
674static void setCommand(redisClient *c);
675static void setnxCommand(redisClient *c);
526d00a5 676static void setexCommand(redisClient *c);
ed9b544e 677static void getCommand(redisClient *c);
678static void delCommand(redisClient *c);
679static void existsCommand(redisClient *c);
680static void incrCommand(redisClient *c);
681static void decrCommand(redisClient *c);
682static void incrbyCommand(redisClient *c);
683static void decrbyCommand(redisClient *c);
684static void selectCommand(redisClient *c);
685static void randomkeyCommand(redisClient *c);
686static void keysCommand(redisClient *c);
687static void dbsizeCommand(redisClient *c);
688static void lastsaveCommand(redisClient *c);
689static void saveCommand(redisClient *c);
690static void bgsaveCommand(redisClient *c);
9d65a1bb 691static void bgrewriteaofCommand(redisClient *c);
ed9b544e 692static void shutdownCommand(redisClient *c);
693static void moveCommand(redisClient *c);
694static void renameCommand(redisClient *c);
695static void renamenxCommand(redisClient *c);
696static void lpushCommand(redisClient *c);
697static void rpushCommand(redisClient *c);
698static void lpopCommand(redisClient *c);
699static void rpopCommand(redisClient *c);
700static void llenCommand(redisClient *c);
701static void lindexCommand(redisClient *c);
702static void lrangeCommand(redisClient *c);
703static void ltrimCommand(redisClient *c);
704static void typeCommand(redisClient *c);
705static void lsetCommand(redisClient *c);
706static void saddCommand(redisClient *c);
707static void sremCommand(redisClient *c);
a4460ef4 708static void smoveCommand(redisClient *c);
ed9b544e 709static void sismemberCommand(redisClient *c);
710static void scardCommand(redisClient *c);
12fea928 711static void spopCommand(redisClient *c);
2abb95a9 712static void srandmemberCommand(redisClient *c);
ed9b544e 713static void sinterCommand(redisClient *c);
714static void sinterstoreCommand(redisClient *c);
40d224a9 715static void sunionCommand(redisClient *c);
716static void sunionstoreCommand(redisClient *c);
f4f56e1d 717static void sdiffCommand(redisClient *c);
718static void sdiffstoreCommand(redisClient *c);
ed9b544e 719static void syncCommand(redisClient *c);
720static void flushdbCommand(redisClient *c);
721static void flushallCommand(redisClient *c);
722static void sortCommand(redisClient *c);
723static void lremCommand(redisClient *c);
0f5f7e9a 724static void rpoplpushcommand(redisClient *c);
ed9b544e 725static void infoCommand(redisClient *c);
70003d28 726static void mgetCommand(redisClient *c);
87eca727 727static void monitorCommand(redisClient *c);
3305306f 728static void expireCommand(redisClient *c);
802e8373 729static void expireatCommand(redisClient *c);
f6b141c5 730static void getsetCommand(redisClient *c);
fd88489a 731static void ttlCommand(redisClient *c);
321b0e13 732static void slaveofCommand(redisClient *c);
7f957c92 733static void debugCommand(redisClient *c);
f6b141c5 734static void msetCommand(redisClient *c);
735static void msetnxCommand(redisClient *c);
fd8ccf44 736static void zaddCommand(redisClient *c);
7db723ad 737static void zincrbyCommand(redisClient *c);
cc812361 738static void zrangeCommand(redisClient *c);
50c55df5 739static void zrangebyscoreCommand(redisClient *c);
f44dd428 740static void zcountCommand(redisClient *c);
e3870fab 741static void zrevrangeCommand(redisClient *c);
3c41331e 742static void zcardCommand(redisClient *c);
1b7106e7 743static void zremCommand(redisClient *c);
6e333bbe 744static void zscoreCommand(redisClient *c);
1807985b 745static void zremrangebyscoreCommand(redisClient *c);
6e469882 746static void multiCommand(redisClient *c);
747static void execCommand(redisClient *c);
18b6cb76 748static void discardCommand(redisClient *c);
4409877e 749static void blpopCommand(redisClient *c);
750static void brpopCommand(redisClient *c);
4b00bebd 751static void appendCommand(redisClient *c);
39191553 752static void substrCommand(redisClient *c);
69d95c3e 753static void zrankCommand(redisClient *c);
798d9e55 754static void zrevrankCommand(redisClient *c);
978c2c94 755static void hsetCommand(redisClient *c);
1f1c7695 756static void hsetnxCommand(redisClient *c);
978c2c94 757static void hgetCommand(redisClient *c);
09aeb579
PN
758static void hmsetCommand(redisClient *c);
759static void hmgetCommand(redisClient *c);
07efaf74 760static void hdelCommand(redisClient *c);
92b27fe9 761static void hlenCommand(redisClient *c);
9212eafd 762static void zremrangebyrankCommand(redisClient *c);
5d373da9 763static void zunionstoreCommand(redisClient *c);
764static void zinterstoreCommand(redisClient *c);
78409a0f 765static void hkeysCommand(redisClient *c);
766static void hvalsCommand(redisClient *c);
767static void hgetallCommand(redisClient *c);
a86f14b1 768static void hexistsCommand(redisClient *c);
500ece7c 769static void configCommand(redisClient *c);
01426b05 770static void hincrbyCommand(redisClient *c);
befec3cd 771static void subscribeCommand(redisClient *c);
772static void unsubscribeCommand(redisClient *c);
ffc6b7f8 773static void psubscribeCommand(redisClient *c);
774static void punsubscribeCommand(redisClient *c);
befec3cd 775static void publishCommand(redisClient *c);
37ab76c9 776static void watchCommand(redisClient *c);
777static void unwatchCommand(redisClient *c);
f6b141c5 778
ed9b544e 779/*================================= Globals ================================= */
780
781/* Global vars */
782static struct redisServer server; /* server global state */
1a132bbc 783static struct redisCommand *commandTable;
1a132bbc 784static struct redisCommand readonlyCommandTable[] = {
76583ea4
PN
785 {"get",getCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
786 {"set",setCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,0,0,0},
787 {"setnx",setnxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,0,0,0},
526d00a5 788 {"setex",setexCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,0,0,0},
76583ea4
PN
789 {"append",appendCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
790 {"substr",substrCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
791 {"del",delCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
792 {"exists",existsCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
793 {"incr",incrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
794 {"decr",decrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
795 {"mget",mgetCommand,-2,REDIS_CMD_INLINE,NULL,1,-1,1},
796 {"rpush",rpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
797 {"lpush",lpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
798 {"rpop",rpopCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
799 {"lpop",lpopCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
800 {"brpop",brpopCommand,-3,REDIS_CMD_INLINE,NULL,1,1,1},
801 {"blpop",blpopCommand,-3,REDIS_CMD_INLINE,NULL,1,1,1},
802 {"llen",llenCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
803 {"lindex",lindexCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
804 {"lset",lsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
805 {"lrange",lrangeCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
806 {"ltrim",ltrimCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
807 {"lrem",lremCommand,4,REDIS_CMD_BULK,NULL,1,1,1},
808 {"rpoplpush",rpoplpushcommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,2,1},
809 {"sadd",saddCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
810 {"srem",sremCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
811 {"smove",smoveCommand,4,REDIS_CMD_BULK,NULL,1,2,1},
812 {"sismember",sismemberCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
813 {"scard",scardCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
814 {"spop",spopCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
815 {"srandmember",srandmemberCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
816 {"sinter",sinterCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,-1,1},
817 {"sinterstore",sinterstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,2,-1,1},
818 {"sunion",sunionCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,-1,1},
819 {"sunionstore",sunionstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,2,-1,1},
820 {"sdiff",sdiffCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,-1,1},
821 {"sdiffstore",sdiffstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,2,-1,1},
822 {"smembers",sinterCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
823 {"zadd",zaddCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
824 {"zincrby",zincrbyCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
825 {"zrem",zremCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
826 {"zremrangebyscore",zremrangebyscoreCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
827 {"zremrangebyrank",zremrangebyrankCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
5d373da9 828 {"zunionstore",zunionstoreCommand,-4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,zunionInterBlockClientOnSwappedKeys,0,0,0},
829 {"zinterstore",zinterstoreCommand,-4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,zunionInterBlockClientOnSwappedKeys,0,0,0},
76583ea4
PN
830 {"zrange",zrangeCommand,-4,REDIS_CMD_INLINE,NULL,1,1,1},
831 {"zrangebyscore",zrangebyscoreCommand,-4,REDIS_CMD_INLINE,NULL,1,1,1},
832 {"zcount",zcountCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
833 {"zrevrange",zrevrangeCommand,-4,REDIS_CMD_INLINE,NULL,1,1,1},
834 {"zcard",zcardCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
835 {"zscore",zscoreCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
836 {"zrank",zrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
837 {"zrevrank",zrevrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
838 {"hset",hsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
1f1c7695 839 {"hsetnx",hsetnxCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
09aeb579 840 {"hget",hgetCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
d33278d1 841 {"hmset",hmsetCommand,-4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
09aeb579 842 {"hmget",hmgetCommand,-3,REDIS_CMD_BULK,NULL,1,1,1},
01426b05 843 {"hincrby",hincrbyCommand,4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
76583ea4
PN
844 {"hdel",hdelCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
845 {"hlen",hlenCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
846 {"hkeys",hkeysCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
847 {"hvals",hvalsCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
848 {"hgetall",hgetallCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
4583c4f0 849 {"hexists",hexistsCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
76583ea4
PN
850 {"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
851 {"decrby",decrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
852 {"getset",getsetCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
853 {"mset",msetCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,-1,2},
854 {"msetnx",msetnxCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,-1,2},
855 {"randomkey",randomkeyCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
856 {"select",selectCommand,2,REDIS_CMD_INLINE,NULL,0,0,0},
857 {"move",moveCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
858 {"rename",renameCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
859 {"renamenx",renamenxCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
860 {"expire",expireCommand,3,REDIS_CMD_INLINE,NULL,0,0,0},
861 {"expireat",expireatCommand,3,REDIS_CMD_INLINE,NULL,0,0,0},
862 {"keys",keysCommand,2,REDIS_CMD_INLINE,NULL,0,0,0},
863 {"dbsize",dbsizeCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
864 {"auth",authCommand,2,REDIS_CMD_INLINE,NULL,0,0,0},
865 {"ping",pingCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
866 {"echo",echoCommand,2,REDIS_CMD_BULK,NULL,0,0,0},
867 {"save",saveCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
868 {"bgsave",bgsaveCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
869 {"bgrewriteaof",bgrewriteaofCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
870 {"shutdown",shutdownCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
871 {"lastsave",lastsaveCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
872 {"type",typeCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
873 {"multi",multiCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
3805e04f 874 {"exec",execCommand,1,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,execBlockClientOnSwappedKeys,0,0,0},
76583ea4
PN
875 {"discard",discardCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
876 {"sync",syncCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
877 {"flushdb",flushdbCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
878 {"flushall",flushallCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
879 {"sort",sortCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
880 {"info",infoCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
881 {"monitor",monitorCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
882 {"ttl",ttlCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
883 {"slaveof",slaveofCommand,3,REDIS_CMD_INLINE,NULL,0,0,0},
884 {"debug",debugCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
500ece7c 885 {"config",configCommand,-2,REDIS_CMD_BULK,NULL,0,0,0},
befec3cd 886 {"subscribe",subscribeCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
887 {"unsubscribe",unsubscribeCommand,-1,REDIS_CMD_INLINE,NULL,0,0,0},
ffc6b7f8 888 {"psubscribe",psubscribeCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
889 {"punsubscribe",punsubscribeCommand,-1,REDIS_CMD_INLINE,NULL,0,0,0},
4005fef1 890 {"publish",publishCommand,3,REDIS_CMD_BULK|REDIS_CMD_FORCE_REPLICATION,NULL,0,0,0},
37ab76c9 891 {"watch",watchCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
d55d5c5d 892 {"unwatch",unwatchCommand,1,REDIS_CMD_INLINE,NULL,0,0,0}
ed9b544e 893};
bcfc686d 894
ed9b544e 895/*============================ Utility functions ============================ */
896
897/* Glob-style pattern matching. */
500ece7c 898static int stringmatchlen(const char *pattern, int patternLen,
ed9b544e 899 const char *string, int stringLen, int nocase)
900{
901 while(patternLen) {
902 switch(pattern[0]) {
903 case '*':
904 while (pattern[1] == '*') {
905 pattern++;
906 patternLen--;
907 }
908 if (patternLen == 1)
909 return 1; /* match */
910 while(stringLen) {
911 if (stringmatchlen(pattern+1, patternLen-1,
912 string, stringLen, nocase))
913 return 1; /* match */
914 string++;
915 stringLen--;
916 }
917 return 0; /* no match */
918 break;
919 case '?':
920 if (stringLen == 0)
921 return 0; /* no match */
922 string++;
923 stringLen--;
924 break;
925 case '[':
926 {
927 int not, match;
928
929 pattern++;
930 patternLen--;
931 not = pattern[0] == '^';
932 if (not) {
933 pattern++;
934 patternLen--;
935 }
936 match = 0;
937 while(1) {
938 if (pattern[0] == '\\') {
939 pattern++;
940 patternLen--;
941 if (pattern[0] == string[0])
942 match = 1;
943 } else if (pattern[0] == ']') {
944 break;
945 } else if (patternLen == 0) {
946 pattern--;
947 patternLen++;
948 break;
949 } else if (pattern[1] == '-' && patternLen >= 3) {
950 int start = pattern[0];
951 int end = pattern[2];
952 int c = string[0];
953 if (start > end) {
954 int t = start;
955 start = end;
956 end = t;
957 }
958 if (nocase) {
959 start = tolower(start);
960 end = tolower(end);
961 c = tolower(c);
962 }
963 pattern += 2;
964 patternLen -= 2;
965 if (c >= start && c <= end)
966 match = 1;
967 } else {
968 if (!nocase) {
969 if (pattern[0] == string[0])
970 match = 1;
971 } else {
972 if (tolower((int)pattern[0]) == tolower((int)string[0]))
973 match = 1;
974 }
975 }
976 pattern++;
977 patternLen--;
978 }
979 if (not)
980 match = !match;
981 if (!match)
982 return 0; /* no match */
983 string++;
984 stringLen--;
985 break;
986 }
987 case '\\':
988 if (patternLen >= 2) {
989 pattern++;
990 patternLen--;
991 }
992 /* fall through */
993 default:
994 if (!nocase) {
995 if (pattern[0] != string[0])
996 return 0; /* no match */
997 } else {
998 if (tolower((int)pattern[0]) != tolower((int)string[0]))
999 return 0; /* no match */
1000 }
1001 string++;
1002 stringLen--;
1003 break;
1004 }
1005 pattern++;
1006 patternLen--;
1007 if (stringLen == 0) {
1008 while(*pattern == '*') {
1009 pattern++;
1010 patternLen--;
1011 }
1012 break;
1013 }
1014 }
1015 if (patternLen == 0 && stringLen == 0)
1016 return 1;
1017 return 0;
1018}
1019
500ece7c 1020static int stringmatch(const char *pattern, const char *string, int nocase) {
1021 return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
1022}
1023
2b619329 1024/* Convert a string representing an amount of memory into the number of
1025 * bytes, so for instance memtoll("1Gi") will return 1073741824 that is
1026 * (1024*1024*1024).
1027 *
1028 * On parsing error, if *err is not NULL, it's set to 1, otherwise it's
1029 * set to 0 */
1030static long long memtoll(const char *p, int *err) {
1031 const char *u;
1032 char buf[128];
1033 long mul; /* unit multiplier */
1034 long long val;
1035 unsigned int digits;
1036
1037 if (err) *err = 0;
1038 /* Search the first non digit character. */
1039 u = p;
1040 if (*u == '-') u++;
1041 while(*u && isdigit(*u)) u++;
1042 if (*u == '\0' || !strcasecmp(u,"b")) {
1043 mul = 1;
72324005 1044 } else if (!strcasecmp(u,"k")) {
2b619329 1045 mul = 1000;
72324005 1046 } else if (!strcasecmp(u,"kb")) {
2b619329 1047 mul = 1024;
72324005 1048 } else if (!strcasecmp(u,"m")) {
2b619329 1049 mul = 1000*1000;
72324005 1050 } else if (!strcasecmp(u,"mb")) {
2b619329 1051 mul = 1024*1024;
72324005 1052 } else if (!strcasecmp(u,"g")) {
2b619329 1053 mul = 1000L*1000*1000;
72324005 1054 } else if (!strcasecmp(u,"gb")) {
2b619329 1055 mul = 1024L*1024*1024;
1056 } else {
1057 if (err) *err = 1;
1058 mul = 1;
1059 }
1060 digits = u-p;
1061 if (digits >= sizeof(buf)) {
1062 if (err) *err = 1;
1063 return LLONG_MAX;
1064 }
1065 memcpy(buf,p,digits);
1066 buf[digits] = '\0';
1067 val = strtoll(buf,NULL,10);
1068 return val*mul;
1069}
1070
ee14da56 1071/* Convert a long long into a string. Returns the number of
1072 * characters needed to represent the number, that can be shorter if passed
1073 * buffer length is not enough to store the whole number. */
1074static int ll2string(char *s, size_t len, long long value) {
1075 char buf[32], *p;
1076 unsigned long long v;
1077 size_t l;
1078
1079 if (len == 0) return 0;
1080 v = (value < 0) ? -value : value;
1081 p = buf+31; /* point to the last character */
1082 do {
1083 *p-- = '0'+(v%10);
1084 v /= 10;
1085 } while(v);
1086 if (value < 0) *p-- = '-';
1087 p++;
1088 l = 32-(p-buf);
1089 if (l+1 > len) l = len-1; /* Make sure it fits, including the nul term */
1090 memcpy(s,p,l);
1091 s[l] = '\0';
1092 return l;
1093}
1094
56906eef 1095static void redisLog(int level, const char *fmt, ...) {
ed9b544e 1096 va_list ap;
1097 FILE *fp;
1098
1099 fp = (server.logfile == NULL) ? stdout : fopen(server.logfile,"a");
1100 if (!fp) return;
1101
1102 va_start(ap, fmt);
1103 if (level >= server.verbosity) {
6766f45e 1104 char *c = ".-*#";
1904ecc1 1105 char buf[64];
1106 time_t now;
1107
1108 now = time(NULL);
6c9385e0 1109 strftime(buf,64,"%d %b %H:%M:%S",localtime(&now));
054e426d 1110 fprintf(fp,"[%d] %s %c ",(int)getpid(),buf,c[level]);
ed9b544e 1111 vfprintf(fp, fmt, ap);
1112 fprintf(fp,"\n");
1113 fflush(fp);
1114 }
1115 va_end(ap);
1116
1117 if (server.logfile) fclose(fp);
1118}
1119
1120/*====================== Hash table type implementation ==================== */
1121
1122/* This is an hash table type that uses the SDS dynamic strings libary as
1123 * keys and radis objects as values (objects can hold SDS strings,
1124 * lists, sets). */
1125
1812e024 1126static void dictVanillaFree(void *privdata, void *val)
1127{
1128 DICT_NOTUSED(privdata);
1129 zfree(val);
1130}
1131
4409877e 1132static void dictListDestructor(void *privdata, void *val)
1133{
1134 DICT_NOTUSED(privdata);
1135 listRelease((list*)val);
1136}
1137
09241813 1138static int dictSdsKeyCompare(void *privdata, const void *key1,
ed9b544e 1139 const void *key2)
1140{
1141 int l1,l2;
1142 DICT_NOTUSED(privdata);
1143
1144 l1 = sdslen((sds)key1);
1145 l2 = sdslen((sds)key2);
1146 if (l1 != l2) return 0;
1147 return memcmp(key1, key2, l1) == 0;
1148}
1149
1150static void dictRedisObjectDestructor(void *privdata, void *val)
1151{
1152 DICT_NOTUSED(privdata);
1153
a35ddf12 1154 if (val == NULL) return; /* Values of swapped out keys as set to NULL */
ed9b544e 1155 decrRefCount(val);
1156}
1157
09241813 1158static void dictSdsDestructor(void *privdata, void *val)
1159{
1160 DICT_NOTUSED(privdata);
1161
1162 sdsfree(val);
1163}
1164
942a3961 1165static int dictObjKeyCompare(void *privdata, const void *key1,
ed9b544e 1166 const void *key2)
1167{
1168 const robj *o1 = key1, *o2 = key2;
09241813 1169 return dictSdsKeyCompare(privdata,o1->ptr,o2->ptr);
ed9b544e 1170}
1171
942a3961 1172static unsigned int dictObjHash(const void *key) {
ed9b544e 1173 const robj *o = key;
1174 return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
1175}
1176
09241813 1177static unsigned int dictSdsHash(const void *key) {
1178 return dictGenHashFunction((unsigned char*)key, sdslen((char*)key));
1179}
1180
942a3961 1181static int dictEncObjKeyCompare(void *privdata, const void *key1,
1182 const void *key2)
1183{
9d65a1bb 1184 robj *o1 = (robj*) key1, *o2 = (robj*) key2;
1185 int cmp;
942a3961 1186
2a1198b4 1187 if (o1->encoding == REDIS_ENCODING_INT &&
dc05abde 1188 o2->encoding == REDIS_ENCODING_INT)
1189 return o1->ptr == o2->ptr;
2a1198b4 1190
9d65a1bb 1191 o1 = getDecodedObject(o1);
1192 o2 = getDecodedObject(o2);
09241813 1193 cmp = dictSdsKeyCompare(privdata,o1->ptr,o2->ptr);
9d65a1bb 1194 decrRefCount(o1);
1195 decrRefCount(o2);
1196 return cmp;
942a3961 1197}
1198
1199static unsigned int dictEncObjHash(const void *key) {
9d65a1bb 1200 robj *o = (robj*) key;
942a3961 1201
ed9e4966 1202 if (o->encoding == REDIS_ENCODING_RAW) {
1203 return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
1204 } else {
1205 if (o->encoding == REDIS_ENCODING_INT) {
1206 char buf[32];
1207 int len;
1208
ee14da56 1209 len = ll2string(buf,32,(long)o->ptr);
ed9e4966 1210 return dictGenHashFunction((unsigned char*)buf, len);
1211 } else {
1212 unsigned int hash;
1213
1214 o = getDecodedObject(o);
1215 hash = dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
1216 decrRefCount(o);
1217 return hash;
1218 }
1219 }
942a3961 1220}
1221
09241813 1222/* Sets type */
ed9b544e 1223static dictType setDictType = {
942a3961 1224 dictEncObjHash, /* hash function */
ed9b544e 1225 NULL, /* key dup */
1226 NULL, /* val dup */
942a3961 1227 dictEncObjKeyCompare, /* key compare */
ed9b544e 1228 dictRedisObjectDestructor, /* key destructor */
1229 NULL /* val destructor */
1230};
1231
f2d9f50f 1232/* Sorted sets hash (note: a skiplist is used in addition to the hash table) */
1812e024 1233static dictType zsetDictType = {
1234 dictEncObjHash, /* hash function */
1235 NULL, /* key dup */
1236 NULL, /* val dup */
1237 dictEncObjKeyCompare, /* key compare */
1238 dictRedisObjectDestructor, /* key destructor */
da0a1620 1239 dictVanillaFree /* val destructor of malloc(sizeof(double)) */
1812e024 1240};
1241
09241813 1242/* Db->dict, keys are sds strings, vals are Redis objects. */
5234952b 1243static dictType dbDictType = {
09241813 1244 dictSdsHash, /* hash function */
ed9b544e 1245 NULL, /* key dup */
1246 NULL, /* val dup */
09241813 1247 dictSdsKeyCompare, /* key compare */
1248 dictSdsDestructor, /* key destructor */
ed9b544e 1249 dictRedisObjectDestructor /* val destructor */
1250};
1251
f2d9f50f 1252/* Db->expires */
1253static dictType keyptrDictType = {
09241813 1254 dictSdsHash, /* hash function */
f2d9f50f 1255 NULL, /* key dup */
1256 NULL, /* val dup */
09241813 1257 dictSdsKeyCompare, /* key compare */
1258 dictSdsDestructor, /* key destructor */
f2d9f50f 1259 NULL /* val destructor */
1260};
1261
5234952b 1262/* Hash type hash table (note that small hashes are represented with zimpaps) */
1263static dictType hashDictType = {
1264 dictEncObjHash, /* hash function */
1265 NULL, /* key dup */
1266 NULL, /* val dup */
1267 dictEncObjKeyCompare, /* key compare */
1268 dictRedisObjectDestructor, /* key destructor */
1269 dictRedisObjectDestructor /* val destructor */
1270};
1271
4409877e 1272/* Keylist hash table type has unencoded redis objects as keys and
d5d55fc3 1273 * lists as values. It's used for blocking operations (BLPOP) and to
1274 * map swapped keys to a list of clients waiting for this keys to be loaded. */
4409877e 1275static dictType keylistDictType = {
1276 dictObjHash, /* hash function */
1277 NULL, /* key dup */
1278 NULL, /* val dup */
1279 dictObjKeyCompare, /* key compare */
1280 dictRedisObjectDestructor, /* key destructor */
1281 dictListDestructor /* val destructor */
1282};
1283
42ab0172
AO
1284static void version();
1285
ed9b544e 1286/* ========================= Random utility functions ======================= */
1287
1288/* Redis generally does not try to recover from out of memory conditions
1289 * when allocating objects or strings, it is not clear if it will be possible
1290 * to report this condition to the client since the networking layer itself
1291 * is based on heap allocation for send buffers, so we simply abort.
1292 * At least the code will be simpler to read... */
1293static void oom(const char *msg) {
71c54b21 1294 redisLog(REDIS_WARNING, "%s: Out of memory\n",msg);
ed9b544e 1295 sleep(1);
1296 abort();
1297}
1298
1299/* ====================== Redis server networking stuff ===================== */
56906eef 1300static void closeTimedoutClients(void) {
ed9b544e 1301 redisClient *c;
ed9b544e 1302 listNode *ln;
1303 time_t now = time(NULL);
c7df85a4 1304 listIter li;
ed9b544e 1305
c7df85a4 1306 listRewind(server.clients,&li);
1307 while ((ln = listNext(&li)) != NULL) {
ed9b544e 1308 c = listNodeValue(ln);
f86a74e9 1309 if (server.maxidletime &&
1310 !(c->flags & REDIS_SLAVE) && /* no timeout for slaves */
c7cf2ec9 1311 !(c->flags & REDIS_MASTER) && /* no timeout for masters */
ffc6b7f8 1312 dictSize(c->pubsub_channels) == 0 && /* no timeout for pubsub */
1313 listLength(c->pubsub_patterns) == 0 &&
d6cc8867 1314 (now - c->lastinteraction > server.maxidletime))
f86a74e9 1315 {
f870935d 1316 redisLog(REDIS_VERBOSE,"Closing idle client");
ed9b544e 1317 freeClient(c);
f86a74e9 1318 } else if (c->flags & REDIS_BLOCKED) {
58d976b8 1319 if (c->blockingto != 0 && c->blockingto < now) {
b177fd30 1320 addReply(c,shared.nullmultibulk);
b0d8747d 1321 unblockClientWaitingData(c);
f86a74e9 1322 }
ed9b544e 1323 }
1324 }
ed9b544e 1325}
1326
12fea928 1327static int htNeedsResize(dict *dict) {
1328 long long size, used;
1329
1330 size = dictSlots(dict);
1331 used = dictSize(dict);
1332 return (size && used && size > DICT_HT_INITIAL_SIZE &&
1333 (used*100/size < REDIS_HT_MINFILL));
1334}
1335
0bc03378 1336/* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
1337 * we resize the hash table to save memory */
56906eef 1338static void tryResizeHashTables(void) {
0bc03378 1339 int j;
1340
1341 for (j = 0; j < server.dbnum; j++) {
5413c40d 1342 if (htNeedsResize(server.db[j].dict))
0bc03378 1343 dictResize(server.db[j].dict);
12fea928 1344 if (htNeedsResize(server.db[j].expires))
1345 dictResize(server.db[j].expires);
0bc03378 1346 }
1347}
1348
8ca3e9d1 1349/* Our hash table implementation performs rehashing incrementally while
1350 * we write/read from the hash table. Still if the server is idle, the hash
1351 * table will use two tables for a long time. So we try to use 1 millisecond
1352 * of CPU time at every serverCron() loop in order to rehash some key. */
1353static void incrementallyRehash(void) {
1354 int j;
1355
1356 for (j = 0; j < server.dbnum; j++) {
1357 if (dictIsRehashing(server.db[j].dict)) {
1358 dictRehashMilliseconds(server.db[j].dict,1);
1359 break; /* already used our millisecond for this loop... */
1360 }
1361 }
1362}
1363
9d65a1bb 1364/* A background saving child (BGSAVE) terminated its work. Handle this. */
1365void backgroundSaveDoneHandler(int statloc) {
1366 int exitcode = WEXITSTATUS(statloc);
1367 int bysignal = WIFSIGNALED(statloc);
1368
1369 if (!bysignal && exitcode == 0) {
1370 redisLog(REDIS_NOTICE,
1371 "Background saving terminated with success");
1372 server.dirty = 0;
1373 server.lastsave = time(NULL);
1374 } else if (!bysignal && exitcode != 0) {
1375 redisLog(REDIS_WARNING, "Background saving error");
1376 } else {
1377 redisLog(REDIS_WARNING,
454eea7c 1378 "Background saving terminated by signal %d", WTERMSIG(statloc));
9d65a1bb 1379 rdbRemoveTempFile(server.bgsavechildpid);
1380 }
1381 server.bgsavechildpid = -1;
1382 /* Possibly there are slaves waiting for a BGSAVE in order to be served
1383 * (the first stage of SYNC is a bulk transfer of dump.rdb) */
1384 updateSlavesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR);
1385}
1386
1387/* A background append only file rewriting (BGREWRITEAOF) terminated its work.
1388 * Handle this. */
1389void backgroundRewriteDoneHandler(int statloc) {
1390 int exitcode = WEXITSTATUS(statloc);
1391 int bysignal = WIFSIGNALED(statloc);
1392
1393 if (!bysignal && exitcode == 0) {
1394 int fd;
1395 char tmpfile[256];
1396
1397 redisLog(REDIS_NOTICE,
1398 "Background append only file rewriting terminated with success");
1399 /* Now it's time to flush the differences accumulated by the parent */
1400 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) server.bgrewritechildpid);
1401 fd = open(tmpfile,O_WRONLY|O_APPEND);
1402 if (fd == -1) {
1403 redisLog(REDIS_WARNING, "Not able to open the temp append only file produced by the child: %s", strerror(errno));
1404 goto cleanup;
1405 }
1406 /* Flush our data... */
1407 if (write(fd,server.bgrewritebuf,sdslen(server.bgrewritebuf)) !=
1408 (signed) sdslen(server.bgrewritebuf)) {
1409 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));
1410 close(fd);
1411 goto cleanup;
1412 }
b32627cd 1413 redisLog(REDIS_NOTICE,"Parent diff flushed into the new append log file with success (%lu bytes)",sdslen(server.bgrewritebuf));
9d65a1bb 1414 /* Now our work is to rename the temp file into the stable file. And
1415 * switch the file descriptor used by the server for append only. */
1416 if (rename(tmpfile,server.appendfilename) == -1) {
1417 redisLog(REDIS_WARNING,"Can't rename the temp append only file into the stable one: %s", strerror(errno));
1418 close(fd);
1419 goto cleanup;
1420 }
1421 /* Mission completed... almost */
1422 redisLog(REDIS_NOTICE,"Append only file successfully rewritten.");
1423 if (server.appendfd != -1) {
1424 /* If append only is actually enabled... */
1425 close(server.appendfd);
1426 server.appendfd = fd;
d5d23dab 1427 if (server.appendfsync != APPENDFSYNC_NO) aof_fsync(fd);
85a83172 1428 server.appendseldb = -1; /* Make sure it will issue SELECT */
9d65a1bb 1429 redisLog(REDIS_NOTICE,"The new append only file was selected for future appends.");
1430 } else {
1431 /* If append only is disabled we just generate a dump in this
1432 * format. Why not? */
1433 close(fd);
1434 }
1435 } else if (!bysignal && exitcode != 0) {
1436 redisLog(REDIS_WARNING, "Background append only file rewriting error");
1437 } else {
1438 redisLog(REDIS_WARNING,
454eea7c 1439 "Background append only file rewriting terminated by signal %d",
1440 WTERMSIG(statloc));
9d65a1bb 1441 }
1442cleanup:
1443 sdsfree(server.bgrewritebuf);
1444 server.bgrewritebuf = sdsempty();
1445 aofRemoveTempFile(server.bgrewritechildpid);
1446 server.bgrewritechildpid = -1;
1447}
1448
884d4b39 1449/* This function is called once a background process of some kind terminates,
1450 * as we want to avoid resizing the hash tables when there is a child in order
1451 * to play well with copy-on-write (otherwise when a resize happens lots of
1452 * memory pages are copied). The goal of this function is to update the ability
1453 * for dict.c to resize the hash tables accordingly to the fact we have o not
1454 * running childs. */
1455static void updateDictResizePolicy(void) {
1456 if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1)
1457 dictEnableResize();
1458 else
1459 dictDisableResize();
1460}
1461
56906eef 1462static int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
94754ccc 1463 int j, loops = server.cronloops++;
ed9b544e 1464 REDIS_NOTUSED(eventLoop);
1465 REDIS_NOTUSED(id);
1466 REDIS_NOTUSED(clientData);
1467
3a66edc7 1468 /* We take a cached value of the unix time in the global state because
1469 * with virtual memory and aging there is to store the current time
1470 * in objects at every object access, and accuracy is not needed.
1471 * To access a global var is faster than calling time(NULL) */
1472 server.unixtime = time(NULL);
560db612 1473 /* We have just 21 bits per object for LRU information.
1474 * So we use an (eventually wrapping) LRU clock with minutes resolution.
1475 *
1476 * When we need to select what object to swap, we compute the minimum
1477 * time distance between the current lruclock and the object last access
1478 * lruclock info. Even if clocks will wrap on overflow, there is
1479 * the interesting property that we are sure that at least
1480 * ABS(A-B) minutes passed between current time and timestamp B.
1481 *
1482 * This is not precise but we don't need at all precision, but just
1483 * something statistically reasonable.
1484 */
1485 server.lruclock = (time(NULL)/60)&((1<<21)-1);
3a66edc7 1486
fab43727 1487 /* We received a SIGTERM, shutting down here in a safe way, as it is
1488 * not ok doing so inside the signal handler. */
1489 if (server.shutdown_asap) {
1490 if (prepareForShutdown() == REDIS_OK) exit(0);
1491 redisLog(REDIS_WARNING,"SIGTERM received but errors trying to shut down the server, check the logs for more information");
1492 }
1493
0bc03378 1494 /* Show some info about non-empty databases */
ed9b544e 1495 for (j = 0; j < server.dbnum; j++) {
dec423d9 1496 long long size, used, vkeys;
94754ccc 1497
3305306f 1498 size = dictSlots(server.db[j].dict);
1499 used = dictSize(server.db[j].dict);
94754ccc 1500 vkeys = dictSize(server.db[j].expires);
1763929f 1501 if (!(loops % 50) && (used || vkeys)) {
f870935d 1502 redisLog(REDIS_VERBOSE,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j,used,vkeys,size);
a4d1ba9a 1503 /* dictPrintStats(server.dict); */
ed9b544e 1504 }
ed9b544e 1505 }
1506
0bc03378 1507 /* We don't want to resize the hash tables while a bacground saving
1508 * is in progress: the saving child is created using fork() that is
1509 * implemented with a copy-on-write semantic in most modern systems, so
1510 * if we resize the HT while there is the saving child at work actually
1511 * a lot of memory movements in the parent will cause a lot of pages
1512 * copied. */
8ca3e9d1 1513 if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1) {
1514 if (!(loops % 10)) tryResizeHashTables();
1515 if (server.activerehashing) incrementallyRehash();
884d4b39 1516 }
0bc03378 1517
ed9b544e 1518 /* Show information about connected clients */
1763929f 1519 if (!(loops % 50)) {
bdcb92f2 1520 redisLog(REDIS_VERBOSE,"%d clients connected (%d slaves), %zu bytes in use",
ed9b544e 1521 listLength(server.clients)-listLength(server.slaves),
1522 listLength(server.slaves),
bdcb92f2 1523 zmalloc_used_memory());
ed9b544e 1524 }
1525
1526 /* Close connections of timedout clients */
1763929f 1527 if ((server.maxidletime && !(loops % 100)) || server.blpop_blocked_clients)
ed9b544e 1528 closeTimedoutClients();
1529
9d65a1bb 1530 /* Check if a background saving or AOF rewrite in progress terminated */
1531 if (server.bgsavechildpid != -1 || server.bgrewritechildpid != -1) {
ed9b544e 1532 int statloc;
9d65a1bb 1533 pid_t pid;
1534
1535 if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
1536 if (pid == server.bgsavechildpid) {
1537 backgroundSaveDoneHandler(statloc);
ed9b544e 1538 } else {
9d65a1bb 1539 backgroundRewriteDoneHandler(statloc);
ed9b544e 1540 }
884d4b39 1541 updateDictResizePolicy();
ed9b544e 1542 }
1543 } else {
1544 /* If there is not a background saving in progress check if
1545 * we have to save now */
1546 time_t now = time(NULL);
1547 for (j = 0; j < server.saveparamslen; j++) {
1548 struct saveparam *sp = server.saveparams+j;
1549
1550 if (server.dirty >= sp->changes &&
1551 now-server.lastsave > sp->seconds) {
1552 redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...",
1553 sp->changes, sp->seconds);
f78fd11b 1554 rdbSaveBackground(server.dbfilename);
ed9b544e 1555 break;
1556 }
1557 }
1558 }
94754ccc 1559
f2324293 1560 /* Try to expire a few timed out keys. The algorithm used is adaptive and
1561 * will use few CPU cycles if there are few expiring keys, otherwise
1562 * it will get more aggressive to avoid that too much memory is used by
1563 * keys that can be removed from the keyspace. */
94754ccc 1564 for (j = 0; j < server.dbnum; j++) {
f2324293 1565 int expired;
94754ccc 1566 redisDb *db = server.db+j;
94754ccc 1567
f2324293 1568 /* Continue to expire if at the end of the cycle more than 25%
1569 * of the keys were expired. */
1570 do {
4ef8de8a 1571 long num = dictSize(db->expires);
94754ccc 1572 time_t now = time(NULL);
1573
f2324293 1574 expired = 0;
94754ccc 1575 if (num > REDIS_EXPIRELOOKUPS_PER_CRON)
1576 num = REDIS_EXPIRELOOKUPS_PER_CRON;
1577 while (num--) {
1578 dictEntry *de;
1579 time_t t;
1580
1581 if ((de = dictGetRandomKey(db->expires)) == NULL) break;
1582 t = (time_t) dictGetEntryVal(de);
1583 if (now > t) {
09241813 1584 sds key = dictGetEntryKey(de);
1585 robj *keyobj = createStringObject(key,sdslen(key));
1586
1587 dbDelete(db,keyobj);
1588 decrRefCount(keyobj);
f2324293 1589 expired++;
2a6a2ed1 1590 server.stat_expiredkeys++;
94754ccc 1591 }
1592 }
f2324293 1593 } while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/4);
94754ccc 1594 }
1595
4ef8de8a 1596 /* Swap a few keys on disk if we are over the memory limit and VM
f870935d 1597 * is enbled. Try to free objects from the free list first. */
7e69548d 1598 if (vmCanSwapOut()) {
1599 while (server.vm_enabled && zmalloc_used_memory() >
f870935d 1600 server.vm_max_memory)
1601 {
72e9fd40 1602 int retval;
1603
a5819310 1604 if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
72e9fd40 1605 retval = (server.vm_max_threads == 0) ?
1606 vmSwapOneObjectBlocking() :
1607 vmSwapOneObjectThreaded();
1763929f 1608 if (retval == REDIS_ERR && !(loops % 300) &&
72e9fd40 1609 zmalloc_used_memory() >
1610 (server.vm_max_memory+server.vm_max_memory/10))
1611 {
1612 redisLog(REDIS_WARNING,"WARNING: vm-max-memory limit exceeded by more than 10%% but unable to swap more objects out!");
7e69548d 1613 }
72e9fd40 1614 /* Note that when using threade I/O we free just one object,
1615 * because anyway when the I/O thread in charge to swap this
1616 * object out will finish, the handler of completed jobs
1617 * will try to swap more objects if we are still out of memory. */
1618 if (retval == REDIS_ERR || server.vm_max_threads > 0) break;
4ef8de8a 1619 }
1620 }
1621
ed9b544e 1622 /* Check if we should connect to a MASTER */
1763929f 1623 if (server.replstate == REDIS_REPL_CONNECT && !(loops % 10)) {
ed9b544e 1624 redisLog(REDIS_NOTICE,"Connecting to MASTER...");
1625 if (syncWithMaster() == REDIS_OK) {
1626 redisLog(REDIS_NOTICE,"MASTER <-> SLAVE sync succeeded");
8f63ddca 1627 if (server.appendonly) rewriteAppendOnlyFileBackground();
ed9b544e 1628 }
1629 }
1763929f 1630 return 100;
ed9b544e 1631}
1632
d5d55fc3 1633/* This function gets called every time Redis is entering the
1634 * main loop of the event driven library, that is, before to sleep
1635 * for ready file descriptors. */
1636static void beforeSleep(struct aeEventLoop *eventLoop) {
1637 REDIS_NOTUSED(eventLoop);
1638
28ed1f33 1639 /* Awake clients that got all the swapped keys they requested */
d5d55fc3 1640 if (server.vm_enabled && listLength(server.io_ready_clients)) {
1641 listIter li;
1642 listNode *ln;
1643
1644 listRewind(server.io_ready_clients,&li);
1645 while((ln = listNext(&li))) {
1646 redisClient *c = ln->value;
1647 struct redisCommand *cmd;
1648
1649 /* Resume the client. */
1650 listDelNode(server.io_ready_clients,ln);
1651 c->flags &= (~REDIS_IO_WAIT);
1652 server.vm_blocked_clients--;
1653 aeCreateFileEvent(server.el, c->fd, AE_READABLE,
1654 readQueryFromClient, c);
1655 cmd = lookupCommand(c->argv[0]->ptr);
1656 assert(cmd != NULL);
1657 call(c,cmd);
1658 resetClient(c);
1659 /* There may be more data to process in the input buffer. */
1660 if (c->querybuf && sdslen(c->querybuf) > 0)
1661 processInputBuffer(c);
1662 }
1663 }
28ed1f33 1664 /* Write the AOF buffer on disk */
1665 flushAppendOnlyFile();
d5d55fc3 1666}
1667
ed9b544e 1668static void createSharedObjects(void) {
05df7621 1669 int j;
1670
ed9b544e 1671 shared.crlf = createObject(REDIS_STRING,sdsnew("\r\n"));
1672 shared.ok = createObject(REDIS_STRING,sdsnew("+OK\r\n"));
1673 shared.err = createObject(REDIS_STRING,sdsnew("-ERR\r\n"));
c937aa89 1674 shared.emptybulk = createObject(REDIS_STRING,sdsnew("$0\r\n\r\n"));
1675 shared.czero = createObject(REDIS_STRING,sdsnew(":0\r\n"));
1676 shared.cone = createObject(REDIS_STRING,sdsnew(":1\r\n"));
1677 shared.nullbulk = createObject(REDIS_STRING,sdsnew("$-1\r\n"));
1678 shared.nullmultibulk = createObject(REDIS_STRING,sdsnew("*-1\r\n"));
1679 shared.emptymultibulk = createObject(REDIS_STRING,sdsnew("*0\r\n"));
ed9b544e 1680 shared.pong = createObject(REDIS_STRING,sdsnew("+PONG\r\n"));
6e469882 1681 shared.queued = createObject(REDIS_STRING,sdsnew("+QUEUED\r\n"));
ed9b544e 1682 shared.wrongtypeerr = createObject(REDIS_STRING,sdsnew(
1683 "-ERR Operation against a key holding the wrong kind of value\r\n"));
ed9b544e 1684 shared.nokeyerr = createObject(REDIS_STRING,sdsnew(
1685 "-ERR no such key\r\n"));
ed9b544e 1686 shared.syntaxerr = createObject(REDIS_STRING,sdsnew(
1687 "-ERR syntax error\r\n"));
c937aa89 1688 shared.sameobjecterr = createObject(REDIS_STRING,sdsnew(
1689 "-ERR source and destination objects are the same\r\n"));
1690 shared.outofrangeerr = createObject(REDIS_STRING,sdsnew(
1691 "-ERR index out of range\r\n"));
ed9b544e 1692 shared.space = createObject(REDIS_STRING,sdsnew(" "));
c937aa89 1693 shared.colon = createObject(REDIS_STRING,sdsnew(":"));
1694 shared.plus = createObject(REDIS_STRING,sdsnew("+"));
ed9b544e 1695 shared.select0 = createStringObject("select 0\r\n",10);
1696 shared.select1 = createStringObject("select 1\r\n",10);
1697 shared.select2 = createStringObject("select 2\r\n",10);
1698 shared.select3 = createStringObject("select 3\r\n",10);
1699 shared.select4 = createStringObject("select 4\r\n",10);
1700 shared.select5 = createStringObject("select 5\r\n",10);
1701 shared.select6 = createStringObject("select 6\r\n",10);
1702 shared.select7 = createStringObject("select 7\r\n",10);
1703 shared.select8 = createStringObject("select 8\r\n",10);
1704 shared.select9 = createStringObject("select 9\r\n",10);
befec3cd 1705 shared.messagebulk = createStringObject("$7\r\nmessage\r\n",13);
c8d0ea0e 1706 shared.pmessagebulk = createStringObject("$8\r\npmessage\r\n",14);
befec3cd 1707 shared.subscribebulk = createStringObject("$9\r\nsubscribe\r\n",15);
fc46bb71 1708 shared.unsubscribebulk = createStringObject("$11\r\nunsubscribe\r\n",18);
ffc6b7f8 1709 shared.psubscribebulk = createStringObject("$10\r\npsubscribe\r\n",17);
1710 shared.punsubscribebulk = createStringObject("$12\r\npunsubscribe\r\n",19);
befec3cd 1711 shared.mbulk3 = createStringObject("*3\r\n",4);
c8d0ea0e 1712 shared.mbulk4 = createStringObject("*4\r\n",4);
05df7621 1713 for (j = 0; j < REDIS_SHARED_INTEGERS; j++) {
1714 shared.integers[j] = createObject(REDIS_STRING,(void*)(long)j);
1715 shared.integers[j]->encoding = REDIS_ENCODING_INT;
1716 }
ed9b544e 1717}
1718
1719static void appendServerSaveParams(time_t seconds, int changes) {
1720 server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));
ed9b544e 1721 server.saveparams[server.saveparamslen].seconds = seconds;
1722 server.saveparams[server.saveparamslen].changes = changes;
1723 server.saveparamslen++;
1724}
1725
bcfc686d 1726static void resetServerSaveParams() {
ed9b544e 1727 zfree(server.saveparams);
1728 server.saveparams = NULL;
1729 server.saveparamslen = 0;
1730}
1731
1732static void initServerConfig() {
1733 server.dbnum = REDIS_DEFAULT_DBNUM;
1734 server.port = REDIS_SERVERPORT;
f870935d 1735 server.verbosity = REDIS_VERBOSE;
ed9b544e 1736 server.maxidletime = REDIS_MAXIDLETIME;
1737 server.saveparams = NULL;
1738 server.logfile = NULL; /* NULL = log on standard output */
1739 server.bindaddr = NULL;
1740 server.glueoutputbuf = 1;
1741 server.daemonize = 0;
44b38ef4 1742 server.appendonly = 0;
1b677732 1743 server.appendfsync = APPENDFSYNC_EVERYSEC;
38db9171 1744 server.no_appendfsync_on_rewrite = 0;
48f0308a 1745 server.lastfsync = time(NULL);
44b38ef4 1746 server.appendfd = -1;
1747 server.appendseldb = -1; /* Make sure the first time will not match */
500ece7c 1748 server.pidfile = zstrdup("/var/run/redis.pid");
1749 server.dbfilename = zstrdup("dump.rdb");
1750 server.appendfilename = zstrdup("appendonly.aof");
abcb223e 1751 server.requirepass = NULL;
b0553789 1752 server.rdbcompression = 1;
8ca3e9d1 1753 server.activerehashing = 1;
285add55 1754 server.maxclients = 0;
d5d55fc3 1755 server.blpop_blocked_clients = 0;
3fd78bcd 1756 server.maxmemory = 0;
75680a3c 1757 server.vm_enabled = 0;
054e426d 1758 server.vm_swap_file = zstrdup("/tmp/redis-%p.vm");
75680a3c 1759 server.vm_page_size = 256; /* 256 bytes per page */
1760 server.vm_pages = 1024*1024*100; /* 104 millions of pages */
1761 server.vm_max_memory = 1024LL*1024*1024*1; /* 1 GB of RAM */
92f8e882 1762 server.vm_max_threads = 4;
d5d55fc3 1763 server.vm_blocked_clients = 0;
cbba7dd7 1764 server.hash_max_zipmap_entries = REDIS_HASH_MAX_ZIPMAP_ENTRIES;
1765 server.hash_max_zipmap_value = REDIS_HASH_MAX_ZIPMAP_VALUE;
d0686e07
PN
1766 server.list_max_ziplist_entries = REDIS_LIST_MAX_ZIPLIST_ENTRIES;
1767 server.list_max_ziplist_value = REDIS_LIST_MAX_ZIPLIST_VALUE;
fab43727 1768 server.shutdown_asap = 0;
75680a3c 1769
bcfc686d 1770 resetServerSaveParams();
ed9b544e 1771
1772 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
1773 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
1774 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1775 /* Replication related */
1776 server.isslave = 0;
d0ccebcf 1777 server.masterauth = NULL;
ed9b544e 1778 server.masterhost = NULL;
1779 server.masterport = 6379;
1780 server.master = NULL;
1781 server.replstate = REDIS_REPL_NONE;
a7866db6 1782
1783 /* Double constants initialization */
1784 R_Zero = 0.0;
1785 R_PosInf = 1.0/R_Zero;
1786 R_NegInf = -1.0/R_Zero;
1787 R_Nan = R_Zero/R_Zero;
ed9b544e 1788}
1789
1790static void initServer() {
1791 int j;
1792
1793 signal(SIGHUP, SIG_IGN);
1794 signal(SIGPIPE, SIG_IGN);
fe3bbfbe 1795 setupSigSegvAction();
ed9b544e 1796
b9bc0eef 1797 server.devnull = fopen("/dev/null","w");
1798 if (server.devnull == NULL) {
1799 redisLog(REDIS_WARNING, "Can't open /dev/null: %s", server.neterr);
1800 exit(1);
1801 }
ed9b544e 1802 server.clients = listCreate();
1803 server.slaves = listCreate();
87eca727 1804 server.monitors = listCreate();
ed9b544e 1805 server.objfreelist = listCreate();
1806 createSharedObjects();
1807 server.el = aeCreateEventLoop();
3305306f 1808 server.db = zmalloc(sizeof(redisDb)*server.dbnum);
ed9b544e 1809 server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr);
1810 if (server.fd == -1) {
1811 redisLog(REDIS_WARNING, "Opening TCP port: %s", server.neterr);
1812 exit(1);
1813 }
3305306f 1814 for (j = 0; j < server.dbnum; j++) {
5234952b 1815 server.db[j].dict = dictCreate(&dbDictType,NULL);
f2d9f50f 1816 server.db[j].expires = dictCreate(&keyptrDictType,NULL);
37ab76c9 1817 server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL);
1818 server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);
d5d55fc3 1819 if (server.vm_enabled)
1820 server.db[j].io_keys = dictCreate(&keylistDictType,NULL);
3305306f 1821 server.db[j].id = j;
1822 }
ffc6b7f8 1823 server.pubsub_channels = dictCreate(&keylistDictType,NULL);
1824 server.pubsub_patterns = listCreate();
1825 listSetFreeMethod(server.pubsub_patterns,freePubsubPattern);
1826 listSetMatchMethod(server.pubsub_patterns,listMatchPubsubPattern);
ed9b544e 1827 server.cronloops = 0;
9f3c422c 1828 server.bgsavechildpid = -1;
9d65a1bb 1829 server.bgrewritechildpid = -1;
1830 server.bgrewritebuf = sdsempty();
28ed1f33 1831 server.aofbuf = sdsempty();
ed9b544e 1832 server.lastsave = time(NULL);
1833 server.dirty = 0;
ed9b544e 1834 server.stat_numcommands = 0;
1835 server.stat_numconnections = 0;
2a6a2ed1 1836 server.stat_expiredkeys = 0;
ed9b544e 1837 server.stat_starttime = time(NULL);
3a66edc7 1838 server.unixtime = time(NULL);
d8f8b666 1839 aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL);
996cb5f7 1840 if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,
1841 acceptHandler, NULL) == AE_ERR) oom("creating file event");
44b38ef4 1842
1843 if (server.appendonly) {
3bb225d6 1844 server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
44b38ef4 1845 if (server.appendfd == -1) {
1846 redisLog(REDIS_WARNING, "Can't open the append-only file: %s",
1847 strerror(errno));
1848 exit(1);
1849 }
1850 }
75680a3c 1851
1852 if (server.vm_enabled) vmInit();
ed9b544e 1853}
1854
1855/* Empty the whole database */
ca37e9cd 1856static long long emptyDb() {
ed9b544e 1857 int j;
ca37e9cd 1858 long long removed = 0;
ed9b544e 1859
3305306f 1860 for (j = 0; j < server.dbnum; j++) {
ca37e9cd 1861 removed += dictSize(server.db[j].dict);
3305306f 1862 dictEmpty(server.db[j].dict);
1863 dictEmpty(server.db[j].expires);
1864 }
ca37e9cd 1865 return removed;
ed9b544e 1866}
1867
85dd2f3a 1868static int yesnotoi(char *s) {
1869 if (!strcasecmp(s,"yes")) return 1;
1870 else if (!strcasecmp(s,"no")) return 0;
1871 else return -1;
1872}
1873
ed9b544e 1874/* I agree, this is a very rudimental way to load a configuration...
1875 will improve later if the config gets more complex */
1876static void loadServerConfig(char *filename) {
c9a111ac 1877 FILE *fp;
ed9b544e 1878 char buf[REDIS_CONFIGLINE_MAX+1], *err = NULL;
1879 int linenum = 0;
1880 sds line = NULL;
c9a111ac 1881
1882 if (filename[0] == '-' && filename[1] == '\0')
1883 fp = stdin;
1884 else {
1885 if ((fp = fopen(filename,"r")) == NULL) {
9a22de82 1886 redisLog(REDIS_WARNING, "Fatal error, can't open config file '%s'", filename);
c9a111ac 1887 exit(1);
1888 }
ed9b544e 1889 }
c9a111ac 1890
ed9b544e 1891 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL) {
1892 sds *argv;
1893 int argc, j;
1894
1895 linenum++;
1896 line = sdsnew(buf);
1897 line = sdstrim(line," \t\r\n");
1898
1899 /* Skip comments and blank lines*/
1900 if (line[0] == '#' || line[0] == '\0') {
1901 sdsfree(line);
1902 continue;
1903 }
1904
1905 /* Split into arguments */
1906 argv = sdssplitlen(line,sdslen(line)," ",1,&argc);
1907 sdstolower(argv[0]);
1908
1909 /* Execute config directives */
bb0b03a3 1910 if (!strcasecmp(argv[0],"timeout") && argc == 2) {
ed9b544e 1911 server.maxidletime = atoi(argv[1]);
0150db36 1912 if (server.maxidletime < 0) {
ed9b544e 1913 err = "Invalid timeout value"; goto loaderr;
1914 }
bb0b03a3 1915 } else if (!strcasecmp(argv[0],"port") && argc == 2) {
ed9b544e 1916 server.port = atoi(argv[1]);
1917 if (server.port < 1 || server.port > 65535) {
1918 err = "Invalid port"; goto loaderr;
1919 }
bb0b03a3 1920 } else if (!strcasecmp(argv[0],"bind") && argc == 2) {
ed9b544e 1921 server.bindaddr = zstrdup(argv[1]);
bb0b03a3 1922 } else if (!strcasecmp(argv[0],"save") && argc == 3) {
ed9b544e 1923 int seconds = atoi(argv[1]);
1924 int changes = atoi(argv[2]);
1925 if (seconds < 1 || changes < 0) {
1926 err = "Invalid save parameters"; goto loaderr;
1927 }
1928 appendServerSaveParams(seconds,changes);
bb0b03a3 1929 } else if (!strcasecmp(argv[0],"dir") && argc == 2) {
ed9b544e 1930 if (chdir(argv[1]) == -1) {
1931 redisLog(REDIS_WARNING,"Can't chdir to '%s': %s",
1932 argv[1], strerror(errno));
1933 exit(1);
1934 }
bb0b03a3 1935 } else if (!strcasecmp(argv[0],"loglevel") && argc == 2) {
1936 if (!strcasecmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG;
f870935d 1937 else if (!strcasecmp(argv[1],"verbose")) server.verbosity = REDIS_VERBOSE;
bb0b03a3 1938 else if (!strcasecmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE;
1939 else if (!strcasecmp(argv[1],"warning")) server.verbosity = REDIS_WARNING;
ed9b544e 1940 else {
1941 err = "Invalid log level. Must be one of debug, notice, warning";
1942 goto loaderr;
1943 }
bb0b03a3 1944 } else if (!strcasecmp(argv[0],"logfile") && argc == 2) {
c9a111ac 1945 FILE *logfp;
ed9b544e 1946
1947 server.logfile = zstrdup(argv[1]);
bb0b03a3 1948 if (!strcasecmp(server.logfile,"stdout")) {
ed9b544e 1949 zfree(server.logfile);
1950 server.logfile = NULL;
1951 }
1952 if (server.logfile) {
1953 /* Test if we are able to open the file. The server will not
1954 * be able to abort just for this problem later... */
c9a111ac 1955 logfp = fopen(server.logfile,"a");
1956 if (logfp == NULL) {
ed9b544e 1957 err = sdscatprintf(sdsempty(),
1958 "Can't open the log file: %s", strerror(errno));
1959 goto loaderr;
1960 }
c9a111ac 1961 fclose(logfp);
ed9b544e 1962 }
bb0b03a3 1963 } else if (!strcasecmp(argv[0],"databases") && argc == 2) {
ed9b544e 1964 server.dbnum = atoi(argv[1]);
1965 if (server.dbnum < 1) {
1966 err = "Invalid number of databases"; goto loaderr;
1967 }
b3f83f12
JZ
1968 } else if (!strcasecmp(argv[0],"include") && argc == 2) {
1969 loadServerConfig(argv[1]);
285add55 1970 } else if (!strcasecmp(argv[0],"maxclients") && argc == 2) {
1971 server.maxclients = atoi(argv[1]);
3fd78bcd 1972 } else if (!strcasecmp(argv[0],"maxmemory") && argc == 2) {
2b619329 1973 server.maxmemory = memtoll(argv[1],NULL);
bb0b03a3 1974 } else if (!strcasecmp(argv[0],"slaveof") && argc == 3) {
ed9b544e 1975 server.masterhost = sdsnew(argv[1]);
1976 server.masterport = atoi(argv[2]);
1977 server.replstate = REDIS_REPL_CONNECT;
d0ccebcf 1978 } else if (!strcasecmp(argv[0],"masterauth") && argc == 2) {
1979 server.masterauth = zstrdup(argv[1]);
bb0b03a3 1980 } else if (!strcasecmp(argv[0],"glueoutputbuf") && argc == 2) {
85dd2f3a 1981 if ((server.glueoutputbuf = yesnotoi(argv[1])) == -1) {
ed9b544e 1982 err = "argument must be 'yes' or 'no'"; goto loaderr;
1983 }
121f70cf 1984 } else if (!strcasecmp(argv[0],"rdbcompression") && argc == 2) {
1985 if ((server.rdbcompression = yesnotoi(argv[1])) == -1) {
8ca3e9d1 1986 err = "argument must be 'yes' or 'no'"; goto loaderr;
1987 }
1988 } else if (!strcasecmp(argv[0],"activerehashing") && argc == 2) {
1989 if ((server.activerehashing = yesnotoi(argv[1])) == -1) {
121f70cf 1990 err = "argument must be 'yes' or 'no'"; goto loaderr;
1991 }
bb0b03a3 1992 } else if (!strcasecmp(argv[0],"daemonize") && argc == 2) {
85dd2f3a 1993 if ((server.daemonize = yesnotoi(argv[1])) == -1) {
ed9b544e 1994 err = "argument must be 'yes' or 'no'"; goto loaderr;
1995 }
44b38ef4 1996 } else if (!strcasecmp(argv[0],"appendonly") && argc == 2) {
1997 if ((server.appendonly = yesnotoi(argv[1])) == -1) {
1998 err = "argument must be 'yes' or 'no'"; goto loaderr;
1999 }
f3b52411
PN
2000 } else if (!strcasecmp(argv[0],"appendfilename") && argc == 2) {
2001 zfree(server.appendfilename);
2002 server.appendfilename = zstrdup(argv[1]);
38db9171 2003 } else if (!strcasecmp(argv[0],"no-appendfsync-on-rewrite")
2004 && argc == 2) {
2005 if ((server.no_appendfsync_on_rewrite= yesnotoi(argv[1])) == -1) {
2006 err = "argument must be 'yes' or 'no'"; goto loaderr;
2007 }
48f0308a 2008 } else if (!strcasecmp(argv[0],"appendfsync") && argc == 2) {
1766c6da 2009 if (!strcasecmp(argv[1],"no")) {
48f0308a 2010 server.appendfsync = APPENDFSYNC_NO;
1766c6da 2011 } else if (!strcasecmp(argv[1],"always")) {
48f0308a 2012 server.appendfsync = APPENDFSYNC_ALWAYS;
1766c6da 2013 } else if (!strcasecmp(argv[1],"everysec")) {
48f0308a 2014 server.appendfsync = APPENDFSYNC_EVERYSEC;
2015 } else {
2016 err = "argument must be 'no', 'always' or 'everysec'";
2017 goto loaderr;
2018 }
bb0b03a3 2019 } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
054e426d 2020 server.requirepass = zstrdup(argv[1]);
bb0b03a3 2021 } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
500ece7c 2022 zfree(server.pidfile);
054e426d 2023 server.pidfile = zstrdup(argv[1]);
bb0b03a3 2024 } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) {
500ece7c 2025 zfree(server.dbfilename);
054e426d 2026 server.dbfilename = zstrdup(argv[1]);
75680a3c 2027 } else if (!strcasecmp(argv[0],"vm-enabled") && argc == 2) {
2028 if ((server.vm_enabled = yesnotoi(argv[1])) == -1) {
2029 err = "argument must be 'yes' or 'no'"; goto loaderr;
2030 }
054e426d 2031 } else if (!strcasecmp(argv[0],"vm-swap-file") && argc == 2) {
fefed597 2032 zfree(server.vm_swap_file);
054e426d 2033 server.vm_swap_file = zstrdup(argv[1]);
4ef8de8a 2034 } else if (!strcasecmp(argv[0],"vm-max-memory") && argc == 2) {
2b619329 2035 server.vm_max_memory = memtoll(argv[1],NULL);
4ef8de8a 2036 } else if (!strcasecmp(argv[0],"vm-page-size") && argc == 2) {
2b619329 2037 server.vm_page_size = memtoll(argv[1], NULL);
4ef8de8a 2038 } else if (!strcasecmp(argv[0],"vm-pages") && argc == 2) {
2b619329 2039 server.vm_pages = memtoll(argv[1], NULL);
92f8e882 2040 } else if (!strcasecmp(argv[0],"vm-max-threads") && argc == 2) {
2041 server.vm_max_threads = strtoll(argv[1], NULL, 10);
cbba7dd7 2042 } else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2){
2b619329 2043 server.hash_max_zipmap_entries = memtoll(argv[1], NULL);
cbba7dd7 2044 } else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2){
2b619329 2045 server.hash_max_zipmap_value = memtoll(argv[1], NULL);
d0686e07
PN
2046 } else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){
2047 server.list_max_ziplist_entries = memtoll(argv[1], NULL);
2048 } else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2){
2049 server.list_max_ziplist_value = memtoll(argv[1], NULL);
ed9b544e 2050 } else {
2051 err = "Bad directive or wrong number of arguments"; goto loaderr;
2052 }
2053 for (j = 0; j < argc; j++)
2054 sdsfree(argv[j]);
2055 zfree(argv);
2056 sdsfree(line);
2057 }
c9a111ac 2058 if (fp != stdin) fclose(fp);
ed9b544e 2059 return;
2060
2061loaderr:
2062 fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n");
2063 fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
2064 fprintf(stderr, ">>> '%s'\n", line);
2065 fprintf(stderr, "%s\n", err);
2066 exit(1);
2067}
2068
2069static void freeClientArgv(redisClient *c) {
2070 int j;
2071
2072 for (j = 0; j < c->argc; j++)
2073 decrRefCount(c->argv[j]);
e8a74421 2074 for (j = 0; j < c->mbargc; j++)
2075 decrRefCount(c->mbargv[j]);
ed9b544e 2076 c->argc = 0;
e8a74421 2077 c->mbargc = 0;
ed9b544e 2078}
2079
2080static void freeClient(redisClient *c) {
2081 listNode *ln;
2082
4409877e 2083 /* Note that if the client we are freeing is blocked into a blocking
b0d8747d 2084 * call, we have to set querybuf to NULL *before* to call
2085 * unblockClientWaitingData() to avoid processInputBuffer() will get
2086 * called. Also it is important to remove the file events after
2087 * this, because this call adds the READABLE event. */
4409877e 2088 sdsfree(c->querybuf);
2089 c->querybuf = NULL;
2090 if (c->flags & REDIS_BLOCKED)
b0d8747d 2091 unblockClientWaitingData(c);
4409877e 2092
37ab76c9 2093 /* UNWATCH all the keys */
2094 unwatchAllKeys(c);
2095 listRelease(c->watched_keys);
ffc6b7f8 2096 /* Unsubscribe from all the pubsub channels */
2097 pubsubUnsubscribeAllChannels(c,0);
2098 pubsubUnsubscribeAllPatterns(c,0);
2099 dictRelease(c->pubsub_channels);
2100 listRelease(c->pubsub_patterns);
befec3cd 2101 /* Obvious cleanup */
ed9b544e 2102 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
2103 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
ed9b544e 2104 listRelease(c->reply);
2105 freeClientArgv(c);
2106 close(c->fd);
92f8e882 2107 /* Remove from the list of clients */
ed9b544e 2108 ln = listSearchKey(server.clients,c);
dfc5e96c 2109 redisAssert(ln != NULL);
ed9b544e 2110 listDelNode(server.clients,ln);
37ab76c9 2111 /* Remove from the list of clients that are now ready to be restarted
2112 * after waiting for swapped keys */
d5d55fc3 2113 if (c->flags & REDIS_IO_WAIT && listLength(c->io_keys) == 0) {
2114 ln = listSearchKey(server.io_ready_clients,c);
2115 if (ln) {
2116 listDelNode(server.io_ready_clients,ln);
2117 server.vm_blocked_clients--;
2118 }
2119 }
37ab76c9 2120 /* Remove from the list of clients waiting for swapped keys */
d5d55fc3 2121 while (server.vm_enabled && listLength(c->io_keys)) {
2122 ln = listFirst(c->io_keys);
2123 dontWaitForSwappedKey(c,ln->value);
92f8e882 2124 }
b3e3d0d7 2125 listRelease(c->io_keys);
befec3cd 2126 /* Master/slave cleanup */
ed9b544e 2127 if (c->flags & REDIS_SLAVE) {
6208b3a7 2128 if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1)
2129 close(c->repldbfd);
87eca727 2130 list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
2131 ln = listSearchKey(l,c);
dfc5e96c 2132 redisAssert(ln != NULL);
87eca727 2133 listDelNode(l,ln);
ed9b544e 2134 }
2135 if (c->flags & REDIS_MASTER) {
2136 server.master = NULL;
2137 server.replstate = REDIS_REPL_CONNECT;
2138 }
befec3cd 2139 /* Release memory */
93ea3759 2140 zfree(c->argv);
e8a74421 2141 zfree(c->mbargv);
6e469882 2142 freeClientMultiState(c);
ed9b544e 2143 zfree(c);
2144}
2145
cc30e368 2146#define GLUEREPLY_UP_TO (1024)
ed9b544e 2147static void glueReplyBuffersIfNeeded(redisClient *c) {
c28b42ac 2148 int copylen = 0;
2149 char buf[GLUEREPLY_UP_TO];
6208b3a7 2150 listNode *ln;
c7df85a4 2151 listIter li;
ed9b544e 2152 robj *o;
2153
c7df85a4 2154 listRewind(c->reply,&li);
2155 while((ln = listNext(&li))) {
c28b42ac 2156 int objlen;
2157
ed9b544e 2158 o = ln->value;
c28b42ac 2159 objlen = sdslen(o->ptr);
2160 if (copylen + objlen <= GLUEREPLY_UP_TO) {
2161 memcpy(buf+copylen,o->ptr,objlen);
2162 copylen += objlen;
ed9b544e 2163 listDelNode(c->reply,ln);
c28b42ac 2164 } else {
2165 if (copylen == 0) return;
2166 break;
ed9b544e 2167 }
ed9b544e 2168 }
c28b42ac 2169 /* Now the output buffer is empty, add the new single element */
2170 o = createObject(REDIS_STRING,sdsnewlen(buf,copylen));
2171 listAddNodeHead(c->reply,o);
ed9b544e 2172}
2173
2174static void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
2175 redisClient *c = privdata;
2176 int nwritten = 0, totwritten = 0, objlen;
2177 robj *o;
2178 REDIS_NOTUSED(el);
2179 REDIS_NOTUSED(mask);
2180
2895e862 2181 /* Use writev() if we have enough buffers to send */
7ea870c0 2182 if (!server.glueoutputbuf &&
e0a62c7f 2183 listLength(c->reply) > REDIS_WRITEV_THRESHOLD &&
7ea870c0 2184 !(c->flags & REDIS_MASTER))
2895e862 2185 {
2186 sendReplyToClientWritev(el, fd, privdata, mask);
2187 return;
2188 }
2895e862 2189
ed9b544e 2190 while(listLength(c->reply)) {
c28b42ac 2191 if (server.glueoutputbuf && listLength(c->reply) > 1)
2192 glueReplyBuffersIfNeeded(c);
2193
ed9b544e 2194 o = listNodeValue(listFirst(c->reply));
2195 objlen = sdslen(o->ptr);
2196
2197 if (objlen == 0) {
2198 listDelNode(c->reply,listFirst(c->reply));
2199 continue;
2200 }
2201
2202 if (c->flags & REDIS_MASTER) {
6f376729 2203 /* Don't reply to a master */
ed9b544e 2204 nwritten = objlen - c->sentlen;
2205 } else {
a4d1ba9a 2206 nwritten = write(fd, ((char*)o->ptr)+c->sentlen, objlen - c->sentlen);
ed9b544e 2207 if (nwritten <= 0) break;
2208 }
2209 c->sentlen += nwritten;
2210 totwritten += nwritten;
2211 /* If we fully sent the object on head go to the next one */
2212 if (c->sentlen == objlen) {
2213 listDelNode(c->reply,listFirst(c->reply));
2214 c->sentlen = 0;
2215 }
6f376729 2216 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
12f9d551 2217 * bytes, in a single threaded server it's a good idea to serve
6f376729 2218 * other clients as well, even if a very large request comes from
2219 * super fast link that is always able to accept data (in real world
12f9d551 2220 * scenario think about 'KEYS *' against the loopback interfae) */
6f376729 2221 if (totwritten > REDIS_MAX_WRITE_PER_EVENT) break;
ed9b544e 2222 }
2223 if (nwritten == -1) {
2224 if (errno == EAGAIN) {
2225 nwritten = 0;
2226 } else {
f870935d 2227 redisLog(REDIS_VERBOSE,
ed9b544e 2228 "Error writing to client: %s", strerror(errno));
2229 freeClient(c);
2230 return;
2231 }
2232 }
2233 if (totwritten > 0) c->lastinteraction = time(NULL);
2234 if (listLength(c->reply) == 0) {
2235 c->sentlen = 0;
2236 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
2237 }
2238}
2239
2895e862 2240static void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask)
2241{
2242 redisClient *c = privdata;
2243 int nwritten = 0, totwritten = 0, objlen, willwrite;
2244 robj *o;
2245 struct iovec iov[REDIS_WRITEV_IOVEC_COUNT];
2246 int offset, ion = 0;
2247 REDIS_NOTUSED(el);
2248 REDIS_NOTUSED(mask);
2249
2250 listNode *node;
2251 while (listLength(c->reply)) {
2252 offset = c->sentlen;
2253 ion = 0;
2254 willwrite = 0;
2255
2256 /* fill-in the iov[] array */
2257 for(node = listFirst(c->reply); node; node = listNextNode(node)) {
2258 o = listNodeValue(node);
2259 objlen = sdslen(o->ptr);
2260
e0a62c7f 2261 if (totwritten + objlen - offset > REDIS_MAX_WRITE_PER_EVENT)
2895e862 2262 break;
2263
2264 if(ion == REDIS_WRITEV_IOVEC_COUNT)
2265 break; /* no more iovecs */
2266
2267 iov[ion].iov_base = ((char*)o->ptr) + offset;
2268 iov[ion].iov_len = objlen - offset;
2269 willwrite += objlen - offset;
2270 offset = 0; /* just for the first item */
2271 ion++;
2272 }
2273
2274 if(willwrite == 0)
2275 break;
2276
2277 /* write all collected blocks at once */
2278 if((nwritten = writev(fd, iov, ion)) < 0) {
2279 if (errno != EAGAIN) {
f870935d 2280 redisLog(REDIS_VERBOSE,
2895e862 2281 "Error writing to client: %s", strerror(errno));
2282 freeClient(c);
2283 return;
2284 }
2285 break;
2286 }
2287
2288 totwritten += nwritten;
2289 offset = c->sentlen;
2290
2291 /* remove written robjs from c->reply */
2292 while (nwritten && listLength(c->reply)) {
2293 o = listNodeValue(listFirst(c->reply));
2294 objlen = sdslen(o->ptr);
2295
2296 if(nwritten >= objlen - offset) {
2297 listDelNode(c->reply, listFirst(c->reply));
2298 nwritten -= objlen - offset;
2299 c->sentlen = 0;
2300 } else {
2301 /* partial write */
2302 c->sentlen += nwritten;
2303 break;
2304 }
2305 offset = 0;
2306 }
2307 }
2308
e0a62c7f 2309 if (totwritten > 0)
2895e862 2310 c->lastinteraction = time(NULL);
2311
2312 if (listLength(c->reply) == 0) {
2313 c->sentlen = 0;
2314 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
2315 }
2316}
2317
1a132bbc
PN
2318static int qsortRedisCommands(const void *r1, const void *r2) {
2319 return strcasecmp(
2320 ((struct redisCommand*)r1)->name,
2321 ((struct redisCommand*)r2)->name);
2322}
2323
2324static void sortCommandTable() {
1a132bbc
PN
2325 /* Copy and sort the read-only version of the command table */
2326 commandTable = (struct redisCommand*)malloc(sizeof(readonlyCommandTable));
2327 memcpy(commandTable,readonlyCommandTable,sizeof(readonlyCommandTable));
d55d5c5d 2328 qsort(commandTable,
2329 sizeof(readonlyCommandTable)/sizeof(struct redisCommand),
2330 sizeof(struct redisCommand),qsortRedisCommands);
1a132bbc
PN
2331}
2332
ed9b544e 2333static struct redisCommand *lookupCommand(char *name) {
1a132bbc
PN
2334 struct redisCommand tmp = {name,NULL,0,0,NULL,0,0,0};
2335 return bsearch(
2336 &tmp,
2337 commandTable,
d55d5c5d 2338 sizeof(readonlyCommandTable)/sizeof(struct redisCommand),
1a132bbc
PN
2339 sizeof(struct redisCommand),
2340 qsortRedisCommands);
ed9b544e 2341}
2342
2343/* resetClient prepare the client to process the next command */
2344static void resetClient(redisClient *c) {
2345 freeClientArgv(c);
2346 c->bulklen = -1;
e8a74421 2347 c->multibulk = 0;
ed9b544e 2348}
2349
6e469882 2350/* Call() is the core of Redis execution of a command */
2351static void call(redisClient *c, struct redisCommand *cmd) {
2352 long long dirty;
2353
2354 dirty = server.dirty;
2355 cmd->proc(c);
4005fef1 2356 dirty = server.dirty-dirty;
2357
2358 if (server.appendonly && dirty)
6e469882 2359 feedAppendOnlyFile(cmd,c->db->id,c->argv,c->argc);
4005fef1 2360 if ((dirty || cmd->flags & REDIS_CMD_FORCE_REPLICATION) &&
2361 listLength(server.slaves))
248ea310 2362 replicationFeedSlaves(server.slaves,c->db->id,c->argv,c->argc);
6e469882 2363 if (listLength(server.monitors))
dd142b9c 2364 replicationFeedMonitors(server.monitors,c->db->id,c->argv,c->argc);
6e469882 2365 server.stat_numcommands++;
2366}
2367
ed9b544e 2368/* If this function gets called we already read a whole
2369 * command, argments are in the client argv/argc fields.
2370 * processCommand() execute the command or prepare the
2371 * server for a bulk read from the client.
2372 *
2373 * If 1 is returned the client is still alive and valid and
2374 * and other operations can be performed by the caller. Otherwise
2375 * if 0 is returned the client was destroied (i.e. after QUIT). */
2376static int processCommand(redisClient *c) {
2377 struct redisCommand *cmd;
ed9b544e 2378
3fd78bcd 2379 /* Free some memory if needed (maxmemory setting) */
2380 if (server.maxmemory) freeMemoryIfNeeded();
2381
e8a74421 2382 /* Handle the multi bulk command type. This is an alternative protocol
2383 * supported by Redis in order to receive commands that are composed of
2384 * multiple binary-safe "bulk" arguments. The latency of processing is
2385 * a bit higher but this allows things like multi-sets, so if this
2386 * protocol is used only for MSET and similar commands this is a big win. */
2387 if (c->multibulk == 0 && c->argc == 1 && ((char*)(c->argv[0]->ptr))[0] == '*') {
2388 c->multibulk = atoi(((char*)c->argv[0]->ptr)+1);
2389 if (c->multibulk <= 0) {
2390 resetClient(c);
2391 return 1;
2392 } else {
2393 decrRefCount(c->argv[c->argc-1]);
2394 c->argc--;
2395 return 1;
2396 }
2397 } else if (c->multibulk) {
2398 if (c->bulklen == -1) {
2399 if (((char*)c->argv[0]->ptr)[0] != '$') {
2400 addReplySds(c,sdsnew("-ERR multi bulk protocol error\r\n"));
2401 resetClient(c);
2402 return 1;
2403 } else {
2404 int bulklen = atoi(((char*)c->argv[0]->ptr)+1);
2405 decrRefCount(c->argv[0]);
2406 if (bulklen < 0 || bulklen > 1024*1024*1024) {
2407 c->argc--;
2408 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
2409 resetClient(c);
2410 return 1;
2411 }
2412 c->argc--;
2413 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
2414 return 1;
2415 }
2416 } else {
2417 c->mbargv = zrealloc(c->mbargv,(sizeof(robj*))*(c->mbargc+1));
2418 c->mbargv[c->mbargc] = c->argv[0];
2419 c->mbargc++;
2420 c->argc--;
2421 c->multibulk--;
2422 if (c->multibulk == 0) {
2423 robj **auxargv;
2424 int auxargc;
2425
2426 /* Here we need to swap the multi-bulk argc/argv with the
2427 * normal argc/argv of the client structure. */
2428 auxargv = c->argv;
2429 c->argv = c->mbargv;
2430 c->mbargv = auxargv;
2431
2432 auxargc = c->argc;
2433 c->argc = c->mbargc;
2434 c->mbargc = auxargc;
2435
2436 /* We need to set bulklen to something different than -1
2437 * in order for the code below to process the command without
2438 * to try to read the last argument of a bulk command as
2439 * a special argument. */
2440 c->bulklen = 0;
2441 /* continue below and process the command */
2442 } else {
2443 c->bulklen = -1;
2444 return 1;
2445 }
2446 }
2447 }
2448 /* -- end of multi bulk commands processing -- */
2449
ed9b544e 2450 /* The QUIT command is handled as a special case. Normal command
2451 * procs are unable to close the client connection safely */
bb0b03a3 2452 if (!strcasecmp(c->argv[0]->ptr,"quit")) {
ed9b544e 2453 freeClient(c);
2454 return 0;
2455 }
d5d55fc3 2456
2457 /* Now lookup the command and check ASAP about trivial error conditions
2458 * such wrong arity, bad command name and so forth. */
ed9b544e 2459 cmd = lookupCommand(c->argv[0]->ptr);
2460 if (!cmd) {
2c14807b 2461 addReplySds(c,
2462 sdscatprintf(sdsempty(), "-ERR unknown command '%s'\r\n",
2463 (char*)c->argv[0]->ptr));
ed9b544e 2464 resetClient(c);
2465 return 1;
2466 } else if ((cmd->arity > 0 && cmd->arity != c->argc) ||
2467 (c->argc < -cmd->arity)) {
454d4e43 2468 addReplySds(c,
2469 sdscatprintf(sdsempty(),
2470 "-ERR wrong number of arguments for '%s' command\r\n",
2471 cmd->name));
ed9b544e 2472 resetClient(c);
2473 return 1;
2474 } else if (cmd->flags & REDIS_CMD_BULK && c->bulklen == -1) {
d5d55fc3 2475 /* This is a bulk command, we have to read the last argument yet. */
ed9b544e 2476 int bulklen = atoi(c->argv[c->argc-1]->ptr);
2477
2478 decrRefCount(c->argv[c->argc-1]);
2479 if (bulklen < 0 || bulklen > 1024*1024*1024) {
2480 c->argc--;
2481 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
2482 resetClient(c);
2483 return 1;
2484 }
2485 c->argc--;
2486 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
2487 /* It is possible that the bulk read is already in the
8d0490e7 2488 * buffer. Check this condition and handle it accordingly.
2489 * This is just a fast path, alternative to call processInputBuffer().
2490 * It's a good idea since the code is small and this condition
2491 * happens most of the times. */
ed9b544e 2492 if ((signed)sdslen(c->querybuf) >= c->bulklen) {
2493 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
2494 c->argc++;
2495 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
2496 } else {
d5d55fc3 2497 /* Otherwise return... there is to read the last argument
2498 * from the socket. */
ed9b544e 2499 return 1;
2500 }
2501 }
942a3961 2502 /* Let's try to encode the bulk object to save space. */
2503 if (cmd->flags & REDIS_CMD_BULK)
05df7621 2504 c->argv[c->argc-1] = tryObjectEncoding(c->argv[c->argc-1]);
942a3961 2505
e63943a4 2506 /* Check if the user is authenticated */
2507 if (server.requirepass && !c->authenticated && cmd->proc != authCommand) {
2508 addReplySds(c,sdsnew("-ERR operation not permitted\r\n"));
2509 resetClient(c);
2510 return 1;
2511 }
2512
b61a28fe 2513 /* Handle the maxmemory directive */
2514 if (server.maxmemory && (cmd->flags & REDIS_CMD_DENYOOM) &&
2515 zmalloc_used_memory() > server.maxmemory)
2516 {
2517 addReplySds(c,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
2518 resetClient(c);
2519 return 1;
2520 }
2521
d6cc8867 2522 /* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
e6cca5db 2523 if ((dictSize(c->pubsub_channels) > 0 || listLength(c->pubsub_patterns) > 0)
2524 &&
ffc6b7f8 2525 cmd->proc != subscribeCommand && cmd->proc != unsubscribeCommand &&
2526 cmd->proc != psubscribeCommand && cmd->proc != punsubscribeCommand) {
2527 addReplySds(c,sdsnew("-ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context\r\n"));
d6cc8867 2528 resetClient(c);
2529 return 1;
2530 }
2531
ed9b544e 2532 /* Exec the command */
6531c94d 2533 if (c->flags & REDIS_MULTI &&
2534 cmd->proc != execCommand && cmd->proc != discardCommand &&
2535 cmd->proc != multiCommand && cmd->proc != watchCommand)
2536 {
6e469882 2537 queueMultiCommand(c,cmd);
2538 addReply(c,shared.queued);
2539 } else {
d5d55fc3 2540 if (server.vm_enabled && server.vm_max_threads > 0 &&
0a6f3f0f 2541 blockClientOnSwappedKeys(c,cmd)) return 1;
6e469882 2542 call(c,cmd);
2543 }
ed9b544e 2544
2545 /* Prepare the client for the next command */
ed9b544e 2546 resetClient(c);
2547 return 1;
2548}
2549
248ea310 2550static void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc) {
6208b3a7 2551 listNode *ln;
c7df85a4 2552 listIter li;
ed9b544e 2553 int outc = 0, j;
93ea3759 2554 robj **outv;
248ea310 2555 /* We need 1+(ARGS*3) objects since commands are using the new protocol
2556 * and we one 1 object for the first "*<count>\r\n" multibulk count, then
2557 * for every additional object we have "$<count>\r\n" + object + "\r\n". */
2558 robj *static_outv[REDIS_STATIC_ARGS*3+1];
2559 robj *lenobj;
93ea3759 2560
2561 if (argc <= REDIS_STATIC_ARGS) {
2562 outv = static_outv;
2563 } else {
248ea310 2564 outv = zmalloc(sizeof(robj*)*(argc*3+1));
93ea3759 2565 }
248ea310 2566
2567 lenobj = createObject(REDIS_STRING,
2568 sdscatprintf(sdsempty(), "*%d\r\n", argc));
2569 lenobj->refcount = 0;
2570 outv[outc++] = lenobj;
ed9b544e 2571 for (j = 0; j < argc; j++) {
248ea310 2572 lenobj = createObject(REDIS_STRING,
2573 sdscatprintf(sdsempty(),"$%lu\r\n",
2574 (unsigned long) stringObjectLen(argv[j])));
2575 lenobj->refcount = 0;
2576 outv[outc++] = lenobj;
ed9b544e 2577 outv[outc++] = argv[j];
248ea310 2578 outv[outc++] = shared.crlf;
ed9b544e 2579 }
ed9b544e 2580
40d224a9 2581 /* Increment all the refcounts at start and decrement at end in order to
2582 * be sure to free objects if there is no slave in a replication state
2583 * able to be feed with commands */
2584 for (j = 0; j < outc; j++) incrRefCount(outv[j]);
c7df85a4 2585 listRewind(slaves,&li);
2586 while((ln = listNext(&li))) {
ed9b544e 2587 redisClient *slave = ln->value;
40d224a9 2588
2589 /* Don't feed slaves that are still waiting for BGSAVE to start */
6208b3a7 2590 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) continue;
40d224a9 2591
2592 /* Feed all the other slaves, MONITORs and so on */
ed9b544e 2593 if (slave->slaveseldb != dictid) {
2594 robj *selectcmd;
2595
2596 switch(dictid) {
2597 case 0: selectcmd = shared.select0; break;
2598 case 1: selectcmd = shared.select1; break;
2599 case 2: selectcmd = shared.select2; break;
2600 case 3: selectcmd = shared.select3; break;
2601 case 4: selectcmd = shared.select4; break;
2602 case 5: selectcmd = shared.select5; break;
2603 case 6: selectcmd = shared.select6; break;
2604 case 7: selectcmd = shared.select7; break;
2605 case 8: selectcmd = shared.select8; break;
2606 case 9: selectcmd = shared.select9; break;
2607 default:
2608 selectcmd = createObject(REDIS_STRING,
2609 sdscatprintf(sdsempty(),"select %d\r\n",dictid));
2610 selectcmd->refcount = 0;
2611 break;
2612 }
2613 addReply(slave,selectcmd);
2614 slave->slaveseldb = dictid;
2615 }
2616 for (j = 0; j < outc; j++) addReply(slave,outv[j]);
ed9b544e 2617 }
40d224a9 2618 for (j = 0; j < outc; j++) decrRefCount(outv[j]);
93ea3759 2619 if (outv != static_outv) zfree(outv);
ed9b544e 2620}
2621
dd142b9c 2622static sds sdscatrepr(sds s, char *p, size_t len) {
2623 s = sdscatlen(s,"\"",1);
2624 while(len--) {
2625 switch(*p) {
2626 case '\\':
2627 case '"':
2628 s = sdscatprintf(s,"\\%c",*p);
2629 break;
2630 case '\n': s = sdscatlen(s,"\\n",1); break;
2631 case '\r': s = sdscatlen(s,"\\r",1); break;
2632 case '\t': s = sdscatlen(s,"\\t",1); break;
2633 case '\a': s = sdscatlen(s,"\\a",1); break;
2634 case '\b': s = sdscatlen(s,"\\b",1); break;
2635 default:
2636 if (isprint(*p))
2637 s = sdscatprintf(s,"%c",*p);
2638 else
2639 s = sdscatprintf(s,"\\x%02x",(unsigned char)*p);
2640 break;
2641 }
2642 p++;
2643 }
2644 return sdscatlen(s,"\"",1);
2645}
2646
2647static void replicationFeedMonitors(list *monitors, int dictid, robj **argv, int argc) {
2648 listNode *ln;
2649 listIter li;
2650 int j;
2651 sds cmdrepr = sdsnew("+");
2652 robj *cmdobj;
2653 struct timeval tv;
2654
2655 gettimeofday(&tv,NULL);
2656 cmdrepr = sdscatprintf(cmdrepr,"%ld.%ld ",(long)tv.tv_sec,(long)tv.tv_usec);
2657 if (dictid != 0) cmdrepr = sdscatprintf(cmdrepr,"(db %d) ", dictid);
2658
2659 for (j = 0; j < argc; j++) {
2660 if (argv[j]->encoding == REDIS_ENCODING_INT) {
2661 cmdrepr = sdscatprintf(cmdrepr, "%ld", (long)argv[j]->ptr);
2662 } else {
2663 cmdrepr = sdscatrepr(cmdrepr,(char*)argv[j]->ptr,
2664 sdslen(argv[j]->ptr));
2665 }
2666 if (j != argc-1)
2667 cmdrepr = sdscatlen(cmdrepr," ",1);
2668 }
2669 cmdrepr = sdscatlen(cmdrepr,"\r\n",2);
2670 cmdobj = createObject(REDIS_STRING,cmdrepr);
2671
2672 listRewind(monitors,&li);
2673 while((ln = listNext(&li))) {
2674 redisClient *monitor = ln->value;
2675 addReply(monitor,cmdobj);
2676 }
2677 decrRefCount(cmdobj);
2678}
2679
638e42ac 2680static void processInputBuffer(redisClient *c) {
ed9b544e 2681again:
4409877e 2682 /* Before to process the input buffer, make sure the client is not
2683 * waitig for a blocking operation such as BLPOP. Note that the first
2684 * iteration the client is never blocked, otherwise the processInputBuffer
2685 * would not be called at all, but after the execution of the first commands
2686 * in the input buffer the client may be blocked, and the "goto again"
2687 * will try to reiterate. The following line will make it return asap. */
92f8e882 2688 if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return;
ed9b544e 2689 if (c->bulklen == -1) {
2690 /* Read the first line of the query */
2691 char *p = strchr(c->querybuf,'\n');
2692 size_t querylen;
644fafa3 2693
ed9b544e 2694 if (p) {
2695 sds query, *argv;
2696 int argc, j;
e0a62c7f 2697
ed9b544e 2698 query = c->querybuf;
2699 c->querybuf = sdsempty();
2700 querylen = 1+(p-(query));
2701 if (sdslen(query) > querylen) {
2702 /* leave data after the first line of the query in the buffer */
2703 c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
2704 }
2705 *p = '\0'; /* remove "\n" */
2706 if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
2707 sdsupdatelen(query);
2708
2709 /* Now we can split the query in arguments */
ed9b544e 2710 argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
93ea3759 2711 sdsfree(query);
2712
2713 if (c->argv) zfree(c->argv);
2714 c->argv = zmalloc(sizeof(robj*)*argc);
93ea3759 2715
2716 for (j = 0; j < argc; j++) {
ed9b544e 2717 if (sdslen(argv[j])) {
2718 c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
2719 c->argc++;
2720 } else {
2721 sdsfree(argv[j]);
2722 }
2723 }
2724 zfree(argv);
7c49733c 2725 if (c->argc) {
2726 /* Execute the command. If the client is still valid
2727 * after processCommand() return and there is something
2728 * on the query buffer try to process the next command. */
2729 if (processCommand(c) && sdslen(c->querybuf)) goto again;
2730 } else {
2731 /* Nothing to process, argc == 0. Just process the query
2732 * buffer if it's not empty or return to the caller */
2733 if (sdslen(c->querybuf)) goto again;
2734 }
ed9b544e 2735 return;
644fafa3 2736 } else if (sdslen(c->querybuf) >= REDIS_REQUEST_MAX_SIZE) {
f870935d 2737 redisLog(REDIS_VERBOSE, "Client protocol error");
ed9b544e 2738 freeClient(c);
2739 return;
2740 }
2741 } else {
2742 /* Bulk read handling. Note that if we are at this point
2743 the client already sent a command terminated with a newline,
2744 we are reading the bulk data that is actually the last
2745 argument of the command. */
2746 int qbl = sdslen(c->querybuf);
2747
2748 if (c->bulklen <= qbl) {
2749 /* Copy everything but the final CRLF as final argument */
2750 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
2751 c->argc++;
2752 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
638e42ac 2753 /* Process the command. If the client is still valid after
2754 * the processing and there is more data in the buffer
2755 * try to parse it. */
2756 if (processCommand(c) && sdslen(c->querybuf)) goto again;
ed9b544e 2757 return;
2758 }
2759 }
2760}
2761
638e42ac 2762static void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
2763 redisClient *c = (redisClient*) privdata;
2764 char buf[REDIS_IOBUF_LEN];
2765 int nread;
2766 REDIS_NOTUSED(el);
2767 REDIS_NOTUSED(mask);
2768
2769 nread = read(fd, buf, REDIS_IOBUF_LEN);
2770 if (nread == -1) {
2771 if (errno == EAGAIN) {
2772 nread = 0;
2773 } else {
f870935d 2774 redisLog(REDIS_VERBOSE, "Reading from client: %s",strerror(errno));
638e42ac 2775 freeClient(c);
2776 return;
2777 }
2778 } else if (nread == 0) {
f870935d 2779 redisLog(REDIS_VERBOSE, "Client closed connection");
638e42ac 2780 freeClient(c);
2781 return;
2782 }
2783 if (nread) {
2784 c->querybuf = sdscatlen(c->querybuf, buf, nread);
2785 c->lastinteraction = time(NULL);
2786 } else {
2787 return;
2788 }
168ac5c6 2789 processInputBuffer(c);
638e42ac 2790}
2791
ed9b544e 2792static int selectDb(redisClient *c, int id) {
2793 if (id < 0 || id >= server.dbnum)
2794 return REDIS_ERR;
3305306f 2795 c->db = &server.db[id];
ed9b544e 2796 return REDIS_OK;
2797}
2798
40d224a9 2799static void *dupClientReplyValue(void *o) {
2800 incrRefCount((robj*)o);
12d090d2 2801 return o;
40d224a9 2802}
2803
ffc6b7f8 2804static int listMatchObjects(void *a, void *b) {
bf028098 2805 return equalStringObjects(a,b);
ffc6b7f8 2806}
2807
ed9b544e 2808static redisClient *createClient(int fd) {
2809 redisClient *c = zmalloc(sizeof(*c));
2810
2811 anetNonBlock(NULL,fd);
2812 anetTcpNoDelay(NULL,fd);
2813 if (!c) return NULL;
2814 selectDb(c,0);
2815 c->fd = fd;
2816 c->querybuf = sdsempty();
2817 c->argc = 0;
93ea3759 2818 c->argv = NULL;
ed9b544e 2819 c->bulklen = -1;
e8a74421 2820 c->multibulk = 0;
2821 c->mbargc = 0;
2822 c->mbargv = NULL;
ed9b544e 2823 c->sentlen = 0;
2824 c->flags = 0;
2825 c->lastinteraction = time(NULL);
abcb223e 2826 c->authenticated = 0;
40d224a9 2827 c->replstate = REDIS_REPL_NONE;
6b47e12e 2828 c->reply = listCreate();
ed9b544e 2829 listSetFreeMethod(c->reply,decrRefCount);
40d224a9 2830 listSetDupMethod(c->reply,dupClientReplyValue);
37ab76c9 2831 c->blocking_keys = NULL;
2832 c->blocking_keys_num = 0;
92f8e882 2833 c->io_keys = listCreate();
87c68815 2834 c->watched_keys = listCreate();
92f8e882 2835 listSetFreeMethod(c->io_keys,decrRefCount);
ffc6b7f8 2836 c->pubsub_channels = dictCreate(&setDictType,NULL);
2837 c->pubsub_patterns = listCreate();
2838 listSetFreeMethod(c->pubsub_patterns,decrRefCount);
2839 listSetMatchMethod(c->pubsub_patterns,listMatchObjects);
ed9b544e 2840 if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
266373b2 2841 readQueryFromClient, c) == AE_ERR) {
ed9b544e 2842 freeClient(c);
2843 return NULL;
2844 }
6b47e12e 2845 listAddNodeTail(server.clients,c);
6e469882 2846 initClientMultiState(c);
ed9b544e 2847 return c;
2848}
2849
2850static void addReply(redisClient *c, robj *obj) {
2851 if (listLength(c->reply) == 0 &&
6208b3a7 2852 (c->replstate == REDIS_REPL_NONE ||
2853 c->replstate == REDIS_REPL_ONLINE) &&
ed9b544e 2854 aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
266373b2 2855 sendReplyToClient, c) == AE_ERR) return;
e3cadb8a 2856
2857 if (server.vm_enabled && obj->storage != REDIS_VM_MEMORY) {
2858 obj = dupStringObject(obj);
2859 obj->refcount = 0; /* getDecodedObject() will increment the refcount */
2860 }
9d65a1bb 2861 listAddNodeTail(c->reply,getDecodedObject(obj));
ed9b544e 2862}
2863
2864static void addReplySds(redisClient *c, sds s) {
2865 robj *o = createObject(REDIS_STRING,s);
2866 addReply(c,o);
2867 decrRefCount(o);
2868}
2869
e2665397 2870static void addReplyDouble(redisClient *c, double d) {
2871 char buf[128];
2872
2873 snprintf(buf,sizeof(buf),"%.17g",d);
682ac724 2874 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n%s\r\n",
83c6a618 2875 (unsigned long) strlen(buf),buf));
e2665397 2876}
2877
aa7c2934
PN
2878static void addReplyLongLong(redisClient *c, long long ll) {
2879 char buf[128];
2880 size_t len;
2881
2882 if (ll == 0) {
2883 addReply(c,shared.czero);
2884 return;
2885 } else if (ll == 1) {
2886 addReply(c,shared.cone);
2887 return;
2888 }
482b672d 2889 buf[0] = ':';
2890 len = ll2string(buf+1,sizeof(buf)-1,ll);
2891 buf[len+1] = '\r';
2892 buf[len+2] = '\n';
2893 addReplySds(c,sdsnewlen(buf,len+3));
aa7c2934
PN
2894}
2895
92b27fe9 2896static void addReplyUlong(redisClient *c, unsigned long ul) {
2897 char buf[128];
2898 size_t len;
2899
dd88747b 2900 if (ul == 0) {
2901 addReply(c,shared.czero);
2902 return;
2903 } else if (ul == 1) {
2904 addReply(c,shared.cone);
2905 return;
2906 }
92b27fe9 2907 len = snprintf(buf,sizeof(buf),":%lu\r\n",ul);
2908 addReplySds(c,sdsnewlen(buf,len));
2909}
2910
942a3961 2911static void addReplyBulkLen(redisClient *c, robj *obj) {
482b672d 2912 size_t len, intlen;
2913 char buf[128];
942a3961 2914
2915 if (obj->encoding == REDIS_ENCODING_RAW) {
2916 len = sdslen(obj->ptr);
2917 } else {
2918 long n = (long)obj->ptr;
2919
e054afda 2920 /* Compute how many bytes will take this integer as a radix 10 string */
942a3961 2921 len = 1;
2922 if (n < 0) {
2923 len++;
2924 n = -n;
2925 }
2926 while((n = n/10) != 0) {
2927 len++;
2928 }
2929 }
482b672d 2930 buf[0] = '$';
2931 intlen = ll2string(buf+1,sizeof(buf)-1,(long long)len);
2932 buf[intlen+1] = '\r';
2933 buf[intlen+2] = '\n';
2934 addReplySds(c,sdsnewlen(buf,intlen+3));
942a3961 2935}
2936
dd88747b 2937static void addReplyBulk(redisClient *c, robj *obj) {
2938 addReplyBulkLen(c,obj);
2939 addReply(c,obj);
2940 addReply(c,shared.crlf);
2941}
2942
09241813 2943static void addReplyBulkSds(redisClient *c, sds s) {
2944 robj *o = createStringObject(s, sdslen(s));
2945 addReplyBulk(c,o);
2946 decrRefCount(o);
2947}
2948
500ece7c 2949/* In the CONFIG command we need to add vanilla C string as bulk replies */
2950static void addReplyBulkCString(redisClient *c, char *s) {
2951 if (s == NULL) {
2952 addReply(c,shared.nullbulk);
2953 } else {
2954 robj *o = createStringObject(s,strlen(s));
2955 addReplyBulk(c,o);
2956 decrRefCount(o);
2957 }
2958}
2959
ed9b544e 2960static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
2961 int cport, cfd;
2962 char cip[128];
285add55 2963 redisClient *c;
ed9b544e 2964 REDIS_NOTUSED(el);
2965 REDIS_NOTUSED(mask);
2966 REDIS_NOTUSED(privdata);
2967
2968 cfd = anetAccept(server.neterr, fd, cip, &cport);
2969 if (cfd == AE_ERR) {
f870935d 2970 redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr);
ed9b544e 2971 return;
2972 }
f870935d 2973 redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport);
285add55 2974 if ((c = createClient(cfd)) == NULL) {
ed9b544e 2975 redisLog(REDIS_WARNING,"Error allocating resoures for the client");
2976 close(cfd); /* May be already closed, just ingore errors */
2977 return;
2978 }
285add55 2979 /* If maxclient directive is set and this is one client more... close the
2980 * connection. Note that we create the client instead to check before
2981 * for this condition, since now the socket is already set in nonblocking
2982 * mode and we can send an error for free using the Kernel I/O */
2983 if (server.maxclients && listLength(server.clients) > server.maxclients) {
2984 char *err = "-ERR max number of clients reached\r\n";
2985
2986 /* That's a best effort error message, don't check write errors */
fee803ba 2987 if (write(c->fd,err,strlen(err)) == -1) {
2988 /* Nothing to do, Just to avoid the warning... */
2989 }
285add55 2990 freeClient(c);
2991 return;
2992 }
ed9b544e 2993 server.stat_numconnections++;
2994}
2995
2996/* ======================= Redis objects implementation ===================== */
2997
2998static robj *createObject(int type, void *ptr) {
2999 robj *o;
3000
a5819310 3001 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
ed9b544e 3002 if (listLength(server.objfreelist)) {
3003 listNode *head = listFirst(server.objfreelist);
3004 o = listNodeValue(head);
3005 listDelNode(server.objfreelist,head);
a5819310 3006 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
ed9b544e 3007 } else {
560db612 3008 if (server.vm_enabled)
a5819310 3009 pthread_mutex_unlock(&server.obj_freelist_mutex);
560db612 3010 o = zmalloc(sizeof(*o));
ed9b544e 3011 }
ed9b544e 3012 o->type = type;
942a3961 3013 o->encoding = REDIS_ENCODING_RAW;
ed9b544e 3014 o->ptr = ptr;
3015 o->refcount = 1;
3a66edc7 3016 if (server.vm_enabled) {
1064ef87 3017 /* Note that this code may run in the context of an I/O thread
560db612 3018 * and accessing server.lruclock in theory is an error
1064ef87 3019 * (no locks). But in practice this is safe, and even if we read
560db612 3020 * garbage Redis will not fail. */
3021 o->lru = server.lruclock;
3a66edc7 3022 o->storage = REDIS_VM_MEMORY;
3023 }
ed9b544e 3024 return o;
3025}
3026
3027static robj *createStringObject(char *ptr, size_t len) {
3028 return createObject(REDIS_STRING,sdsnewlen(ptr,len));
3029}
3030
3f973463
PN
3031static robj *createStringObjectFromLongLong(long long value) {
3032 robj *o;
3033 if (value >= 0 && value < REDIS_SHARED_INTEGERS) {
3034 incrRefCount(shared.integers[value]);
3035 o = shared.integers[value];
3036 } else {
3f973463 3037 if (value >= LONG_MIN && value <= LONG_MAX) {
10dea8dc 3038 o = createObject(REDIS_STRING, NULL);
3f973463
PN
3039 o->encoding = REDIS_ENCODING_INT;
3040 o->ptr = (void*)((long)value);
3041 } else {
ee14da56 3042 o = createObject(REDIS_STRING,sdsfromlonglong(value));
3f973463
PN
3043 }
3044 }
3045 return o;
3046}
3047
4ef8de8a 3048static robj *dupStringObject(robj *o) {
b9bc0eef 3049 assert(o->encoding == REDIS_ENCODING_RAW);
4ef8de8a 3050 return createStringObject(o->ptr,sdslen(o->ptr));
3051}
3052
ed9b544e 3053static robj *createListObject(void) {
3054 list *l = listCreate();
1cd92e7f 3055 robj *o = createObject(REDIS_LIST,l);
ed9b544e 3056 listSetFreeMethod(l,decrRefCount);
1cd92e7f
PN
3057 o->encoding = REDIS_ENCODING_LIST;
3058 return o;
3059}
3060
3061static robj *createZiplistObject(void) {
3062 unsigned char *zl = ziplistNew();
3063 robj *o = createObject(REDIS_LIST,zl);
3064 o->encoding = REDIS_ENCODING_ZIPLIST;
3065 return o;
ed9b544e 3066}
3067
3068static robj *createSetObject(void) {
3069 dict *d = dictCreate(&setDictType,NULL);
35cabcb5
PN
3070 robj *o = createObject(REDIS_SET,d);
3071 o->encoding = REDIS_ENCODING_HT;
3072 return o;
ed9b544e 3073}
3074
d0b58d53
PN
3075static robj *createIntsetObject(void) {
3076 intset *is = intsetNew();
3077 robj *o = createObject(REDIS_SET,is);
3078 o->encoding = REDIS_ENCODING_INTSET;
3079 return o;
3080}
3081
5234952b 3082static robj *createHashObject(void) {
3083 /* All the Hashes start as zipmaps. Will be automatically converted
3084 * into hash tables if there are enough elements or big elements
3085 * inside. */
3086 unsigned char *zm = zipmapNew();
3087 robj *o = createObject(REDIS_HASH,zm);
3088 o->encoding = REDIS_ENCODING_ZIPMAP;
3089 return o;
3090}
3091
1812e024 3092static robj *createZsetObject(void) {
6b47e12e 3093 zset *zs = zmalloc(sizeof(*zs));
3094
3095 zs->dict = dictCreate(&zsetDictType,NULL);
3096 zs->zsl = zslCreate();
3097 return createObject(REDIS_ZSET,zs);
1812e024 3098}
3099
ed9b544e 3100static void freeStringObject(robj *o) {
942a3961 3101 if (o->encoding == REDIS_ENCODING_RAW) {
3102 sdsfree(o->ptr);
3103 }
ed9b544e 3104}
3105
3106static void freeListObject(robj *o) {
c7d9d662
PN
3107 switch (o->encoding) {
3108 case REDIS_ENCODING_LIST:
3109 listRelease((list*) o->ptr);
3110 break;
3111 case REDIS_ENCODING_ZIPLIST:
3112 zfree(o->ptr);
3113 break;
3114 default:
3115 redisPanic("Unknown list encoding type");
3116 }
ed9b544e 3117}
3118
3119static void freeSetObject(robj *o) {
d0b58d53
PN
3120 switch (o->encoding) {
3121 case REDIS_ENCODING_HT:
3122 dictRelease((dict*) o->ptr);
3123 break;
3124 case REDIS_ENCODING_INTSET:
3125 zfree(o->ptr);
3126 break;
3127 default:
3128 redisPanic("Unknown set encoding type");
3129 }
ed9b544e 3130}
3131
fd8ccf44 3132static void freeZsetObject(robj *o) {
3133 zset *zs = o->ptr;
3134
3135 dictRelease(zs->dict);
3136 zslFree(zs->zsl);
3137 zfree(zs);
3138}
3139
ed9b544e 3140static void freeHashObject(robj *o) {
cbba7dd7 3141 switch (o->encoding) {
3142 case REDIS_ENCODING_HT:
3143 dictRelease((dict*) o->ptr);
3144 break;
3145 case REDIS_ENCODING_ZIPMAP:
3146 zfree(o->ptr);
3147 break;
3148 default:
f83c6cb5 3149 redisPanic("Unknown hash encoding type");
cbba7dd7 3150 break;
3151 }
ed9b544e 3152}
3153
3154static void incrRefCount(robj *o) {
3155 o->refcount++;
3156}
3157
3158static void decrRefCount(void *obj) {
3159 robj *o = obj;
94754ccc 3160
560db612 3161 /* Object is a swapped out value, or in the process of being loaded. */
996cb5f7 3162 if (server.vm_enabled &&
3163 (o->storage == REDIS_VM_SWAPPED || o->storage == REDIS_VM_LOADING))
3164 {
560db612 3165 vmpointer *vp = obj;
3166 if (o->storage == REDIS_VM_LOADING) vmCancelThreadedIOJob(o);
3167 vmMarkPagesFree(vp->page,vp->usedpages);
7d98e08c 3168 server.vm_stats_swapped_objects--;
560db612 3169 zfree(vp);
a35ddf12 3170 return;
3171 }
560db612 3172
3173 if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0");
e4ed181d 3174 /* Object is in memory, or in the process of being swapped out.
3175 *
3176 * If the object is being swapped out, abort the operation on
3177 * decrRefCount even if the refcount does not drop to 0: the object
3178 * is referenced at least two times, as value of the key AND as
3179 * job->val in the iojob. So if we don't invalidate the iojob, when it is
3180 * done but the relevant key was removed in the meantime, the
3181 * complete jobs handler will not find the key about the job and the
3182 * assert will fail. */
3183 if (server.vm_enabled && o->storage == REDIS_VM_SWAPPING)
3184 vmCancelThreadedIOJob(o);
ed9b544e 3185 if (--(o->refcount) == 0) {
3186 switch(o->type) {
3187 case REDIS_STRING: freeStringObject(o); break;
3188 case REDIS_LIST: freeListObject(o); break;
3189 case REDIS_SET: freeSetObject(o); break;
fd8ccf44 3190 case REDIS_ZSET: freeZsetObject(o); break;
ed9b544e 3191 case REDIS_HASH: freeHashObject(o); break;
f83c6cb5 3192 default: redisPanic("Unknown object type"); break;
ed9b544e 3193 }
a5819310 3194 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
ed9b544e 3195 if (listLength(server.objfreelist) > REDIS_OBJFREELIST_MAX ||
3196 !listAddNodeHead(server.objfreelist,o))
3197 zfree(o);
a5819310 3198 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
ed9b544e 3199 }
3200}
3201
92b27fe9 3202static int checkType(redisClient *c, robj *o, int type) {
3203 if (o->type != type) {
3204 addReply(c,shared.wrongtypeerr);
3205 return 1;
3206 }
3207 return 0;
3208}
3209
724a51b1 3210/* Check if the nul-terminated string 's' can be represented by a long
3211 * (that is, is a number that fits into long without any other space or
3212 * character before or after the digits).
3213 *
3214 * If so, the function returns REDIS_OK and *longval is set to the value
3215 * of the number. Otherwise REDIS_ERR is returned */
f69f2cba 3216static int isStringRepresentableAsLong(sds s, long *longval) {
724a51b1 3217 char buf[32], *endptr;
3218 long value;
3219 int slen;
e0a62c7f 3220
724a51b1 3221 value = strtol(s, &endptr, 10);
3222 if (endptr[0] != '\0') return REDIS_ERR;
ee14da56 3223 slen = ll2string(buf,32,value);
724a51b1 3224
3225 /* If the number converted back into a string is not identical
3226 * then it's not possible to encode the string as integer */
f69f2cba 3227 if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR;
724a51b1 3228 if (longval) *longval = value;
3229 return REDIS_OK;
3230}
3231
942a3961 3232/* Try to encode a string object in order to save space */
05df7621 3233static robj *tryObjectEncoding(robj *o) {
942a3961 3234 long value;
942a3961 3235 sds s = o->ptr;
3305306f 3236
942a3961 3237 if (o->encoding != REDIS_ENCODING_RAW)
05df7621 3238 return o; /* Already encoded */
3305306f 3239
05df7621 3240 /* It's not safe to encode shared objects: shared objects can be shared
942a3961 3241 * everywhere in the "object space" of Redis. Encoded objects can only
3242 * appear as "values" (and not, for instance, as keys) */
05df7621 3243 if (o->refcount > 1) return o;
3305306f 3244
942a3961 3245 /* Currently we try to encode only strings */
dfc5e96c 3246 redisAssert(o->type == REDIS_STRING);
94754ccc 3247
724a51b1 3248 /* Check if we can represent this string as a long integer */
05df7621 3249 if (isStringRepresentableAsLong(s,&value) == REDIS_ERR) return o;
942a3961 3250
3251 /* Ok, this object can be encoded */
05df7621 3252 if (value >= 0 && value < REDIS_SHARED_INTEGERS) {
3253 decrRefCount(o);
3254 incrRefCount(shared.integers[value]);
3255 return shared.integers[value];
3256 } else {
3257 o->encoding = REDIS_ENCODING_INT;
3258 sdsfree(o->ptr);
3259 o->ptr = (void*) value;
3260 return o;
3261 }
942a3961 3262}
3263
9d65a1bb 3264/* Get a decoded version of an encoded object (returned as a new object).
3265 * If the object is already raw-encoded just increment the ref count. */
3266static robj *getDecodedObject(robj *o) {
942a3961 3267 robj *dec;
e0a62c7f 3268
9d65a1bb 3269 if (o->encoding == REDIS_ENCODING_RAW) {
3270 incrRefCount(o);
3271 return o;
3272 }
942a3961 3273 if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) {
3274 char buf[32];
3275
ee14da56 3276 ll2string(buf,32,(long)o->ptr);
942a3961 3277 dec = createStringObject(buf,strlen(buf));
3278 return dec;
3279 } else {
08ee9b57 3280 redisPanic("Unknown encoding type");
942a3961 3281 }
3305306f 3282}
3283
d7f43c08 3284/* Compare two string objects via strcmp() or alike.
3285 * Note that the objects may be integer-encoded. In such a case we
ee14da56 3286 * use ll2string() to get a string representation of the numbers on the stack
1fd9bc8a 3287 * and compare the strings, it's much faster than calling getDecodedObject().
3288 *
3289 * Important note: if objects are not integer encoded, but binary-safe strings,
3290 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
3291 * binary safe. */
724a51b1 3292static int compareStringObjects(robj *a, robj *b) {
dfc5e96c 3293 redisAssert(a->type == REDIS_STRING && b->type == REDIS_STRING);
d7f43c08 3294 char bufa[128], bufb[128], *astr, *bstr;
3295 int bothsds = 1;
724a51b1 3296
e197b441 3297 if (a == b) return 0;
d7f43c08 3298 if (a->encoding != REDIS_ENCODING_RAW) {
ee14da56 3299 ll2string(bufa,sizeof(bufa),(long) a->ptr);
d7f43c08 3300 astr = bufa;
3301 bothsds = 0;
724a51b1 3302 } else {
d7f43c08 3303 astr = a->ptr;
724a51b1 3304 }
d7f43c08 3305 if (b->encoding != REDIS_ENCODING_RAW) {
ee14da56 3306 ll2string(bufb,sizeof(bufb),(long) b->ptr);
d7f43c08 3307 bstr = bufb;
3308 bothsds = 0;
3309 } else {
3310 bstr = b->ptr;
3311 }
3312 return bothsds ? sdscmp(astr,bstr) : strcmp(astr,bstr);
724a51b1 3313}
3314
bf028098 3315/* Equal string objects return 1 if the two objects are the same from the
3316 * point of view of a string comparison, otherwise 0 is returned. Note that
3317 * this function is faster then checking for (compareStringObject(a,b) == 0)
3318 * because it can perform some more optimization. */
3319static int equalStringObjects(robj *a, robj *b) {
3320 if (a->encoding != REDIS_ENCODING_RAW && b->encoding != REDIS_ENCODING_RAW){
3321 return a->ptr == b->ptr;
3322 } else {
3323 return compareStringObjects(a,b) == 0;
3324 }
3325}
3326
0ea663ea 3327static size_t stringObjectLen(robj *o) {
dfc5e96c 3328 redisAssert(o->type == REDIS_STRING);
0ea663ea 3329 if (o->encoding == REDIS_ENCODING_RAW) {
3330 return sdslen(o->ptr);
3331 } else {
3332 char buf[32];
3333
ee14da56 3334 return ll2string(buf,32,(long)o->ptr);
0ea663ea 3335 }
3336}
3337
bd79a6bd
PN
3338static int getDoubleFromObject(robj *o, double *target) {
3339 double value;
682c73e8 3340 char *eptr;
bbe025e0 3341
bd79a6bd
PN
3342 if (o == NULL) {
3343 value = 0;
3344 } else {
3345 redisAssert(o->type == REDIS_STRING);
3346 if (o->encoding == REDIS_ENCODING_RAW) {
3347 value = strtod(o->ptr, &eptr);
682c73e8 3348 if (eptr[0] != '\0') return REDIS_ERR;
bd79a6bd
PN
3349 } else if (o->encoding == REDIS_ENCODING_INT) {
3350 value = (long)o->ptr;
3351 } else {
946342c1 3352 redisPanic("Unknown string encoding");
bd79a6bd
PN
3353 }
3354 }
3355
bd79a6bd
PN
3356 *target = value;
3357 return REDIS_OK;
3358}
bbe025e0 3359
bd79a6bd
PN
3360static int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg) {
3361 double value;
3362 if (getDoubleFromObject(o, &value) != REDIS_OK) {
3363 if (msg != NULL) {
3364 addReplySds(c, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg));
3365 } else {
3366 addReplySds(c, sdsnew("-ERR value is not a double\r\n"));
3367 }
bbe025e0
AM
3368 return REDIS_ERR;
3369 }
3370
bd79a6bd 3371 *target = value;
bbe025e0
AM
3372 return REDIS_OK;
3373}
3374
bd79a6bd
PN
3375static int getLongLongFromObject(robj *o, long long *target) {
3376 long long value;
682c73e8 3377 char *eptr;
bbe025e0 3378
bd79a6bd
PN
3379 if (o == NULL) {
3380 value = 0;
3381 } else {
3382 redisAssert(o->type == REDIS_STRING);
3383 if (o->encoding == REDIS_ENCODING_RAW) {
3384 value = strtoll(o->ptr, &eptr, 10);
682c73e8 3385 if (eptr[0] != '\0') return REDIS_ERR;
bd79a6bd
PN
3386 } else if (o->encoding == REDIS_ENCODING_INT) {
3387 value = (long)o->ptr;
3388 } else {
946342c1 3389 redisPanic("Unknown string encoding");
bd79a6bd
PN
3390 }
3391 }
3392
d0b58d53 3393 if (target) *target = value;
bd79a6bd
PN
3394 return REDIS_OK;
3395}
bbe025e0 3396
bd79a6bd
PN
3397static int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, const char *msg) {
3398 long long value;
3399 if (getLongLongFromObject(o, &value) != REDIS_OK) {
3400 if (msg != NULL) {
3401 addReplySds(c, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg));
3402 } else {
3403 addReplySds(c, sdsnew("-ERR value is not an integer\r\n"));
3404 }
bbe025e0
AM
3405 return REDIS_ERR;
3406 }
3407
bd79a6bd 3408 *target = value;
bbe025e0
AM
3409 return REDIS_OK;
3410}
3411
bd79a6bd
PN
3412static int getLongFromObjectOrReply(redisClient *c, robj *o, long *target, const char *msg) {
3413 long long value;
bbe025e0 3414
bd79a6bd
PN
3415 if (getLongLongFromObjectOrReply(c, o, &value, msg) != REDIS_OK) return REDIS_ERR;
3416 if (value < LONG_MIN || value > LONG_MAX) {
3417 if (msg != NULL) {
3418 addReplySds(c, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg));
3419 } else {
3420 addReplySds(c, sdsnew("-ERR value is out of range\r\n"));
3421 }
bbe025e0
AM
3422 return REDIS_ERR;
3423 }
3424
bd79a6bd 3425 *target = value;
bbe025e0
AM
3426 return REDIS_OK;
3427}
3428
612e4de8 3429/* =========================== Keyspace access API ========================== */
3430
3431static robj *lookupKey(redisDb *db, robj *key) {
09241813 3432 dictEntry *de = dictFind(db->dict,key->ptr);
612e4de8 3433 if (de) {
612e4de8 3434 robj *val = dictGetEntryVal(de);
3435
3436 if (server.vm_enabled) {
3437 if (val->storage == REDIS_VM_MEMORY ||
3438 val->storage == REDIS_VM_SWAPPING)
3439 {
3440 /* If we were swapping the object out, cancel the operation */
3441 if (val->storage == REDIS_VM_SWAPPING)
3442 vmCancelThreadedIOJob(val);
09241813 3443 /* Update the access time for the aging algorithm. */
612e4de8 3444 val->lru = server.lruclock;
3445 } else {
3446 int notify = (val->storage == REDIS_VM_LOADING);
3447
3448 /* Our value was swapped on disk. Bring it at home. */
3449 redisAssert(val->type == REDIS_VMPOINTER);
3450 val = vmLoadObject(val);
3451 dictGetEntryVal(de) = val;
3452
3453 /* Clients blocked by the VM subsystem may be waiting for
3454 * this key... */
3455 if (notify) handleClientsBlockedOnSwappedKey(db,key);
3456 }
3457 }
3458 return val;
3459 } else {
3460 return NULL;
3461 }
3462}
3463
3464static robj *lookupKeyRead(redisDb *db, robj *key) {
3465 expireIfNeeded(db,key);
3466 return lookupKey(db,key);
3467}
3468
3469static robj *lookupKeyWrite(redisDb *db, robj *key) {
3470 deleteIfVolatile(db,key);
3471 touchWatchedKey(db,key);
3472 return lookupKey(db,key);
3473}
3474
3475static robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply) {
3476 robj *o = lookupKeyRead(c->db, key);
3477 if (!o) addReply(c,reply);
3478 return o;
3479}
3480
3481static robj *lookupKeyWriteOrReply(redisClient *c, robj *key, robj *reply) {
3482 robj *o = lookupKeyWrite(c->db, key);
3483 if (!o) addReply(c,reply);
3484 return o;
3485}
3486
09241813 3487/* Add the key to the DB. If the key already exists REDIS_ERR is returned,
3488 * otherwise REDIS_OK is returned, and the caller should increment the
3489 * refcount of 'val'. */
3490static int dbAdd(redisDb *db, robj *key, robj *val) {
3491 /* Perform a lookup before adding the key, as we need to copy the
3492 * key value. */
3493 if (dictFind(db->dict, key->ptr) != NULL) {
3494 return REDIS_ERR;
3495 } else {
3496 sds copy = sdsdup(key->ptr);
3497 dictAdd(db->dict, copy, val);
3498 return REDIS_OK;
3499 }
3500}
3501
3502/* If the key does not exist, this is just like dbAdd(). Otherwise
3503 * the value associated to the key is replaced with the new one.
3504 *
3505 * On update (key already existed) 0 is returned. Otherwise 1. */
3506static int dbReplace(redisDb *db, robj *key, robj *val) {
3507 if (dictFind(db->dict,key->ptr) == NULL) {
3508 sds copy = sdsdup(key->ptr);
3509 dictAdd(db->dict, copy, val);
3510 return 1;
3511 } else {
3512 dictReplace(db->dict, key->ptr, val);
3513 return 0;
3514 }
3515}
3516
3517static int dbExists(redisDb *db, robj *key) {
3518 return dictFind(db->dict,key->ptr) != NULL;
3519}
3520
3521/* Return a random key, in form of a Redis object.
3522 * If there are no keys, NULL is returned.
3523 *
3524 * The function makes sure to return keys not already expired. */
3525static robj *dbRandomKey(redisDb *db) {
3526 struct dictEntry *de;
3527
3528 while(1) {
3529 sds key;
3530 robj *keyobj;
3531
3532 de = dictGetRandomKey(db->dict);
3533 if (de == NULL) return NULL;
3534
3535 key = dictGetEntryKey(de);
3536 keyobj = createStringObject(key,sdslen(key));
3537 if (dictFind(db->expires,key)) {
3538 if (expireIfNeeded(db,keyobj)) {
3539 decrRefCount(keyobj);
3540 continue; /* search for another key. This expired. */
3541 }
3542 }
3543 return keyobj;
3544 }
3545}
3546
3547/* Delete a key, value, and associated expiration entry if any, from the DB */
3548static int dbDelete(redisDb *db, robj *key) {
612e4de8 3549 int retval;
3550
09241813 3551 if (dictSize(db->expires)) dictDelete(db->expires,key->ptr);
3552 retval = dictDelete(db->dict,key->ptr);
612e4de8 3553
3554 return retval == DICT_OK;
3555}
3556
06233c45 3557/*============================ RDB saving/loading =========================== */
ed9b544e 3558
f78fd11b 3559static int rdbSaveType(FILE *fp, unsigned char type) {
3560 if (fwrite(&type,1,1,fp) == 0) return -1;
3561 return 0;
3562}
3563
bb32ede5 3564static int rdbSaveTime(FILE *fp, time_t t) {
3565 int32_t t32 = (int32_t) t;
3566 if (fwrite(&t32,4,1,fp) == 0) return -1;
3567 return 0;
3568}
3569
e3566d4b 3570/* check rdbLoadLen() comments for more info */
f78fd11b 3571static int rdbSaveLen(FILE *fp, uint32_t len) {
3572 unsigned char buf[2];
3573
3574 if (len < (1<<6)) {
3575 /* Save a 6 bit len */
10c43610 3576 buf[0] = (len&0xFF)|(REDIS_RDB_6BITLEN<<6);
f78fd11b 3577 if (fwrite(buf,1,1,fp) == 0) return -1;
3578 } else if (len < (1<<14)) {
3579 /* Save a 14 bit len */
10c43610 3580 buf[0] = ((len>>8)&0xFF)|(REDIS_RDB_14BITLEN<<6);
f78fd11b 3581 buf[1] = len&0xFF;
17be1a4a 3582 if (fwrite(buf,2,1,fp) == 0) return -1;
f78fd11b 3583 } else {
3584 /* Save a 32 bit len */
10c43610 3585 buf[0] = (REDIS_RDB_32BITLEN<<6);
f78fd11b 3586 if (fwrite(buf,1,1,fp) == 0) return -1;
3587 len = htonl(len);
3588 if (fwrite(&len,4,1,fp) == 0) return -1;
3589 }
3590 return 0;
3591}
3592
32a66513 3593/* Encode 'value' as an integer if possible (if integer will fit the
3594 * supported range). If the function sucessful encoded the integer
3595 * then the (up to 5 bytes) encoded representation is written in the
3596 * string pointed by 'enc' and the length is returned. Otherwise
3597 * 0 is returned. */
3598static int rdbEncodeInteger(long long value, unsigned char *enc) {
e3566d4b 3599 /* Finally check if it fits in our ranges */
3600 if (value >= -(1<<7) && value <= (1<<7)-1) {
3601 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT8;
3602 enc[1] = value&0xFF;
3603 return 2;
3604 } else if (value >= -(1<<15) && value <= (1<<15)-1) {
3605 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT16;
3606 enc[1] = value&0xFF;
3607 enc[2] = (value>>8)&0xFF;
3608 return 3;
3609 } else if (value >= -((long long)1<<31) && value <= ((long long)1<<31)-1) {
3610 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT32;
3611 enc[1] = value&0xFF;
3612 enc[2] = (value>>8)&0xFF;
3613 enc[3] = (value>>16)&0xFF;
3614 enc[4] = (value>>24)&0xFF;
3615 return 5;
3616 } else {
3617 return 0;
3618 }
3619}
3620
32a66513 3621/* String objects in the form "2391" "-100" without any space and with a
3622 * range of values that can fit in an 8, 16 or 32 bit signed value can be
3623 * encoded as integers to save space */
3624static int rdbTryIntegerEncoding(char *s, size_t len, unsigned char *enc) {
3625 long long value;
3626 char *endptr, buf[32];
3627
3628 /* Check if it's possible to encode this value as a number */
3629 value = strtoll(s, &endptr, 10);
3630 if (endptr[0] != '\0') return 0;
3631 ll2string(buf,32,value);
3632
3633 /* If the number converted back into a string is not identical
3634 * then it's not possible to encode the string as integer */
3635 if (strlen(buf) != len || memcmp(buf,s,len)) return 0;
3636
3637 return rdbEncodeInteger(value,enc);
3638}
3639
b1befe6a 3640static int rdbSaveLzfStringObject(FILE *fp, unsigned char *s, size_t len) {
3641 size_t comprlen, outlen;
774e3047 3642 unsigned char byte;
3643 void *out;
3644
3645 /* We require at least four bytes compression for this to be worth it */
b1befe6a 3646 if (len <= 4) return 0;
3647 outlen = len-4;
3a2694c4 3648 if ((out = zmalloc(outlen+1)) == NULL) return 0;
b1befe6a 3649 comprlen = lzf_compress(s, len, out, outlen);
774e3047 3650 if (comprlen == 0) {
88e85998 3651 zfree(out);
774e3047 3652 return 0;
3653 }
3654 /* Data compressed! Let's save it on disk */
3655 byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF;
3656 if (fwrite(&byte,1,1,fp) == 0) goto writeerr;
3657 if (rdbSaveLen(fp,comprlen) == -1) goto writeerr;
b1befe6a 3658 if (rdbSaveLen(fp,len) == -1) goto writeerr;
774e3047 3659 if (fwrite(out,comprlen,1,fp) == 0) goto writeerr;
88e85998 3660 zfree(out);
774e3047 3661 return comprlen;
3662
3663writeerr:
88e85998 3664 zfree(out);
774e3047 3665 return -1;
3666}
3667
e3566d4b 3668/* Save a string objet as [len][data] on disk. If the object is a string
3669 * representation of an integer value we try to safe it in a special form */
b1befe6a 3670static int rdbSaveRawString(FILE *fp, unsigned char *s, size_t len) {
e3566d4b 3671 int enclen;
10c43610 3672
774e3047 3673 /* Try integer encoding */
e3566d4b 3674 if (len <= 11) {
3675 unsigned char buf[5];
b1befe6a 3676 if ((enclen = rdbTryIntegerEncoding((char*)s,len,buf)) > 0) {
e3566d4b 3677 if (fwrite(buf,enclen,1,fp) == 0) return -1;
3678 return 0;
3679 }
3680 }
774e3047 3681
3682 /* Try LZF compression - under 20 bytes it's unable to compress even
88e85998 3683 * aaaaaaaaaaaaaaaaaa so skip it */
121f70cf 3684 if (server.rdbcompression && len > 20) {
774e3047 3685 int retval;
3686
b1befe6a 3687 retval = rdbSaveLzfStringObject(fp,s,len);
774e3047 3688 if (retval == -1) return -1;
3689 if (retval > 0) return 0;
3690 /* retval == 0 means data can't be compressed, save the old way */
3691 }
3692
3693 /* Store verbatim */
10c43610 3694 if (rdbSaveLen(fp,len) == -1) return -1;
b1befe6a 3695 if (len && fwrite(s,len,1,fp) == 0) return -1;
10c43610 3696 return 0;
3697}
3698
2796f6da
PN
3699/* Save a long long value as either an encoded string or a string. */
3700static int rdbSaveLongLongAsStringObject(FILE *fp, long long value) {
3701 unsigned char buf[32];
3702 int enclen = rdbEncodeInteger(value,buf);
3703 if (enclen > 0) {
3704 if (fwrite(buf,enclen,1,fp) == 0) return -1;
3705 } else {
3706 /* Encode as string */
3707 enclen = ll2string((char*)buf,32,value);
3708 redisAssert(enclen < 32);
3709 if (rdbSaveLen(fp,enclen) == -1) return -1;
3710 if (fwrite(buf,enclen,1,fp) == 0) return -1;
3711 }
3712 return 0;
3713}
3714
942a3961 3715/* Like rdbSaveStringObjectRaw() but handle encoded objects */
3716static int rdbSaveStringObject(FILE *fp, robj *obj) {
32a66513 3717 /* Avoid to decode the object, then encode it again, if the
3718 * object is alrady integer encoded. */
3719 if (obj->encoding == REDIS_ENCODING_INT) {
2796f6da 3720 return rdbSaveLongLongAsStringObject(fp,(long)obj->ptr);
996cb5f7 3721 } else {
2796f6da
PN
3722 redisAssert(obj->encoding == REDIS_ENCODING_RAW);
3723 return rdbSaveRawString(fp,obj->ptr,sdslen(obj->ptr));
996cb5f7 3724 }
942a3961 3725}
3726
a7866db6 3727/* Save a double value. Doubles are saved as strings prefixed by an unsigned
3728 * 8 bit integer specifing the length of the representation.
3729 * This 8 bit integer has special values in order to specify the following
3730 * conditions:
3731 * 253: not a number
3732 * 254: + inf
3733 * 255: - inf
3734 */
3735static int rdbSaveDoubleValue(FILE *fp, double val) {
3736 unsigned char buf[128];
3737 int len;
3738
3739 if (isnan(val)) {
3740 buf[0] = 253;
3741 len = 1;
3742 } else if (!isfinite(val)) {
3743 len = 1;
3744 buf[0] = (val < 0) ? 255 : 254;
3745 } else {
88e8d89f 3746#if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)
fe244589 3747 /* Check if the float is in a safe range to be casted into a
3748 * long long. We are assuming that long long is 64 bit here.
3749 * Also we are assuming that there are no implementations around where
3750 * double has precision < 52 bit.
3751 *
3752 * Under this assumptions we test if a double is inside an interval
3753 * where casting to long long is safe. Then using two castings we
3754 * make sure the decimal part is zero. If all this is true we use
3755 * integer printing function that is much faster. */
fb82e75c 3756 double min = -4503599627370495; /* (2^52)-1 */
3757 double max = 4503599627370496; /* -(2^52) */
fe244589 3758 if (val > min && val < max && val == ((double)((long long)val)))
8c096b16 3759 ll2string((char*)buf+1,sizeof(buf),(long long)val);
3760 else
88e8d89f 3761#endif
8c096b16 3762 snprintf((char*)buf+1,sizeof(buf)-1,"%.17g",val);
6c446631 3763 buf[0] = strlen((char*)buf+1);
a7866db6 3764 len = buf[0]+1;
3765 }
3766 if (fwrite(buf,len,1,fp) == 0) return -1;
3767 return 0;
3768}
3769
06233c45 3770/* Save a Redis object. */
3771static int rdbSaveObject(FILE *fp, robj *o) {
3772 if (o->type == REDIS_STRING) {
3773 /* Save a string value */
3774 if (rdbSaveStringObject(fp,o) == -1) return -1;
3775 } else if (o->type == REDIS_LIST) {
3776 /* Save a list value */
23f96494
PN
3777 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
3778 unsigned char *p;
3779 unsigned char *vstr;
3780 unsigned int vlen;
3781 long long vlong;
3782
3783 if (rdbSaveLen(fp,ziplistLen(o->ptr)) == -1) return -1;
3784 p = ziplistIndex(o->ptr,0);
3785 while(ziplistGet(p,&vstr,&vlen,&vlong)) {
3786 if (vstr) {
3787 if (rdbSaveRawString(fp,vstr,vlen) == -1)
3788 return -1;
3789 } else {
3790 if (rdbSaveLongLongAsStringObject(fp,vlong) == -1)
3791 return -1;
3792 }
3793 p = ziplistNext(o->ptr,p);
3794 }
3795 } else if (o->encoding == REDIS_ENCODING_LIST) {
3796 list *list = o->ptr;
3797 listIter li;
3798 listNode *ln;
3799
3800 if (rdbSaveLen(fp,listLength(list)) == -1) return -1;
3801 listRewind(list,&li);
3802 while((ln = listNext(&li))) {
3803 robj *eleobj = listNodeValue(ln);
3804 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
3805 }
3806 } else {
3807 redisPanic("Unknown list encoding");
06233c45 3808 }
3809 } else if (o->type == REDIS_SET) {
3810 /* Save a set value */
d0b58d53
PN
3811 if (o->encoding == REDIS_ENCODING_HT) {
3812 dict *set = o->ptr;
3813 dictIterator *di = dictGetIterator(set);
3814 dictEntry *de;
06233c45 3815
d0b58d53
PN
3816 if (rdbSaveLen(fp,dictSize(set)) == -1) return -1;
3817 while((de = dictNext(di)) != NULL) {
3818 robj *eleobj = dictGetEntryKey(de);
3819 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
3820 }
3821 dictReleaseIterator(di);
3822 } else if (o->encoding == REDIS_ENCODING_INTSET) {
3823 intset *is = o->ptr;
3824 long long llval;
3825 int i = 0;
3826
3827 if (rdbSaveLen(fp,intsetLen(is)) == -1) return -1;
3828 while(intsetGet(is,i++,&llval)) {
3829 if (rdbSaveLongLongAsStringObject(fp,llval) == -1) return -1;
3830 }
3831 } else {
3832 redisPanic("Unknown set encoding");
06233c45 3833 }
06233c45 3834 } else if (o->type == REDIS_ZSET) {
3835 /* Save a set value */
3836 zset *zs = o->ptr;
3837 dictIterator *di = dictGetIterator(zs->dict);
3838 dictEntry *de;
3839
3840 if (rdbSaveLen(fp,dictSize(zs->dict)) == -1) return -1;
3841 while((de = dictNext(di)) != NULL) {
3842 robj *eleobj = dictGetEntryKey(de);
3843 double *score = dictGetEntryVal(de);
3844
3845 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
3846 if (rdbSaveDoubleValue(fp,*score) == -1) return -1;
3847 }
3848 dictReleaseIterator(di);
b1befe6a 3849 } else if (o->type == REDIS_HASH) {
3850 /* Save a hash value */
3851 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
3852 unsigned char *p = zipmapRewind(o->ptr);
3853 unsigned int count = zipmapLen(o->ptr);
3854 unsigned char *key, *val;
3855 unsigned int klen, vlen;
3856
3857 if (rdbSaveLen(fp,count) == -1) return -1;
3858 while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
3859 if (rdbSaveRawString(fp,key,klen) == -1) return -1;
3860 if (rdbSaveRawString(fp,val,vlen) == -1) return -1;
3861 }
3862 } else {
3863 dictIterator *di = dictGetIterator(o->ptr);
3864 dictEntry *de;
3865
3866 if (rdbSaveLen(fp,dictSize((dict*)o->ptr)) == -1) return -1;
3867 while((de = dictNext(di)) != NULL) {
3868 robj *key = dictGetEntryKey(de);
3869 robj *val = dictGetEntryVal(de);
3870
3871 if (rdbSaveStringObject(fp,key) == -1) return -1;
3872 if (rdbSaveStringObject(fp,val) == -1) return -1;
3873 }
3874 dictReleaseIterator(di);
3875 }
06233c45 3876 } else {
f83c6cb5 3877 redisPanic("Unknown object type");
06233c45 3878 }
3879 return 0;
3880}
3881
3882/* Return the length the object will have on disk if saved with
3883 * the rdbSaveObject() function. Currently we use a trick to get
3884 * this length with very little changes to the code. In the future
3885 * we could switch to a faster solution. */
b9bc0eef 3886static off_t rdbSavedObjectLen(robj *o, FILE *fp) {
3887 if (fp == NULL) fp = server.devnull;
06233c45 3888 rewind(fp);
3889 assert(rdbSaveObject(fp,o) != 1);
3890 return ftello(fp);
3891}
3892
06224fec 3893/* Return the number of pages required to save this object in the swap file */
b9bc0eef 3894static off_t rdbSavedObjectPages(robj *o, FILE *fp) {
3895 off_t bytes = rdbSavedObjectLen(o,fp);
e0a62c7f 3896
06224fec 3897 return (bytes+(server.vm_page_size-1))/server.vm_page_size;
3898}
3899
ed9b544e 3900/* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
f78fd11b 3901static int rdbSave(char *filename) {
ed9b544e 3902 dictIterator *di = NULL;
3903 dictEntry *de;
ed9b544e 3904 FILE *fp;
3905 char tmpfile[256];
3906 int j;
bb32ede5 3907 time_t now = time(NULL);
ed9b544e 3908
2316bb3b 3909 /* Wait for I/O therads to terminate, just in case this is a
3910 * foreground-saving, to avoid seeking the swap file descriptor at the
3911 * same time. */
3912 if (server.vm_enabled)
3913 waitEmptyIOJobsQueue();
3914
a3b21203 3915 snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
ed9b544e 3916 fp = fopen(tmpfile,"w");
3917 if (!fp) {
3918 redisLog(REDIS_WARNING, "Failed saving the DB: %s", strerror(errno));
3919 return REDIS_ERR;
3920 }
f78fd11b 3921 if (fwrite("REDIS0001",9,1,fp) == 0) goto werr;
ed9b544e 3922 for (j = 0; j < server.dbnum; j++) {
bb32ede5 3923 redisDb *db = server.db+j;
3924 dict *d = db->dict;
3305306f 3925 if (dictSize(d) == 0) continue;
ed9b544e 3926 di = dictGetIterator(d);
3927 if (!di) {
3928 fclose(fp);
3929 return REDIS_ERR;
3930 }
3931
3932 /* Write the SELECT DB opcode */
f78fd11b 3933 if (rdbSaveType(fp,REDIS_SELECTDB) == -1) goto werr;
3934 if (rdbSaveLen(fp,j) == -1) goto werr;
ed9b544e 3935
3936 /* Iterate this DB writing every entry */
3937 while((de = dictNext(di)) != NULL) {
09241813 3938 sds keystr = dictGetEntryKey(de);
3939 robj key, *o = dictGetEntryVal(de);
3940 time_t expiretime;
3941
3942 initStaticStringObject(key,keystr);
3943 expiretime = getExpire(db,&key);
bb32ede5 3944
3945 /* Save the expire time */
3946 if (expiretime != -1) {
3947 /* If this key is already expired skip it */
3948 if (expiretime < now) continue;
3949 if (rdbSaveType(fp,REDIS_EXPIRETIME) == -1) goto werr;
3950 if (rdbSaveTime(fp,expiretime) == -1) goto werr;
3951 }
7e69548d 3952 /* Save the key and associated value. This requires special
3953 * handling if the value is swapped out. */
560db612 3954 if (!server.vm_enabled || o->storage == REDIS_VM_MEMORY ||
3955 o->storage == REDIS_VM_SWAPPING) {
7e69548d 3956 /* Save type, key, value */
3957 if (rdbSaveType(fp,o->type) == -1) goto werr;
09241813 3958 if (rdbSaveStringObject(fp,&key) == -1) goto werr;
7e69548d 3959 if (rdbSaveObject(fp,o) == -1) goto werr;
3960 } else {
996cb5f7 3961 /* REDIS_VM_SWAPPED or REDIS_VM_LOADING */
b9bc0eef 3962 robj *po;
7e69548d 3963 /* Get a preview of the object in memory */
560db612 3964 po = vmPreviewObject(o);
7e69548d 3965 /* Save type, key, value */
560db612 3966 if (rdbSaveType(fp,po->type) == -1) goto werr;
09241813 3967 if (rdbSaveStringObject(fp,&key) == -1) goto werr;
7e69548d 3968 if (rdbSaveObject(fp,po) == -1) goto werr;
3969 /* Remove the loaded object from memory */
3970 decrRefCount(po);
7e69548d 3971 }
ed9b544e 3972 }
3973 dictReleaseIterator(di);
3974 }
3975 /* EOF opcode */
f78fd11b 3976 if (rdbSaveType(fp,REDIS_EOF) == -1) goto werr;
3977
3978 /* Make sure data will not remain on the OS's output buffers */
ed9b544e 3979 fflush(fp);
3980 fsync(fileno(fp));
3981 fclose(fp);
e0a62c7f 3982
ed9b544e 3983 /* Use RENAME to make sure the DB file is changed atomically only
3984 * if the generate DB file is ok. */
3985 if (rename(tmpfile,filename) == -1) {
325d1eb4 3986 redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
ed9b544e 3987 unlink(tmpfile);
3988 return REDIS_ERR;
3989 }
3990 redisLog(REDIS_NOTICE,"DB saved on disk");
3991 server.dirty = 0;
3992 server.lastsave = time(NULL);
3993 return REDIS_OK;
3994
3995werr:
3996 fclose(fp);
3997 unlink(tmpfile);
3998 redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
3999 if (di) dictReleaseIterator(di);
4000 return REDIS_ERR;
4001}
4002
f78fd11b 4003static int rdbSaveBackground(char *filename) {
ed9b544e 4004 pid_t childpid;
4005
9d65a1bb 4006 if (server.bgsavechildpid != -1) return REDIS_ERR;
054e426d 4007 if (server.vm_enabled) waitEmptyIOJobsQueue();
ed9b544e 4008 if ((childpid = fork()) == 0) {
4009 /* Child */
054e426d 4010 if (server.vm_enabled) vmReopenSwapFile();
ed9b544e 4011 close(server.fd);
f78fd11b 4012 if (rdbSave(filename) == REDIS_OK) {
478c2c6f 4013 _exit(0);
ed9b544e 4014 } else {
478c2c6f 4015 _exit(1);
ed9b544e 4016 }
4017 } else {
4018 /* Parent */
5a7c647e 4019 if (childpid == -1) {
4020 redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
4021 strerror(errno));
4022 return REDIS_ERR;
4023 }
ed9b544e 4024 redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
9f3c422c 4025 server.bgsavechildpid = childpid;
884d4b39 4026 updateDictResizePolicy();
ed9b544e 4027 return REDIS_OK;
4028 }
4029 return REDIS_OK; /* unreached */
4030}
4031
a3b21203 4032static void rdbRemoveTempFile(pid_t childpid) {
4033 char tmpfile[256];
4034
4035 snprintf(tmpfile,256,"temp-%d.rdb", (int) childpid);
4036 unlink(tmpfile);
4037}
4038
f78fd11b 4039static int rdbLoadType(FILE *fp) {
4040 unsigned char type;
7b45bfb2 4041 if (fread(&type,1,1,fp) == 0) return -1;
4042 return type;
4043}
4044
bb32ede5 4045static time_t rdbLoadTime(FILE *fp) {
4046 int32_t t32;
4047 if (fread(&t32,4,1,fp) == 0) return -1;
4048 return (time_t) t32;
4049}
4050
e3566d4b 4051/* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
4052 * of this file for a description of how this are stored on disk.
4053 *
4054 * isencoded is set to 1 if the readed length is not actually a length but
4055 * an "encoding type", check the above comments for more info */
c78a8ccc 4056static uint32_t rdbLoadLen(FILE *fp, int *isencoded) {
f78fd11b 4057 unsigned char buf[2];
4058 uint32_t len;
c78a8ccc 4059 int type;
f78fd11b 4060
e3566d4b 4061 if (isencoded) *isencoded = 0;
c78a8ccc 4062 if (fread(buf,1,1,fp) == 0) return REDIS_RDB_LENERR;
4063 type = (buf[0]&0xC0)>>6;
4064 if (type == REDIS_RDB_6BITLEN) {
4065 /* Read a 6 bit len */
4066 return buf[0]&0x3F;
4067 } else if (type == REDIS_RDB_ENCVAL) {
4068 /* Read a 6 bit len encoding type */
4069 if (isencoded) *isencoded = 1;
4070 return buf[0]&0x3F;
4071 } else if (type == REDIS_RDB_14BITLEN) {
4072 /* Read a 14 bit len */
4073 if (fread(buf+1,1,1,fp) == 0) return REDIS_RDB_LENERR;
4074 return ((buf[0]&0x3F)<<8)|buf[1];
4075 } else {
4076 /* Read a 32 bit len */
f78fd11b 4077 if (fread(&len,4,1,fp) == 0) return REDIS_RDB_LENERR;
4078 return ntohl(len);
f78fd11b 4079 }
f78fd11b 4080}
4081
ad30aa60 4082/* Load an integer-encoded object from file 'fp', with the specified
4083 * encoding type 'enctype'. If encode is true the function may return
4084 * an integer-encoded object as reply, otherwise the returned object
4085 * will always be encoded as a raw string. */
4086static robj *rdbLoadIntegerObject(FILE *fp, int enctype, int encode) {
e3566d4b 4087 unsigned char enc[4];
4088 long long val;
4089
4090 if (enctype == REDIS_RDB_ENC_INT8) {
4091 if (fread(enc,1,1,fp) == 0) return NULL;
4092 val = (signed char)enc[0];
4093 } else if (enctype == REDIS_RDB_ENC_INT16) {
4094 uint16_t v;
4095 if (fread(enc,2,1,fp) == 0) return NULL;
4096 v = enc[0]|(enc[1]<<8);
4097 val = (int16_t)v;
4098 } else if (enctype == REDIS_RDB_ENC_INT32) {
4099 uint32_t v;
4100 if (fread(enc,4,1,fp) == 0) return NULL;
4101 v = enc[0]|(enc[1]<<8)|(enc[2]<<16)|(enc[3]<<24);
4102 val = (int32_t)v;
4103 } else {
4104 val = 0; /* anti-warning */
f83c6cb5 4105 redisPanic("Unknown RDB integer encoding type");
e3566d4b 4106 }
ad30aa60 4107 if (encode)
4108 return createStringObjectFromLongLong(val);
4109 else
4110 return createObject(REDIS_STRING,sdsfromlonglong(val));
e3566d4b 4111}
4112
c78a8ccc 4113static robj *rdbLoadLzfStringObject(FILE*fp) {
88e85998 4114 unsigned int len, clen;
4115 unsigned char *c = NULL;
4116 sds val = NULL;
4117
c78a8ccc 4118 if ((clen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
4119 if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
88e85998 4120 if ((c = zmalloc(clen)) == NULL) goto err;
4121 if ((val = sdsnewlen(NULL,len)) == NULL) goto err;
4122 if (fread(c,clen,1,fp) == 0) goto err;
4123 if (lzf_decompress(c,clen,val,len) == 0) goto err;
5109cdff 4124 zfree(c);
88e85998 4125 return createObject(REDIS_STRING,val);
4126err:
4127 zfree(c);
4128 sdsfree(val);
4129 return NULL;
4130}
4131
ad30aa60 4132static robj *rdbGenericLoadStringObject(FILE*fp, int encode) {
e3566d4b 4133 int isencoded;
4134 uint32_t len;
f78fd11b 4135 sds val;
4136
c78a8ccc 4137 len = rdbLoadLen(fp,&isencoded);
e3566d4b 4138 if (isencoded) {
4139 switch(len) {
4140 case REDIS_RDB_ENC_INT8:
4141 case REDIS_RDB_ENC_INT16:
4142 case REDIS_RDB_ENC_INT32:
ad30aa60 4143 return rdbLoadIntegerObject(fp,len,encode);
88e85998 4144 case REDIS_RDB_ENC_LZF:
bdcb92f2 4145 return rdbLoadLzfStringObject(fp);
e3566d4b 4146 default:
f83c6cb5 4147 redisPanic("Unknown RDB encoding type");
e3566d4b 4148 }
4149 }
4150
f78fd11b 4151 if (len == REDIS_RDB_LENERR) return NULL;
4152 val = sdsnewlen(NULL,len);
4153 if (len && fread(val,len,1,fp) == 0) {
4154 sdsfree(val);
4155 return NULL;
4156 }
bdcb92f2 4157 return createObject(REDIS_STRING,val);
f78fd11b 4158}
4159
ad30aa60 4160static robj *rdbLoadStringObject(FILE *fp) {
4161 return rdbGenericLoadStringObject(fp,0);
4162}
4163
4164static robj *rdbLoadEncodedStringObject(FILE *fp) {
4165 return rdbGenericLoadStringObject(fp,1);
4166}
4167
a7866db6 4168/* For information about double serialization check rdbSaveDoubleValue() */
4169static int rdbLoadDoubleValue(FILE *fp, double *val) {
4170 char buf[128];
4171 unsigned char len;
4172
4173 if (fread(&len,1,1,fp) == 0) return -1;
4174 switch(len) {
4175 case 255: *val = R_NegInf; return 0;
4176 case 254: *val = R_PosInf; return 0;
4177 case 253: *val = R_Nan; return 0;
4178 default:
4179 if (fread(buf,len,1,fp) == 0) return -1;
231d758e 4180 buf[len] = '\0';
a7866db6 4181 sscanf(buf, "%lg", val);
4182 return 0;
4183 }
4184}
4185
c78a8ccc 4186/* Load a Redis object of the specified type from the specified file.
4187 * On success a newly allocated object is returned, otherwise NULL. */
4188static robj *rdbLoadObject(int type, FILE *fp) {
23f96494
PN
4189 robj *o, *ele, *dec;
4190 size_t len;
c78a8ccc 4191
bcd11906 4192 redisLog(REDIS_DEBUG,"LOADING OBJECT %d (at %d)\n",type,ftell(fp));
c78a8ccc 4193 if (type == REDIS_STRING) {
4194 /* Read string value */
ad30aa60 4195 if ((o = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
05df7621 4196 o = tryObjectEncoding(o);
23f96494
PN
4197 } else if (type == REDIS_LIST) {
4198 /* Read list value */
4199 if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
4200
d0686e07
PN
4201 /* Use a real list when there are too many entries */
4202 if (len > server.list_max_ziplist_entries) {
4203 o = createListObject();
4204 } else {
4205 o = createZiplistObject();
4206 }
c78a8ccc 4207
23f96494
PN
4208 /* Load every single element of the list */
4209 while(len--) {
4210 if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
4211
d0686e07
PN
4212 /* If we are using a ziplist and the value is too big, convert
4213 * the object to a real list. */
4214 if (o->encoding == REDIS_ENCODING_ZIPLIST &&
4215 ele->encoding == REDIS_ENCODING_RAW &&
4216 sdslen(ele->ptr) > server.list_max_ziplist_value)
003f0840 4217 listTypeConvert(o,REDIS_ENCODING_LIST);
d0686e07 4218
23f96494
PN
4219 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
4220 dec = getDecodedObject(ele);
4221 o->ptr = ziplistPush(o->ptr,dec->ptr,sdslen(dec->ptr),REDIS_TAIL);
4222 decrRefCount(dec);
4223 decrRefCount(ele);
4224 } else {
4225 ele = tryObjectEncoding(ele);
4226 listAddNodeTail(o->ptr,ele);
23f96494
PN
4227 }
4228 }
4229 } else if (type == REDIS_SET) {
4230 /* Read list/set value */
4231 if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
4232 o = createSetObject();
3c68de9b 4233 /* It's faster to expand the dict to the right size asap in order
4234 * to avoid rehashing */
23f96494
PN
4235 if (len > DICT_HT_INITIAL_SIZE)
4236 dictExpand(o->ptr,len);
c78a8ccc 4237 /* Load every single element of the list/set */
23f96494 4238 while(len--) {
ad30aa60 4239 if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
05df7621 4240 ele = tryObjectEncoding(ele);
23f96494 4241 dictAdd((dict*)o->ptr,ele,NULL);
c78a8ccc 4242 }
4243 } else if (type == REDIS_ZSET) {
4244 /* Read list/set value */
ada386b2 4245 size_t zsetlen;
c78a8ccc 4246 zset *zs;
4247
4248 if ((zsetlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
4249 o = createZsetObject();
4250 zs = o->ptr;
4251 /* Load every single element of the list/set */
4252 while(zsetlen--) {
4253 robj *ele;
4254 double *score = zmalloc(sizeof(double));
4255
ad30aa60 4256 if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
05df7621 4257 ele = tryObjectEncoding(ele);
c78a8ccc 4258 if (rdbLoadDoubleValue(fp,score) == -1) return NULL;
4259 dictAdd(zs->dict,ele,score);
4260 zslInsert(zs->zsl,*score,ele);
4261 incrRefCount(ele); /* added to skiplist */
4262 }
ada386b2 4263 } else if (type == REDIS_HASH) {
4264 size_t hashlen;
4265
4266 if ((hashlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
4267 o = createHashObject();
4268 /* Too many entries? Use an hash table. */
4269 if (hashlen > server.hash_max_zipmap_entries)
4270 convertToRealHash(o);
4271 /* Load every key/value, then set it into the zipmap or hash
4272 * table, as needed. */
4273 while(hashlen--) {
4274 robj *key, *val;
4275
b785b2bf 4276 if ((key = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
4277 if ((val = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
ada386b2 4278 /* If we are using a zipmap and there are too big values
4279 * the object is converted to real hash table encoding. */
4280 if (o->encoding != REDIS_ENCODING_HT &&
4281 (sdslen(key->ptr) > server.hash_max_zipmap_value ||
4282 sdslen(val->ptr) > server.hash_max_zipmap_value))
4283 {
4284 convertToRealHash(o);
4285 }
4286
4287 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
4288 unsigned char *zm = o->ptr;
4289
4290 zm = zipmapSet(zm,key->ptr,sdslen(key->ptr),
4291 val->ptr,sdslen(val->ptr),NULL);
4292 o->ptr = zm;
4293 decrRefCount(key);
4294 decrRefCount(val);
4295 } else {
05df7621 4296 key = tryObjectEncoding(key);
4297 val = tryObjectEncoding(val);
ada386b2 4298 dictAdd((dict*)o->ptr,key,val);
ada386b2 4299 }
4300 }
c78a8ccc 4301 } else {
f83c6cb5 4302 redisPanic("Unknown object type");
c78a8ccc 4303 }
4304 return o;
4305}
4306
f78fd11b 4307static int rdbLoad(char *filename) {
ed9b544e 4308 FILE *fp;
f78fd11b 4309 uint32_t dbid;
bb32ede5 4310 int type, retval, rdbver;
585af7e2 4311 int swap_all_values = 0;
bb32ede5 4312 redisDb *db = server.db+0;
f78fd11b 4313 char buf[1024];
242a64f3 4314 time_t expiretime, now = time(NULL);
bb32ede5 4315
ed9b544e 4316 fp = fopen(filename,"r");
4317 if (!fp) return REDIS_ERR;
4318 if (fread(buf,9,1,fp) == 0) goto eoferr;
f78fd11b 4319 buf[9] = '\0';
4320 if (memcmp(buf,"REDIS",5) != 0) {
ed9b544e 4321 fclose(fp);
4322 redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
4323 return REDIS_ERR;
4324 }
f78fd11b 4325 rdbver = atoi(buf+5);
c78a8ccc 4326 if (rdbver != 1) {
f78fd11b 4327 fclose(fp);
4328 redisLog(REDIS_WARNING,"Can't handle RDB format version %d",rdbver);
4329 return REDIS_ERR;
4330 }
ed9b544e 4331 while(1) {
585af7e2 4332 robj *key, *val;
7e02fe32 4333 int force_swapout;
ed9b544e 4334
585af7e2 4335 expiretime = -1;
ed9b544e 4336 /* Read type. */
f78fd11b 4337 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
bb32ede5 4338 if (type == REDIS_EXPIRETIME) {
4339 if ((expiretime = rdbLoadTime(fp)) == -1) goto eoferr;
4340 /* We read the time so we need to read the object type again */
4341 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
4342 }
ed9b544e 4343 if (type == REDIS_EOF) break;
4344 /* Handle SELECT DB opcode as a special case */
4345 if (type == REDIS_SELECTDB) {
c78a8ccc 4346 if ((dbid = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR)
e3566d4b 4347 goto eoferr;
ed9b544e 4348 if (dbid >= (unsigned)server.dbnum) {
f78fd11b 4349 redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum);
ed9b544e 4350 exit(1);
4351 }
bb32ede5 4352 db = server.db+dbid;
ed9b544e 4353 continue;
4354 }
4355 /* Read key */
585af7e2 4356 if ((key = rdbLoadStringObject(fp)) == NULL) goto eoferr;
c78a8ccc 4357 /* Read value */
585af7e2 4358 if ((val = rdbLoadObject(type,fp)) == NULL) goto eoferr;
89e689c5 4359 /* Check if the key already expired */
4360 if (expiretime != -1 && expiretime < now) {
4361 decrRefCount(key);
4362 decrRefCount(val);
4363 continue;
4364 }
ed9b544e 4365 /* Add the new object in the hash table */
09241813 4366 retval = dbAdd(db,key,val);
4367 if (retval == REDIS_ERR) {
585af7e2 4368 redisLog(REDIS_WARNING,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", key->ptr);
ed9b544e 4369 exit(1);
4370 }
bb32ede5 4371 /* Set the expire time if needed */
89e689c5 4372 if (expiretime != -1) setExpire(db,key,expiretime);
242a64f3 4373
b492cf00 4374 /* Handle swapping while loading big datasets when VM is on */
242a64f3 4375
4376 /* If we detecter we are hopeless about fitting something in memory
4377 * we just swap every new key on disk. Directly...
4378 * Note that's important to check for this condition before resorting
4379 * to random sampling, otherwise we may try to swap already
4380 * swapped keys. */
585af7e2 4381 if (swap_all_values) {
09241813 4382 dictEntry *de = dictFind(db->dict,key->ptr);
242a64f3 4383
4384 /* de may be NULL since the key already expired */
4385 if (de) {
560db612 4386 vmpointer *vp;
585af7e2 4387 val = dictGetEntryVal(de);
242a64f3 4388
560db612 4389 if (val->refcount == 1 &&
4390 (vp = vmSwapObjectBlocking(val)) != NULL)
4391 dictGetEntryVal(de) = vp;
242a64f3 4392 }
09241813 4393 decrRefCount(key);
242a64f3 4394 continue;
4395 }
09241813 4396 decrRefCount(key);
242a64f3 4397
a89b7013 4398 /* Flush data on disk once 32 MB of additional RAM are used... */
7e02fe32 4399 force_swapout = 0;
4400 if ((zmalloc_used_memory() - server.vm_max_memory) > 1024*1024*32)
4401 force_swapout = 1;
242a64f3 4402
4403 /* If we have still some hope of having some value fitting memory
4404 * then we try random sampling. */
7e02fe32 4405 if (!swap_all_values && server.vm_enabled && force_swapout) {
b492cf00 4406 while (zmalloc_used_memory() > server.vm_max_memory) {
a69a0c9c 4407 if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
b492cf00 4408 }
242a64f3 4409 if (zmalloc_used_memory() > server.vm_max_memory)
585af7e2 4410 swap_all_values = 1; /* We are already using too much mem */
b492cf00 4411 }
ed9b544e 4412 }
4413 fclose(fp);
4414 return REDIS_OK;
4415
4416eoferr: /* unexpected end of file is handled here with a fatal exit */
f80dff62 4417 redisLog(REDIS_WARNING,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
ed9b544e 4418 exit(1);
4419 return REDIS_ERR; /* Just to avoid warning */
4420}
4421
b58ba105 4422/*================================== Shutdown =============================== */
fab43727 4423static int prepareForShutdown() {
b58ba105
AM
4424 redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
4425 /* Kill the saving child if there is a background saving in progress.
4426 We want to avoid race conditions, for instance our saving child may
4427 overwrite the synchronous saving did by SHUTDOWN. */
4428 if (server.bgsavechildpid != -1) {
4429 redisLog(REDIS_WARNING,"There is a live saving child. Killing it!");
4430 kill(server.bgsavechildpid,SIGKILL);
4431 rdbRemoveTempFile(server.bgsavechildpid);
4432 }
4433 if (server.appendonly) {
4434 /* Append only file: fsync() the AOF and exit */
b0bd87f6 4435 aof_fsync(server.appendfd);
b58ba105 4436 if (server.vm_enabled) unlink(server.vm_swap_file);
b58ba105
AM
4437 } else {
4438 /* Snapshotting. Perform a SYNC SAVE and exit */
4439 if (rdbSave(server.dbfilename) == REDIS_OK) {
4440 if (server.daemonize)
4441 unlink(server.pidfile);
4442 redisLog(REDIS_WARNING,"%zu bytes used at exit",zmalloc_used_memory());
b58ba105
AM
4443 } else {
4444 /* Ooops.. error saving! The best we can do is to continue
4445 * operating. Note that if there was a background saving process,
4446 * in the next cron() Redis will be notified that the background
4447 * saving aborted, handling special stuff like slaves pending for
4448 * synchronization... */
4449 redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
fab43727 4450 return REDIS_ERR;
b58ba105
AM
4451 }
4452 }
8513a757 4453 redisLog(REDIS_WARNING,"Server exit now, bye bye...");
fab43727 4454 return REDIS_OK;
b58ba105
AM
4455}
4456
ed9b544e 4457/*================================== Commands =============================== */
4458
abcb223e 4459static void authCommand(redisClient *c) {
2e77c2ee 4460 if (!server.requirepass || !strcmp(c->argv[1]->ptr, server.requirepass)) {
abcb223e
BH
4461 c->authenticated = 1;
4462 addReply(c,shared.ok);
4463 } else {
4464 c->authenticated = 0;
fa4c0aba 4465 addReplySds(c,sdscatprintf(sdsempty(),"-ERR invalid password\r\n"));
abcb223e
BH
4466 }
4467}
4468
ed9b544e 4469static void pingCommand(redisClient *c) {
4470 addReply(c,shared.pong);
4471}
4472
4473static void echoCommand(redisClient *c) {
dd88747b 4474 addReplyBulk(c,c->argv[1]);
ed9b544e 4475}
4476
4477/*=================================== Strings =============================== */
4478
526d00a5 4479static void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire) {
ed9b544e 4480 int retval;
10ce1276 4481 long seconds = 0; /* initialized to avoid an harmness warning */
ed9b544e 4482
526d00a5 4483 if (expire) {
4484 if (getLongFromObjectOrReply(c, expire, &seconds, NULL) != REDIS_OK)
4485 return;
4486 if (seconds <= 0) {
4487 addReplySds(c,sdsnew("-ERR invalid expire time in SETEX\r\n"));
4488 return;
4489 }
4490 }
4491
37ab76c9 4492 touchWatchedKey(c->db,key);
526d00a5 4493 if (nx) deleteIfVolatile(c->db,key);
09241813 4494 retval = dbAdd(c->db,key,val);
4495 if (retval == REDIS_ERR) {
ed9b544e 4496 if (!nx) {
09241813 4497 dbReplace(c->db,key,val);
526d00a5 4498 incrRefCount(val);
ed9b544e 4499 } else {
c937aa89 4500 addReply(c,shared.czero);
ed9b544e 4501 return;
4502 }
4503 } else {
526d00a5 4504 incrRefCount(val);
ed9b544e 4505 }
4506 server.dirty++;
526d00a5 4507 removeExpire(c->db,key);
4508 if (expire) setExpire(c->db,key,time(NULL)+seconds);
c937aa89 4509 addReply(c, nx ? shared.cone : shared.ok);
ed9b544e 4510}
4511
4512static void setCommand(redisClient *c) {
526d00a5 4513 setGenericCommand(c,0,c->argv[1],c->argv[2],NULL);
ed9b544e 4514}
4515
4516static void setnxCommand(redisClient *c) {
526d00a5 4517 setGenericCommand(c,1,c->argv[1],c->argv[2],NULL);
4518}
4519
4520static void setexCommand(redisClient *c) {
4521 setGenericCommand(c,0,c->argv[1],c->argv[3],c->argv[2]);
ed9b544e 4522}
4523
322fc7d8 4524static int getGenericCommand(redisClient *c) {
dd88747b 4525 robj *o;
e0a62c7f 4526
dd88747b 4527 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)
322fc7d8 4528 return REDIS_OK;
dd88747b 4529
4530 if (o->type != REDIS_STRING) {
4531 addReply(c,shared.wrongtypeerr);
4532 return REDIS_ERR;
ed9b544e 4533 } else {
dd88747b 4534 addReplyBulk(c,o);
4535 return REDIS_OK;
ed9b544e 4536 }
4537}
4538
322fc7d8 4539static void getCommand(redisClient *c) {
4540 getGenericCommand(c);
4541}
4542
f6b141c5 4543static void getsetCommand(redisClient *c) {
322fc7d8 4544 if (getGenericCommand(c) == REDIS_ERR) return;
09241813 4545 dbReplace(c->db,c->argv[1],c->argv[2]);
a431eb74 4546 incrRefCount(c->argv[2]);
4547 server.dirty++;
4548 removeExpire(c->db,c->argv[1]);
4549}
4550
70003d28 4551static void mgetCommand(redisClient *c) {
70003d28 4552 int j;
e0a62c7f 4553
c937aa89 4554 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-1));
70003d28 4555 for (j = 1; j < c->argc; j++) {
3305306f 4556 robj *o = lookupKeyRead(c->db,c->argv[j]);
4557 if (o == NULL) {
c937aa89 4558 addReply(c,shared.nullbulk);
70003d28 4559 } else {
70003d28 4560 if (o->type != REDIS_STRING) {
c937aa89 4561 addReply(c,shared.nullbulk);
70003d28 4562 } else {
dd88747b 4563 addReplyBulk(c,o);
70003d28 4564 }
4565 }
4566 }
4567}
4568
6c446631 4569static void msetGenericCommand(redisClient *c, int nx) {
906573e7 4570 int j, busykeys = 0;
6c446631 4571
4572 if ((c->argc % 2) == 0) {
454d4e43 4573 addReplySds(c,sdsnew("-ERR wrong number of arguments for MSET\r\n"));
6c446631 4574 return;
4575 }
4576 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
4577 * set nothing at all if at least one already key exists. */
4578 if (nx) {
4579 for (j = 1; j < c->argc; j += 2) {
906573e7 4580 if (lookupKeyWrite(c->db,c->argv[j]) != NULL) {
4581 busykeys++;
6c446631 4582 }
4583 }
4584 }
906573e7 4585 if (busykeys) {
4586 addReply(c, shared.czero);
4587 return;
4588 }
6c446631 4589
4590 for (j = 1; j < c->argc; j += 2) {
05df7621 4591 c->argv[j+1] = tryObjectEncoding(c->argv[j+1]);
09241813 4592 dbReplace(c->db,c->argv[j],c->argv[j+1]);
4593 incrRefCount(c->argv[j+1]);
6c446631 4594 removeExpire(c->db,c->argv[j]);
4595 }
4596 server.dirty += (c->argc-1)/2;
4597 addReply(c, nx ? shared.cone : shared.ok);
4598}
4599
4600static void msetCommand(redisClient *c) {
4601 msetGenericCommand(c,0);
4602}
4603
4604static void msetnxCommand(redisClient *c) {
4605 msetGenericCommand(c,1);
4606}
4607
d68ed120 4608static void incrDecrCommand(redisClient *c, long long incr) {
ed9b544e 4609 long long value;
ed9b544e 4610 robj *o;
e0a62c7f 4611
3305306f 4612 o = lookupKeyWrite(c->db,c->argv[1]);
6485f293
PN
4613 if (o != NULL && checkType(c,o,REDIS_STRING)) return;
4614 if (getLongLongFromObjectOrReply(c,o,&value,NULL) != REDIS_OK) return;
ed9b544e 4615
4616 value += incr;
d6f4c262 4617 o = createStringObjectFromLongLong(value);
09241813 4618 dbReplace(c->db,c->argv[1],o);
ed9b544e 4619 server.dirty++;
c937aa89 4620 addReply(c,shared.colon);
ed9b544e 4621 addReply(c,o);
4622 addReply(c,shared.crlf);
4623}
4624
4625static void incrCommand(redisClient *c) {
a4d1ba9a 4626 incrDecrCommand(c,1);
ed9b544e 4627}
4628
4629static void decrCommand(redisClient *c) {
a4d1ba9a 4630 incrDecrCommand(c,-1);
ed9b544e 4631}
4632
4633static void incrbyCommand(redisClient *c) {
bbe025e0
AM
4634 long long incr;
4635
bd79a6bd 4636 if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != REDIS_OK) return;
a4d1ba9a 4637 incrDecrCommand(c,incr);
ed9b544e 4638}
4639
4640static void decrbyCommand(redisClient *c) {
bbe025e0
AM
4641 long long incr;
4642
bd79a6bd 4643 if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != REDIS_OK) return;
a4d1ba9a 4644 incrDecrCommand(c,-incr);
ed9b544e 4645}
4646
4b00bebd 4647static void appendCommand(redisClient *c) {
4648 int retval;
4649 size_t totlen;
4650 robj *o;
4651
4652 o = lookupKeyWrite(c->db,c->argv[1]);
4653 if (o == NULL) {
4654 /* Create the key */
09241813 4655 retval = dbAdd(c->db,c->argv[1],c->argv[2]);
4b00bebd 4656 incrRefCount(c->argv[2]);
4657 totlen = stringObjectLen(c->argv[2]);
4658 } else {
4b00bebd 4659 if (o->type != REDIS_STRING) {
4660 addReply(c,shared.wrongtypeerr);
4661 return;
4662 }
4663 /* If the object is specially encoded or shared we have to make
4664 * a copy */
4665 if (o->refcount != 1 || o->encoding != REDIS_ENCODING_RAW) {
4666 robj *decoded = getDecodedObject(o);
4667
4668 o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
4669 decrRefCount(decoded);
09241813 4670 dbReplace(c->db,c->argv[1],o);
4b00bebd 4671 }
4672 /* APPEND! */
4673 if (c->argv[2]->encoding == REDIS_ENCODING_RAW) {
4674 o->ptr = sdscatlen(o->ptr,
4675 c->argv[2]->ptr, sdslen(c->argv[2]->ptr));
4676 } else {
4677 o->ptr = sdscatprintf(o->ptr, "%ld",
4678 (unsigned long) c->argv[2]->ptr);
4679 }
4680 totlen = sdslen(o->ptr);
4681 }
4682 server.dirty++;
4683 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",(unsigned long)totlen));
4684}
4685
39191553 4686static void substrCommand(redisClient *c) {
4687 robj *o;
4688 long start = atoi(c->argv[2]->ptr);
4689 long end = atoi(c->argv[3]->ptr);
dd88747b 4690 size_t rangelen, strlen;
4691 sds range;
39191553 4692
dd88747b 4693 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
4694 checkType(c,o,REDIS_STRING)) return;
39191553 4695
dd88747b 4696 o = getDecodedObject(o);
4697 strlen = sdslen(o->ptr);
8fe7fad7 4698
dd88747b 4699 /* convert negative indexes */
4700 if (start < 0) start = strlen+start;
4701 if (end < 0) end = strlen+end;
4702 if (start < 0) start = 0;
4703 if (end < 0) end = 0;
39191553 4704
dd88747b 4705 /* indexes sanity checks */
4706 if (start > end || (size_t)start >= strlen) {
4707 /* Out of range start or start > end result in null reply */
4708 addReply(c,shared.nullbulk);
4709 decrRefCount(o);
4710 return;
39191553 4711 }
dd88747b 4712 if ((size_t)end >= strlen) end = strlen-1;
4713 rangelen = (end-start)+1;
4714
4715 /* Return the result */
4716 addReplySds(c,sdscatprintf(sdsempty(),"$%zu\r\n",rangelen));
4717 range = sdsnewlen((char*)o->ptr+start,rangelen);
4718 addReplySds(c,range);
4719 addReply(c,shared.crlf);
4720 decrRefCount(o);
39191553 4721}
4722
ed9b544e 4723/* ========================= Type agnostic commands ========================= */
4724
4725static void delCommand(redisClient *c) {
5109cdff 4726 int deleted = 0, j;
4727
4728 for (j = 1; j < c->argc; j++) {
09241813 4729 if (dbDelete(c->db,c->argv[j])) {
37ab76c9 4730 touchWatchedKey(c->db,c->argv[j]);
5109cdff 4731 server.dirty++;
4732 deleted++;
4733 }
4734 }
482b672d 4735 addReplyLongLong(c,deleted);
ed9b544e 4736}
4737
4738static void existsCommand(redisClient *c) {
f4f06efc 4739 expireIfNeeded(c->db,c->argv[1]);
09241813 4740 if (dbExists(c->db,c->argv[1])) {
f4f06efc
PN
4741 addReply(c, shared.cone);
4742 } else {
4743 addReply(c, shared.czero);
4744 }
ed9b544e 4745}
4746
4747static void selectCommand(redisClient *c) {
4748 int id = atoi(c->argv[1]->ptr);
e0a62c7f 4749
ed9b544e 4750 if (selectDb(c,id) == REDIS_ERR) {
774e3047 4751 addReplySds(c,sdsnew("-ERR invalid DB index\r\n"));
ed9b544e 4752 } else {
4753 addReply(c,shared.ok);
4754 }
4755}
4756
4757static void randomkeyCommand(redisClient *c) {
dc4be23e 4758 robj *key;
e0a62c7f 4759
09241813 4760 if ((key = dbRandomKey(c->db)) == NULL) {
dc4be23e 4761 addReply(c,shared.nullbulk);
4762 return;
4763 }
4764
09241813 4765 addReplyBulk(c,key);
4766 decrRefCount(key);
ed9b544e 4767}
4768
4769static void keysCommand(redisClient *c) {
4770 dictIterator *di;
4771 dictEntry *de;
4772 sds pattern = c->argv[1]->ptr;
4773 int plen = sdslen(pattern);
a3f9eec2 4774 unsigned long numkeys = 0;
ed9b544e 4775 robj *lenobj = createObject(REDIS_STRING,NULL);
4776
3305306f 4777 di = dictGetIterator(c->db->dict);
ed9b544e 4778 addReply(c,lenobj);
4779 decrRefCount(lenobj);
4780 while((de = dictNext(di)) != NULL) {
09241813 4781 sds key = dictGetEntryKey(de);
4782 robj *keyobj;
3305306f 4783
ed9b544e 4784 if ((pattern[0] == '*' && pattern[1] == '\0') ||
4785 stringmatchlen(pattern,plen,key,sdslen(key),0)) {
09241813 4786 keyobj = createStringObject(key,sdslen(key));
3305306f 4787 if (expireIfNeeded(c->db,keyobj) == 0) {
dd88747b 4788 addReplyBulk(c,keyobj);
3305306f 4789 numkeys++;
3305306f 4790 }
09241813 4791 decrRefCount(keyobj);
ed9b544e 4792 }
4793 }
4794 dictReleaseIterator(di);
a3f9eec2 4795 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",numkeys);
ed9b544e 4796}
4797
4798static void dbsizeCommand(redisClient *c) {
4799 addReplySds(c,
3305306f 4800 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c->db->dict)));
ed9b544e 4801}
4802
4803static void lastsaveCommand(redisClient *c) {
4804 addReplySds(c,
c937aa89 4805 sdscatprintf(sdsempty(),":%lu\r\n",server.lastsave));
ed9b544e 4806}
4807
4808static void typeCommand(redisClient *c) {
3305306f 4809 robj *o;
ed9b544e 4810 char *type;
3305306f 4811
4812 o = lookupKeyRead(c->db,c->argv[1]);
4813 if (o == NULL) {
c937aa89 4814 type = "+none";
ed9b544e 4815 } else {
ed9b544e 4816 switch(o->type) {
c937aa89 4817 case REDIS_STRING: type = "+string"; break;
4818 case REDIS_LIST: type = "+list"; break;
4819 case REDIS_SET: type = "+set"; break;
412a8bce 4820 case REDIS_ZSET: type = "+zset"; break;
ada386b2 4821 case REDIS_HASH: type = "+hash"; break;
4822 default: type = "+unknown"; break;
ed9b544e 4823 }
4824 }
4825 addReplySds(c,sdsnew(type));
4826 addReply(c,shared.crlf);
4827}
4828
4829static void saveCommand(redisClient *c) {
9d65a1bb 4830 if (server.bgsavechildpid != -1) {
05557f6d 4831 addReplySds(c,sdsnew("-ERR background save in progress\r\n"));
4832 return;
4833 }
f78fd11b 4834 if (rdbSave(server.dbfilename) == REDIS_OK) {
ed9b544e 4835 addReply(c,shared.ok);
4836 } else {
4837 addReply(c,shared.err);
4838 }
4839}
4840
4841static void bgsaveCommand(redisClient *c) {
9d65a1bb 4842 if (server.bgsavechildpid != -1) {
ed9b544e 4843 addReplySds(c,sdsnew("-ERR background save already in progress\r\n"));
4844 return;
4845 }
f78fd11b 4846 if (rdbSaveBackground(server.dbfilename) == REDIS_OK) {
49b99ab4 4847 char *status = "+Background saving started\r\n";
4848 addReplySds(c,sdsnew(status));
ed9b544e 4849 } else {
4850 addReply(c,shared.err);
4851 }
4852}
4853
4854static void shutdownCommand(redisClient *c) {
fab43727 4855 if (prepareForShutdown() == REDIS_OK)
4856 exit(0);
4857 addReplySds(c, sdsnew("-ERR Errors trying to SHUTDOWN. Check logs.\r\n"));
ed9b544e 4858}
4859
4860static void renameGenericCommand(redisClient *c, int nx) {
ed9b544e 4861 robj *o;
4862
4863 /* To use the same key as src and dst is probably an error */
4864 if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) {
c937aa89 4865 addReply(c,shared.sameobjecterr);
ed9b544e 4866 return;
4867 }
4868
dd88747b 4869 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr)) == NULL)
ed9b544e 4870 return;
dd88747b 4871
ed9b544e 4872 incrRefCount(o);
3305306f 4873 deleteIfVolatile(c->db,c->argv[2]);
09241813 4874 if (dbAdd(c->db,c->argv[2],o) == REDIS_ERR) {
ed9b544e 4875 if (nx) {
4876 decrRefCount(o);
c937aa89 4877 addReply(c,shared.czero);
ed9b544e 4878 return;
4879 }
09241813 4880 dbReplace(c->db,c->argv[2],o);
ed9b544e 4881 }
09241813 4882 dbDelete(c->db,c->argv[1]);
b167f877 4883 touchWatchedKey(c->db,c->argv[2]);
ed9b544e 4884 server.dirty++;
c937aa89 4885 addReply(c,nx ? shared.cone : shared.ok);
ed9b544e 4886}
4887
4888static void renameCommand(redisClient *c) {
4889 renameGenericCommand(c,0);
4890}
4891
4892static void renamenxCommand(redisClient *c) {
4893 renameGenericCommand(c,1);
4894}
4895
4896static void moveCommand(redisClient *c) {
3305306f 4897 robj *o;
4898 redisDb *src, *dst;
ed9b544e 4899 int srcid;
4900
4901 /* Obtain source and target DB pointers */
3305306f 4902 src = c->db;
4903 srcid = c->db->id;
ed9b544e 4904 if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) {
c937aa89 4905 addReply(c,shared.outofrangeerr);
ed9b544e 4906 return;
4907 }
3305306f 4908 dst = c->db;
4909 selectDb(c,srcid); /* Back to the source DB */
ed9b544e 4910
4911 /* If the user is moving using as target the same
4912 * DB as the source DB it is probably an error. */
4913 if (src == dst) {
c937aa89 4914 addReply(c,shared.sameobjecterr);
ed9b544e 4915 return;
4916 }
4917
4918 /* Check if the element exists and get a reference */
3305306f 4919 o = lookupKeyWrite(c->db,c->argv[1]);
4920 if (!o) {
c937aa89 4921 addReply(c,shared.czero);
ed9b544e 4922 return;
4923 }
4924
4925 /* Try to add the element to the target DB */
3305306f 4926 deleteIfVolatile(dst,c->argv[1]);
09241813 4927 if (dbAdd(dst,c->argv[1],o) == REDIS_ERR) {
c937aa89 4928 addReply(c,shared.czero);
ed9b544e 4929 return;
4930 }
ed9b544e 4931 incrRefCount(o);
4932
4933 /* OK! key moved, free the entry in the source DB */
09241813 4934 dbDelete(src,c->argv[1]);
ed9b544e 4935 server.dirty++;
c937aa89 4936 addReply(c,shared.cone);
ed9b544e 4937}
4938
4939/* =================================== Lists ================================ */
d0686e07
PN
4940
4941
4942/* Check the argument length to see if it requires us to convert the ziplist
4943 * to a real list. Only check raw-encoded objects because integer encoded
4944 * objects are never too long. */
003f0840 4945static void listTypeTryConversion(robj *subject, robj *value) {
d0686e07
PN
4946 if (subject->encoding != REDIS_ENCODING_ZIPLIST) return;
4947 if (value->encoding == REDIS_ENCODING_RAW &&
4948 sdslen(value->ptr) > server.list_max_ziplist_value)
003f0840 4949 listTypeConvert(subject,REDIS_ENCODING_LIST);
d0686e07
PN
4950}
4951
003f0840 4952static void listTypePush(robj *subject, robj *value, int where) {
d0686e07 4953 /* Check if we need to convert the ziplist */
003f0840 4954 listTypeTryConversion(subject,value);
d0686e07
PN
4955 if (subject->encoding == REDIS_ENCODING_ZIPLIST &&
4956 ziplistLen(subject->ptr) > server.list_max_ziplist_entries)
003f0840 4957 listTypeConvert(subject,REDIS_ENCODING_LIST);
d0686e07 4958
c7d9d662
PN
4959 if (subject->encoding == REDIS_ENCODING_ZIPLIST) {
4960 int pos = (where == REDIS_HEAD) ? ZIPLIST_HEAD : ZIPLIST_TAIL;
4961 value = getDecodedObject(value);
4962 subject->ptr = ziplistPush(subject->ptr,value->ptr,sdslen(value->ptr),pos);
4963 decrRefCount(value);
4964 } else if (subject->encoding == REDIS_ENCODING_LIST) {
4965 if (where == REDIS_HEAD) {
4966 listAddNodeHead(subject->ptr,value);
4967 } else {
4968 listAddNodeTail(subject->ptr,value);
4969 }
4970 incrRefCount(value);
4971 } else {
4972 redisPanic("Unknown list encoding");
4973 }
4974}
4975
003f0840 4976static robj *listTypePop(robj *subject, int where) {
d72562f7
PN
4977 robj *value = NULL;
4978 if (subject->encoding == REDIS_ENCODING_ZIPLIST) {
4979 unsigned char *p;
b6eb9703 4980 unsigned char *vstr;
d72562f7 4981 unsigned int vlen;
b6eb9703 4982 long long vlong;
d72562f7
PN
4983 int pos = (where == REDIS_HEAD) ? 0 : -1;
4984 p = ziplistIndex(subject->ptr,pos);
b6eb9703
PN
4985 if (ziplistGet(p,&vstr,&vlen,&vlong)) {
4986 if (vstr) {
4987 value = createStringObject((char*)vstr,vlen);
d72562f7 4988 } else {
b6eb9703 4989 value = createStringObjectFromLongLong(vlong);
d72562f7 4990 }
0f62e177
PN
4991 /* We only need to delete an element when it exists */
4992 subject->ptr = ziplistDelete(subject->ptr,&p);
d72562f7 4993 }
d72562f7
PN
4994 } else if (subject->encoding == REDIS_ENCODING_LIST) {
4995 list *list = subject->ptr;
4996 listNode *ln;
4997 if (where == REDIS_HEAD) {
4998 ln = listFirst(list);
4999 } else {
5000 ln = listLast(list);
5001 }
5002 if (ln != NULL) {
5003 value = listNodeValue(ln);
5004 incrRefCount(value);
5005 listDelNode(list,ln);
5006 }
5007 } else {
5008 redisPanic("Unknown list encoding");
5009 }
5010 return value;
5011}
5012
003f0840 5013static unsigned long listTypeLength(robj *subject) {
d72562f7
PN
5014 if (subject->encoding == REDIS_ENCODING_ZIPLIST) {
5015 return ziplistLen(subject->ptr);
5016 } else if (subject->encoding == REDIS_ENCODING_LIST) {
5017 return listLength((list*)subject->ptr);
5018 } else {
5019 redisPanic("Unknown list encoding");
5020 }
5021}
5022
a6dd455b
PN
5023/* Structure to hold set iteration abstraction. */
5024typedef struct {
5025 robj *subject;
5026 unsigned char encoding;
be02a7c0 5027 unsigned char direction; /* Iteration direction */
a6dd455b
PN
5028 unsigned char *zi;
5029 listNode *ln;
003f0840 5030} listTypeIterator;
a6dd455b 5031
be02a7c0
PN
5032/* Structure for an entry while iterating over a list. */
5033typedef struct {
003f0840 5034 listTypeIterator *li;
be02a7c0
PN
5035 unsigned char *zi; /* Entry in ziplist */
5036 listNode *ln; /* Entry in linked list */
003f0840 5037} listTypeEntry;
be02a7c0 5038
a6dd455b 5039/* Initialize an iterator at the specified index. */
003f0840
PN
5040static listTypeIterator *listTypeInitIterator(robj *subject, int index, unsigned char direction) {
5041 listTypeIterator *li = zmalloc(sizeof(listTypeIterator));
a6dd455b
PN
5042 li->subject = subject;
5043 li->encoding = subject->encoding;
be02a7c0 5044 li->direction = direction;
a6dd455b
PN
5045 if (li->encoding == REDIS_ENCODING_ZIPLIST) {
5046 li->zi = ziplistIndex(subject->ptr,index);
5047 } else if (li->encoding == REDIS_ENCODING_LIST) {
5048 li->ln = listIndex(subject->ptr,index);
5049 } else {
5050 redisPanic("Unknown list encoding");
5051 }
5052 return li;
5053}
5054
5055/* Clean up the iterator. */
003f0840 5056static void listTypeReleaseIterator(listTypeIterator *li) {
a6dd455b
PN
5057 zfree(li);
5058}
5059
be02a7c0
PN
5060/* Stores pointer to current the entry in the provided entry structure
5061 * and advances the position of the iterator. Returns 1 when the current
5062 * entry is in fact an entry, 0 otherwise. */
003f0840 5063static int listTypeNext(listTypeIterator *li, listTypeEntry *entry) {
dda20542
PN
5064 /* Protect from converting when iterating */
5065 redisAssert(li->subject->encoding == li->encoding);
5066
be02a7c0 5067 entry->li = li;
d2ee16ab 5068 if (li->encoding == REDIS_ENCODING_ZIPLIST) {
be02a7c0
PN
5069 entry->zi = li->zi;
5070 if (entry->zi != NULL) {
5071 if (li->direction == REDIS_TAIL)
5072 li->zi = ziplistNext(li->subject->ptr,li->zi);
5073 else
5074 li->zi = ziplistPrev(li->subject->ptr,li->zi);
5075 return 1;
5076 }
d2ee16ab 5077 } else if (li->encoding == REDIS_ENCODING_LIST) {
be02a7c0
PN
5078 entry->ln = li->ln;
5079 if (entry->ln != NULL) {
5080 if (li->direction == REDIS_TAIL)
5081 li->ln = li->ln->next;
5082 else
5083 li->ln = li->ln->prev;
5084 return 1;
5085 }
d2ee16ab
PN
5086 } else {
5087 redisPanic("Unknown list encoding");
5088 }
be02a7c0 5089 return 0;
d2ee16ab
PN
5090}
5091
a6dd455b 5092/* Return entry or NULL at the current position of the iterator. */
003f0840
PN
5093static robj *listTypeGet(listTypeEntry *entry) {
5094 listTypeIterator *li = entry->li;
a6dd455b
PN
5095 robj *value = NULL;
5096 if (li->encoding == REDIS_ENCODING_ZIPLIST) {
b6eb9703 5097 unsigned char *vstr;
a6dd455b 5098 unsigned int vlen;
b6eb9703 5099 long long vlong;
be02a7c0 5100 redisAssert(entry->zi != NULL);
b6eb9703
PN
5101 if (ziplistGet(entry->zi,&vstr,&vlen,&vlong)) {
5102 if (vstr) {
5103 value = createStringObject((char*)vstr,vlen);
a6dd455b 5104 } else {
b6eb9703 5105 value = createStringObjectFromLongLong(vlong);
a6dd455b
PN
5106 }
5107 }
5108 } else if (li->encoding == REDIS_ENCODING_LIST) {
be02a7c0
PN
5109 redisAssert(entry->ln != NULL);
5110 value = listNodeValue(entry->ln);
a6dd455b
PN
5111 incrRefCount(value);
5112 } else {
5113 redisPanic("Unknown list encoding");
5114 }
5115 return value;
5116}
5117
d2ee16ab 5118/* Compare the given object with the entry at the current position. */
003f0840
PN
5119static int listTypeEqual(listTypeEntry *entry, robj *o) {
5120 listTypeIterator *li = entry->li;
d2ee16ab
PN
5121 if (li->encoding == REDIS_ENCODING_ZIPLIST) {
5122 redisAssert(o->encoding == REDIS_ENCODING_RAW);
be02a7c0 5123 return ziplistCompare(entry->zi,o->ptr,sdslen(o->ptr));
d2ee16ab 5124 } else if (li->encoding == REDIS_ENCODING_LIST) {
be02a7c0 5125 return equalStringObjects(o,listNodeValue(entry->ln));
d2ee16ab
PN
5126 } else {
5127 redisPanic("Unknown list encoding");
5128 }
5129}
5130
be02a7c0 5131/* Delete the element pointed to. */
003f0840
PN
5132static void listTypeDelete(listTypeEntry *entry) {
5133 listTypeIterator *li = entry->li;
a6dd455b 5134 if (li->encoding == REDIS_ENCODING_ZIPLIST) {
be02a7c0
PN
5135 unsigned char *p = entry->zi;
5136 li->subject->ptr = ziplistDelete(li->subject->ptr,&p);
5137
5138 /* Update position of the iterator depending on the direction */
5139 if (li->direction == REDIS_TAIL)
5140 li->zi = p;
a6dd455b 5141 else
be02a7c0
PN
5142 li->zi = ziplistPrev(li->subject->ptr,p);
5143 } else if (entry->li->encoding == REDIS_ENCODING_LIST) {
5144 listNode *next;
5145 if (li->direction == REDIS_TAIL)
5146 next = entry->ln->next;
a6dd455b 5147 else
be02a7c0
PN
5148 next = entry->ln->prev;
5149 listDelNode(li->subject->ptr,entry->ln);
5150 li->ln = next;
a6dd455b
PN
5151 } else {
5152 redisPanic("Unknown list encoding");
5153 }
5154}
3305306f 5155
003f0840
PN
5156static void listTypeConvert(robj *subject, int enc) {
5157 listTypeIterator *li;
5158 listTypeEntry entry;
d0686e07
PN
5159 redisAssert(subject->type == REDIS_LIST);
5160
5161 if (enc == REDIS_ENCODING_LIST) {
5162 list *l = listCreate();
cd627d4e 5163 listSetFreeMethod(l,decrRefCount);
d0686e07 5164
003f0840
PN
5165 /* listTypeGet returns a robj with incremented refcount */
5166 li = listTypeInitIterator(subject,0,REDIS_TAIL);
5167 while (listTypeNext(li,&entry)) listAddNodeTail(l,listTypeGet(&entry));
5168 listTypeReleaseIterator(li);
d0686e07
PN
5169
5170 subject->encoding = REDIS_ENCODING_LIST;
5171 zfree(subject->ptr);
5172 subject->ptr = l;
5173 } else {
5174 redisPanic("Unsupported list conversion");
5175 }
5176}
5177
c7d9d662
PN
5178static void pushGenericCommand(redisClient *c, int where) {
5179 robj *lobj = lookupKeyWrite(c->db,c->argv[1]);
3305306f 5180 if (lobj == NULL) {
95242ab5 5181 if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) {
520b5a33 5182 addReply(c,shared.cone);
95242ab5 5183 return;
5184 }
1cd92e7f 5185 lobj = createZiplistObject();
09241813 5186 dbAdd(c->db,c->argv[1],lobj);
ed9b544e 5187 } else {
ed9b544e 5188 if (lobj->type != REDIS_LIST) {
5189 addReply(c,shared.wrongtypeerr);
5190 return;
5191 }
95242ab5 5192 if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) {
520b5a33 5193 addReply(c,shared.cone);
95242ab5 5194 return;
5195 }
ed9b544e 5196 }
003f0840
PN
5197 listTypePush(lobj,c->argv[2],where);
5198 addReplyLongLong(c,listTypeLength(lobj));
ed9b544e 5199 server.dirty++;
ed9b544e 5200}
5201
5202static void lpushCommand(redisClient *c) {
5203 pushGenericCommand(c,REDIS_HEAD);
5204}
5205
5206static void rpushCommand(redisClient *c) {
5207 pushGenericCommand(c,REDIS_TAIL);
5208}
5209
5210static void llenCommand(redisClient *c) {
d72562f7
PN
5211 robj *o = lookupKeyReadOrReply(c,c->argv[1],shared.czero);
5212 if (o == NULL || checkType(c,o,REDIS_LIST)) return;
003f0840 5213 addReplyUlong(c,listTypeLength(o));
ed9b544e 5214}
5215
5216static void lindexCommand(redisClient *c) {
697bd567
PN
5217 robj *o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk);
5218 if (o == NULL || checkType(c,o,REDIS_LIST)) return;
ed9b544e 5219 int index = atoi(c->argv[2]->ptr);
bd8db0ad 5220 robj *value = NULL;
dd88747b 5221
697bd567
PN
5222 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
5223 unsigned char *p;
b6eb9703 5224 unsigned char *vstr;
697bd567 5225 unsigned int vlen;
b6eb9703 5226 long long vlong;
697bd567 5227 p = ziplistIndex(o->ptr,index);
b6eb9703
PN
5228 if (ziplistGet(p,&vstr,&vlen,&vlong)) {
5229 if (vstr) {
5230 value = createStringObject((char*)vstr,vlen);
697bd567 5231 } else {
b6eb9703 5232 value = createStringObjectFromLongLong(vlong);
697bd567 5233 }
bd8db0ad
PN
5234 addReplyBulk(c,value);
5235 decrRefCount(value);
697bd567
PN
5236 } else {
5237 addReply(c,shared.nullbulk);
5238 }
5239 } else if (o->encoding == REDIS_ENCODING_LIST) {
5240 listNode *ln = listIndex(o->ptr,index);
5241 if (ln != NULL) {
bd8db0ad
PN
5242 value = listNodeValue(ln);
5243 addReplyBulk(c,value);
697bd567
PN
5244 } else {
5245 addReply(c,shared.nullbulk);
5246 }
ed9b544e 5247 } else {
697bd567 5248 redisPanic("Unknown list encoding");
ed9b544e 5249 }
5250}
5251
5252static void lsetCommand(redisClient *c) {
697bd567
PN
5253 robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr);
5254 if (o == NULL || checkType(c,o,REDIS_LIST)) return;
ed9b544e 5255 int index = atoi(c->argv[2]->ptr);
697bd567 5256 robj *value = c->argv[3];
dd88747b 5257
003f0840 5258 listTypeTryConversion(o,value);
697bd567
PN
5259 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
5260 unsigned char *p, *zl = o->ptr;
5261 p = ziplistIndex(zl,index);
5262 if (p == NULL) {
5263 addReply(c,shared.outofrangeerr);
5264 } else {
be02a7c0 5265 o->ptr = ziplistDelete(o->ptr,&p);
697bd567
PN
5266 value = getDecodedObject(value);
5267 o->ptr = ziplistInsert(o->ptr,p,value->ptr,sdslen(value->ptr));
5268 decrRefCount(value);
5269 addReply(c,shared.ok);
5270 server.dirty++;
5271 }
5272 } else if (o->encoding == REDIS_ENCODING_LIST) {
5273 listNode *ln = listIndex(o->ptr,index);
5274 if (ln == NULL) {
5275 addReply(c,shared.outofrangeerr);
5276 } else {
5277 decrRefCount((robj*)listNodeValue(ln));
5278 listNodeValue(ln) = value;
5279 incrRefCount(value);
5280 addReply(c,shared.ok);
5281 server.dirty++;
5282 }
ed9b544e 5283 } else {
697bd567 5284 redisPanic("Unknown list encoding");
ed9b544e 5285 }
5286}
5287
5288static void popGenericCommand(redisClient *c, int where) {
d72562f7
PN
5289 robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk);
5290 if (o == NULL || checkType(c,o,REDIS_LIST)) return;
3305306f 5291
003f0840 5292 robj *value = listTypePop(o,where);
d72562f7 5293 if (value == NULL) {
dd88747b 5294 addReply(c,shared.nullbulk);
5295 } else {
d72562f7
PN
5296 addReplyBulk(c,value);
5297 decrRefCount(value);
003f0840 5298 if (listTypeLength(o) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5299 server.dirty++;
ed9b544e 5300 }
5301}
5302
5303static void lpopCommand(redisClient *c) {
5304 popGenericCommand(c,REDIS_HEAD);
5305}
5306
5307static void rpopCommand(redisClient *c) {
5308 popGenericCommand(c,REDIS_TAIL);
5309}
5310
5311static void lrangeCommand(redisClient *c) {
a6dd455b 5312 robj *o, *value;
ed9b544e 5313 int start = atoi(c->argv[2]->ptr);
5314 int end = atoi(c->argv[3]->ptr);
dd88747b 5315 int llen;
5316 int rangelen, j;
003f0840 5317 listTypeEntry entry;
dd88747b 5318
4e27f268 5319 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
5320 || checkType(c,o,REDIS_LIST)) return;
003f0840 5321 llen = listTypeLength(o);
dd88747b 5322
5323 /* convert negative indexes */
5324 if (start < 0) start = llen+start;
5325 if (end < 0) end = llen+end;
5326 if (start < 0) start = 0;
5327 if (end < 0) end = 0;
5328
5329 /* indexes sanity checks */
5330 if (start > end || start >= llen) {
5331 /* Out of range start or start > end result in empty list */
5332 addReply(c,shared.emptymultibulk);
5333 return;
5334 }
5335 if (end >= llen) end = llen-1;
5336 rangelen = (end-start)+1;
3305306f 5337
dd88747b 5338 /* Return the result in form of a multi-bulk reply */
dd88747b 5339 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen));
003f0840 5340 listTypeIterator *li = listTypeInitIterator(o,start,REDIS_TAIL);
dd88747b 5341 for (j = 0; j < rangelen; j++) {
003f0840
PN
5342 redisAssert(listTypeNext(li,&entry));
5343 value = listTypeGet(&entry);
a6dd455b 5344 addReplyBulk(c,value);
be02a7c0 5345 decrRefCount(value);
ed9b544e 5346 }
003f0840 5347 listTypeReleaseIterator(li);
ed9b544e 5348}
5349
5350static void ltrimCommand(redisClient *c) {
3305306f 5351 robj *o;
ed9b544e 5352 int start = atoi(c->argv[2]->ptr);
5353 int end = atoi(c->argv[3]->ptr);
dd88747b 5354 int llen;
5355 int j, ltrim, rtrim;
5356 list *list;
5357 listNode *ln;
5358
5359 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.ok)) == NULL ||
5360 checkType(c,o,REDIS_LIST)) return;
003f0840 5361 llen = listTypeLength(o);
dd88747b 5362
5363 /* convert negative indexes */
5364 if (start < 0) start = llen+start;
5365 if (end < 0) end = llen+end;
5366 if (start < 0) start = 0;
5367 if (end < 0) end = 0;
5368
5369 /* indexes sanity checks */
5370 if (start > end || start >= llen) {
5371 /* Out of range start or start > end result in empty list */
5372 ltrim = llen;
5373 rtrim = 0;
ed9b544e 5374 } else {
dd88747b 5375 if (end >= llen) end = llen-1;
5376 ltrim = start;
5377 rtrim = llen-end-1;
5378 }
ed9b544e 5379
dd88747b 5380 /* Remove list elements to perform the trim */
9ae6b0be
PN
5381 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
5382 o->ptr = ziplistDeleteRange(o->ptr,0,ltrim);
5383 o->ptr = ziplistDeleteRange(o->ptr,-rtrim,rtrim);
5384 } else if (o->encoding == REDIS_ENCODING_LIST) {
5385 list = o->ptr;
5386 for (j = 0; j < ltrim; j++) {
5387 ln = listFirst(list);
5388 listDelNode(list,ln);
5389 }
5390 for (j = 0; j < rtrim; j++) {
5391 ln = listLast(list);
5392 listDelNode(list,ln);
5393 }
5394 } else {
5395 redisPanic("Unknown list encoding");
ed9b544e 5396 }
003f0840 5397 if (listTypeLength(o) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5398 server.dirty++;
5399 addReply(c,shared.ok);
ed9b544e 5400}
5401
5402static void lremCommand(redisClient *c) {
d2ee16ab 5403 robj *subject, *obj = c->argv[3];
dd88747b 5404 int toremove = atoi(c->argv[2]->ptr);
5405 int removed = 0;
003f0840 5406 listTypeEntry entry;
a4d1ba9a 5407
d2ee16ab
PN
5408 subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero);
5409 if (subject == NULL || checkType(c,subject,REDIS_LIST)) return;
dd88747b 5410
d2ee16ab
PN
5411 /* Make sure obj is raw when we're dealing with a ziplist */
5412 if (subject->encoding == REDIS_ENCODING_ZIPLIST)
5413 obj = getDecodedObject(obj);
5414
003f0840 5415 listTypeIterator *li;
dd88747b 5416 if (toremove < 0) {
5417 toremove = -toremove;
003f0840 5418 li = listTypeInitIterator(subject,-1,REDIS_HEAD);
d2ee16ab 5419 } else {
003f0840 5420 li = listTypeInitIterator(subject,0,REDIS_TAIL);
dd88747b 5421 }
dd88747b 5422
003f0840
PN
5423 while (listTypeNext(li,&entry)) {
5424 if (listTypeEqual(&entry,obj)) {
5425 listTypeDelete(&entry);
dd88747b 5426 server.dirty++;
5427 removed++;
3fbf9001 5428 if (toremove && removed == toremove) break;
ed9b544e 5429 }
5430 }
003f0840 5431 listTypeReleaseIterator(li);
d2ee16ab
PN
5432
5433 /* Clean up raw encoded object */
5434 if (subject->encoding == REDIS_ENCODING_ZIPLIST)
5435 decrRefCount(obj);
5436
003f0840 5437 if (listTypeLength(subject) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5438 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",removed));
ed9b544e 5439}
5440
12f9d551 5441/* This is the semantic of this command:
0f5f7e9a 5442 * RPOPLPUSH srclist dstlist:
12f9d551 5443 * IF LLEN(srclist) > 0
5444 * element = RPOP srclist
5445 * LPUSH dstlist element
5446 * RETURN element
5447 * ELSE
5448 * RETURN nil
5449 * END
5450 * END
5451 *
5452 * The idea is to be able to get an element from a list in a reliable way
5453 * since the element is not just returned but pushed against another list
5454 * as well. This command was originally proposed by Ezra Zygmuntowicz.
5455 */
0f5f7e9a 5456static void rpoplpushcommand(redisClient *c) {
0f62e177 5457 robj *sobj, *value;
dd88747b 5458 if ((sobj = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
5459 checkType(c,sobj,REDIS_LIST)) return;
12f9d551 5460
003f0840 5461 if (listTypeLength(sobj) == 0) {
12f9d551 5462 addReply(c,shared.nullbulk);
5463 } else {
dd88747b 5464 robj *dobj = lookupKeyWrite(c->db,c->argv[2]);
0f62e177 5465 if (dobj && checkType(c,dobj,REDIS_LIST)) return;
003f0840 5466 value = listTypePop(sobj,REDIS_TAIL);
12f9d551 5467
dd88747b 5468 /* Add the element to the target list (unless it's directly
5469 * passed to some BLPOP-ing client */
0f62e177
PN
5470 if (!handleClientsWaitingListPush(c,c->argv[2],value)) {
5471 /* Create the list if the key does not exist */
5472 if (!dobj) {
1cd92e7f 5473 dobj = createZiplistObject();
09241813 5474 dbAdd(c->db,c->argv[2],dobj);
12f9d551 5475 }
003f0840 5476 listTypePush(dobj,value,REDIS_HEAD);
12f9d551 5477 }
dd88747b 5478
5479 /* Send the element to the client as reply as well */
0f62e177
PN
5480 addReplyBulk(c,value);
5481
003f0840 5482 /* listTypePop returns an object with its refcount incremented */
0f62e177 5483 decrRefCount(value);
dd88747b 5484
0f62e177 5485 /* Delete the source list when it is empty */
003f0840 5486 if (listTypeLength(sobj) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5487 server.dirty++;
12f9d551 5488 }
5489}
5490
ed9b544e 5491/* ==================================== Sets ================================ */
5492
d0b58d53
PN
5493/* Factory method to return a set that *can* hold "value". When the object has
5494 * an integer-encodable value, an intset will be returned. Otherwise a regular
5495 * hash table. */
5496static robj *setTypeCreate(robj *value) {
5497 if (getLongLongFromObject(value,NULL) == REDIS_OK)
5498 return createIntsetObject();
5499 return createSetObject();
5500}
5501
35cabcb5 5502static int setTypeAdd(robj *subject, robj *value) {
d0b58d53 5503 long long llval;
35cabcb5
PN
5504 if (subject->encoding == REDIS_ENCODING_HT) {
5505 if (dictAdd(subject->ptr,value,NULL) == DICT_OK) {
5506 incrRefCount(value);
5507 return 1;
5508 }
d0b58d53
PN
5509 } else if (subject->encoding == REDIS_ENCODING_INTSET) {
5510 if (getLongLongFromObject(value,&llval) == REDIS_OK) {
5511 uint8_t success;
5512 subject->ptr = intsetAdd(subject->ptr,llval,&success);
5513 if (success) return 1;
5514 } else {
5515 /* Failed to get integer from object, convert to regular set. */
5516 setTypeConvert(subject,REDIS_ENCODING_HT);
5517
5518 /* The set *was* an intset and this value is not integer
5519 * encodable, so dictAdd should always work. */
5520 redisAssert(dictAdd(subject->ptr,value,NULL) == DICT_OK);
5521 incrRefCount(value);
5522 return 1;
5523 }
35cabcb5
PN
5524 } else {
5525 redisPanic("Unknown set encoding");
5526 }
5527 return 0;
5528}
5529
5530static int setTypeRemove(robj *subject, robj *value) {
d0b58d53 5531 long long llval;
35cabcb5
PN
5532 if (subject->encoding == REDIS_ENCODING_HT) {
5533 if (dictDelete(subject->ptr,value) == DICT_OK) {
5534 if (htNeedsResize(subject->ptr)) dictResize(subject->ptr);
5535 return 1;
5536 }
d0b58d53
PN
5537 } else if (subject->encoding == REDIS_ENCODING_INTSET) {
5538 if (getLongLongFromObject(value,&llval) == REDIS_OK) {
5539 uint8_t success;
5540 subject->ptr = intsetRemove(subject->ptr,llval,&success);
5541 if (success) return 1;
5542 }
35cabcb5
PN
5543 } else {
5544 redisPanic("Unknown set encoding");
5545 }
5546 return 0;
5547}
5548
5549static int setTypeIsMember(robj *subject, robj *value) {
d0b58d53 5550 long long llval;
35cabcb5
PN
5551 if (subject->encoding == REDIS_ENCODING_HT) {
5552 return dictFind((dict*)subject->ptr,value) != NULL;
d0b58d53
PN
5553 } else if (subject->encoding == REDIS_ENCODING_INTSET) {
5554 if (getLongLongFromObject(value,&llval) == REDIS_OK) {
5555 return intsetFind((intset*)subject->ptr,llval);
5556 }
35cabcb5
PN
5557 } else {
5558 redisPanic("Unknown set encoding");
5559 }
d0b58d53 5560 return 0;
35cabcb5
PN
5561}
5562
5563/* Structure to hold set iteration abstraction. */
5564typedef struct {
d0b58d53 5565 robj *subject;
35cabcb5 5566 int encoding;
d0b58d53 5567 int ii; /* intset iterator */
35cabcb5
PN
5568 dictIterator *di;
5569} setIterator;
5570
5571static setIterator *setTypeInitIterator(robj *subject) {
5572 setIterator *si = zmalloc(sizeof(setIterator));
d0b58d53 5573 si->subject = subject;
35cabcb5
PN
5574 si->encoding = subject->encoding;
5575 if (si->encoding == REDIS_ENCODING_HT) {
5576 si->di = dictGetIterator(subject->ptr);
d0b58d53
PN
5577 } else if (si->encoding == REDIS_ENCODING_INTSET) {
5578 si->ii = 0;
35cabcb5
PN
5579 } else {
5580 redisPanic("Unknown set encoding");
5581 }
5582 return si;
5583}
5584
5585static void setTypeReleaseIterator(setIterator *si) {
5586 if (si->encoding == REDIS_ENCODING_HT)
5587 dictReleaseIterator(si->di);
5588 zfree(si);
5589}
5590
5591/* Move to the next entry in the set. Returns the object at the current
5592 * position, or NULL when the end is reached. This object will have its
5593 * refcount incremented, so the caller needs to take care of this. */
5594static robj *setTypeNext(setIterator *si) {
5595 robj *ret = NULL;
5596 if (si->encoding == REDIS_ENCODING_HT) {
5597 dictEntry *de = dictNext(si->di);
5598 if (de != NULL) {
5599 ret = dictGetEntryKey(de);
5600 incrRefCount(ret);
5601 }
d0b58d53
PN
5602 } else if (si->encoding == REDIS_ENCODING_INTSET) {
5603 long long llval;
5604 if (intsetGet(si->subject->ptr,si->ii++,&llval))
5605 ret = createStringObjectFromLongLong(llval);
35cabcb5
PN
5606 }
5607 return ret;
5608}
5609
5610
5611/* Return random element from set. The returned object will always have
5612 * an incremented refcount. */
5613robj *setTypeRandomElement(robj *subject) {
5614 robj *ret = NULL;
5615 if (subject->encoding == REDIS_ENCODING_HT) {
5616 dictEntry *de = dictGetRandomKey(subject->ptr);
5617 ret = dictGetEntryKey(de);
5618 incrRefCount(ret);
d0b58d53
PN
5619 } else if (subject->encoding == REDIS_ENCODING_INTSET) {
5620 long long llval = intsetRandom(subject->ptr);
5621 ret = createStringObjectFromLongLong(llval);
35cabcb5
PN
5622 } else {
5623 redisPanic("Unknown set encoding");
5624 }
5625 return ret;
5626}
5627
5628static unsigned long setTypeSize(robj *subject) {
5629 if (subject->encoding == REDIS_ENCODING_HT) {
5630 return dictSize((dict*)subject->ptr);
d0b58d53
PN
5631 } else if (subject->encoding == REDIS_ENCODING_INTSET) {
5632 return intsetLen((intset*)subject->ptr);
35cabcb5
PN
5633 } else {
5634 redisPanic("Unknown set encoding");
5635 }
5636}
5637
d0b58d53
PN
5638static void setTypeConvert(robj *subject, int enc) {
5639 setIterator *si;
5640 robj *element;
5641 redisAssert(subject->type == REDIS_SET);
5642
5643 if (enc == REDIS_ENCODING_HT) {
5644 dict *d = dictCreate(&setDictType,NULL);
5645
5646 /* setTypeGet returns a robj with incremented refcount */
5647 si = setTypeInitIterator(subject);
5648 while ((element = setTypeNext(si)) != NULL)
5649 redisAssert(dictAdd(d,element,NULL) == DICT_OK);
5650 setTypeReleaseIterator(si);
5651
5652 subject->encoding = REDIS_ENCODING_HT;
5653 zfree(subject->ptr);
5654 subject->ptr = d;
5655 } else {
5656 redisPanic("Unsupported set conversion");
5657 }
5658}
5659
ed9b544e 5660static void saddCommand(redisClient *c) {
ed9b544e 5661 robj *set;
5662
3305306f 5663 set = lookupKeyWrite(c->db,c->argv[1]);
5664 if (set == NULL) {
d0b58d53 5665 set = setTypeCreate(c->argv[2]);
09241813 5666 dbAdd(c->db,c->argv[1],set);
ed9b544e 5667 } else {
ed9b544e 5668 if (set->type != REDIS_SET) {
c937aa89 5669 addReply(c,shared.wrongtypeerr);
ed9b544e 5670 return;
5671 }
5672 }
35cabcb5 5673 if (setTypeAdd(set,c->argv[2])) {
ed9b544e 5674 server.dirty++;
c937aa89 5675 addReply(c,shared.cone);
ed9b544e 5676 } else {
c937aa89 5677 addReply(c,shared.czero);
ed9b544e 5678 }
5679}
5680
5681static void sremCommand(redisClient *c) {
3305306f 5682 robj *set;
ed9b544e 5683
dd88747b 5684 if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
5685 checkType(c,set,REDIS_SET)) return;
5686
35cabcb5
PN
5687 if (setTypeRemove(set,c->argv[2])) {
5688 if (setTypeSize(set) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5689 server.dirty++;
dd88747b 5690 addReply(c,shared.cone);
ed9b544e 5691 } else {
dd88747b 5692 addReply(c,shared.czero);
ed9b544e 5693 }
5694}
5695
a4460ef4 5696static void smoveCommand(redisClient *c) {
5697 robj *srcset, *dstset;
5698
5699 srcset = lookupKeyWrite(c->db,c->argv[1]);
5700 dstset = lookupKeyWrite(c->db,c->argv[2]);
5701
5702 /* If the source key does not exist return 0, if it's of the wrong type
5703 * raise an error */
5704 if (srcset == NULL || srcset->type != REDIS_SET) {
5705 addReply(c, srcset ? shared.wrongtypeerr : shared.czero);
5706 return;
5707 }
5708 /* Error if the destination key is not a set as well */
5709 if (dstset && dstset->type != REDIS_SET) {
5710 addReply(c,shared.wrongtypeerr);
5711 return;
5712 }
5713 /* Remove the element from the source set */
35cabcb5 5714 if (!setTypeRemove(srcset,c->argv[3])) {
a4460ef4 5715 /* Key not found in the src set! return zero */
5716 addReply(c,shared.czero);
5717 return;
5718 }
35cabcb5 5719 if (setTypeSize(srcset) == 0 && srcset != dstset)
09241813 5720 dbDelete(c->db,c->argv[1]);
a4460ef4 5721 server.dirty++;
5722 /* Add the element to the destination set */
5723 if (!dstset) {
d0b58d53 5724 dstset = setTypeCreate(c->argv[3]);
09241813 5725 dbAdd(c->db,c->argv[2],dstset);
a4460ef4 5726 }
35cabcb5 5727 setTypeAdd(dstset,c->argv[3]);
a4460ef4 5728 addReply(c,shared.cone);
5729}
5730
ed9b544e 5731static void sismemberCommand(redisClient *c) {
3305306f 5732 robj *set;
ed9b544e 5733
dd88747b 5734 if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
5735 checkType(c,set,REDIS_SET)) return;
5736
35cabcb5 5737 if (setTypeIsMember(set,c->argv[2]))
dd88747b 5738 addReply(c,shared.cone);
5739 else
c937aa89 5740 addReply(c,shared.czero);
ed9b544e 5741}
5742
5743static void scardCommand(redisClient *c) {
3305306f 5744 robj *o;
dd88747b 5745
5746 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
5747 checkType(c,o,REDIS_SET)) return;
e0a62c7f 5748
35cabcb5 5749 addReplyUlong(c,setTypeSize(o));
ed9b544e 5750}
5751
12fea928 5752static void spopCommand(redisClient *c) {
35cabcb5 5753 robj *set, *ele;
12fea928 5754
dd88747b 5755 if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
5756 checkType(c,set,REDIS_SET)) return;
5757
35cabcb5
PN
5758 ele = setTypeRandomElement(set);
5759 if (ele == NULL) {
12fea928 5760 addReply(c,shared.nullbulk);
5761 } else {
35cabcb5 5762 setTypeRemove(set,ele);
dd88747b 5763 addReplyBulk(c,ele);
35cabcb5
PN
5764 decrRefCount(ele);
5765 if (setTypeSize(set) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5766 server.dirty++;
12fea928 5767 }
5768}
5769
2abb95a9 5770static void srandmemberCommand(redisClient *c) {
35cabcb5 5771 robj *set, *ele;
2abb95a9 5772
dd88747b 5773 if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
5774 checkType(c,set,REDIS_SET)) return;
5775
35cabcb5
PN
5776 ele = setTypeRandomElement(set);
5777 if (ele == NULL) {
2abb95a9 5778 addReply(c,shared.nullbulk);
5779 } else {
dd88747b 5780 addReplyBulk(c,ele);
35cabcb5 5781 decrRefCount(ele);
2abb95a9 5782 }
5783}
5784
ed9b544e 5785static int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
35cabcb5 5786 return setTypeSize(*(robj**)s1)-setTypeSize(*(robj**)s2);
ed9b544e 5787}
5788
35cabcb5
PN
5789static void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum, robj *dstkey) {
5790 robj **sets = zmalloc(sizeof(robj*)*setnum);
5791 setIterator *si;
5792 robj *ele, *lenobj = NULL, *dstset = NULL;
682ac724 5793 unsigned long j, cardinality = 0;
ed9b544e 5794
35cabcb5
PN
5795 for (j = 0; j < setnum; j++) {
5796 robj *setobj = dstkey ?
5797 lookupKeyWrite(c->db,setkeys[j]) :
5798 lookupKeyRead(c->db,setkeys[j]);
3305306f 5799 if (!setobj) {
35cabcb5 5800 zfree(sets);
5faa6025 5801 if (dstkey) {
09241813 5802 if (dbDelete(c->db,dstkey))
fdcaae84 5803 server.dirty++;
0d36ded0 5804 addReply(c,shared.czero);
5faa6025 5805 } else {
4e27f268 5806 addReply(c,shared.emptymultibulk);
5faa6025 5807 }
ed9b544e 5808 return;
5809 }
35cabcb5
PN
5810 if (checkType(c,setobj,REDIS_SET)) {
5811 zfree(sets);
ed9b544e 5812 return;
5813 }
35cabcb5 5814 sets[j] = setobj;
ed9b544e 5815 }
5816 /* Sort sets from the smallest to largest, this will improve our
5817 * algorithm's performace */
35cabcb5 5818 qsort(sets,setnum,sizeof(robj*),qsortCompareSetsByCardinality);
ed9b544e 5819
5820 /* The first thing we should output is the total number of elements...
5821 * since this is a multi-bulk write, but at this stage we don't know
5822 * the intersection set size, so we use a trick, append an empty object
5823 * to the output list and save the pointer to later modify it with the
5824 * right length */
5825 if (!dstkey) {
5826 lenobj = createObject(REDIS_STRING,NULL);
5827 addReply(c,lenobj);
5828 decrRefCount(lenobj);
5829 } else {
5830 /* If we have a target key where to store the resulting set
5831 * create this key with an empty set inside */
d0b58d53 5832 dstset = createIntsetObject();
ed9b544e 5833 }
5834
5835 /* Iterate all the elements of the first (smallest) set, and test
5836 * the element against all the other sets, if at least one set does
5837 * not include the element it is discarded */
35cabcb5
PN
5838 si = setTypeInitIterator(sets[0]);
5839 while((ele = setTypeNext(si)) != NULL) {
5840 for (j = 1; j < setnum; j++)
5841 if (!setTypeIsMember(sets[j],ele)) break;
5842
5843 /* Only take action when all sets contain the member */
5844 if (j == setnum) {
5845 if (!dstkey) {
5846 addReplyBulk(c,ele);
5847 cardinality++;
5848 } else {
5849 setTypeAdd(dstset,ele);
5850 }
ed9b544e 5851 }
35cabcb5 5852 decrRefCount(ele);
ed9b544e 5853 }
35cabcb5 5854 setTypeReleaseIterator(si);
ed9b544e 5855
83cdfe18 5856 if (dstkey) {
3ea27d37 5857 /* Store the resulting set into the target, if the intersection
5858 * is not an empty set. */
09241813 5859 dbDelete(c->db,dstkey);
35cabcb5 5860 if (setTypeSize(dstset) > 0) {
09241813 5861 dbAdd(c->db,dstkey,dstset);
35cabcb5 5862 addReplyLongLong(c,setTypeSize(dstset));
3ea27d37 5863 } else {
5864 decrRefCount(dstset);
d36c4e97 5865 addReply(c,shared.czero);
3ea27d37 5866 }
40d224a9 5867 server.dirty++;
d36c4e97 5868 } else {
5869 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",cardinality);
40d224a9 5870 }
35cabcb5 5871 zfree(sets);
ed9b544e 5872}
5873
5874static void sinterCommand(redisClient *c) {
5875 sinterGenericCommand(c,c->argv+1,c->argc-1,NULL);
5876}
5877
5878static void sinterstoreCommand(redisClient *c) {
5879 sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
5880}
5881
f4f56e1d 5882#define REDIS_OP_UNION 0
5883#define REDIS_OP_DIFF 1
2830ca53 5884#define REDIS_OP_INTER 2
f4f56e1d 5885
35cabcb5
PN
5886static void sunionDiffGenericCommand(redisClient *c, robj **setkeys, int setnum, robj *dstkey, int op) {
5887 robj **sets = zmalloc(sizeof(robj*)*setnum);
5888 setIterator *si;
5889 robj *ele, *dstset = NULL;
40d224a9 5890 int j, cardinality = 0;
5891
35cabcb5
PN
5892 for (j = 0; j < setnum; j++) {
5893 robj *setobj = dstkey ?
5894 lookupKeyWrite(c->db,setkeys[j]) :
5895 lookupKeyRead(c->db,setkeys[j]);
40d224a9 5896 if (!setobj) {
35cabcb5 5897 sets[j] = NULL;
40d224a9 5898 continue;
5899 }
35cabcb5
PN
5900 if (checkType(c,setobj,REDIS_SET)) {
5901 zfree(sets);
40d224a9 5902 return;
5903 }
35cabcb5 5904 sets[j] = setobj;
40d224a9 5905 }
5906
5907 /* We need a temp set object to store our union. If the dstkey
5908 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
5909 * this set object will be the resulting object to set into the target key*/
d0b58d53 5910 dstset = createIntsetObject();
40d224a9 5911
40d224a9 5912 /* Iterate all the elements of all the sets, add every element a single
5913 * time to the result set */
35cabcb5
PN
5914 for (j = 0; j < setnum; j++) {
5915 if (op == REDIS_OP_DIFF && j == 0 && !sets[j]) break; /* result set is empty */
5916 if (!sets[j]) continue; /* non existing keys are like empty sets */
40d224a9 5917
35cabcb5
PN
5918 si = setTypeInitIterator(sets[j]);
5919 while((ele = setTypeNext(si)) != NULL) {
f4f56e1d 5920 if (op == REDIS_OP_UNION || j == 0) {
35cabcb5 5921 if (setTypeAdd(dstset,ele)) {
40d224a9 5922 cardinality++;
5923 }
f4f56e1d 5924 } else if (op == REDIS_OP_DIFF) {
35cabcb5 5925 if (setTypeRemove(dstset,ele)) {
f4f56e1d 5926 cardinality--;
5927 }
40d224a9 5928 }
35cabcb5 5929 decrRefCount(ele);
40d224a9 5930 }
35cabcb5 5931 setTypeReleaseIterator(si);
51829ed3 5932
35cabcb5 5933 /* Exit when result set is empty. */
d36c4e97 5934 if (op == REDIS_OP_DIFF && cardinality == 0) break;
40d224a9 5935 }
5936
f4f56e1d 5937 /* Output the content of the resulting set, if not in STORE mode */
5938 if (!dstkey) {
5939 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",cardinality));
35cabcb5
PN
5940 si = setTypeInitIterator(dstset);
5941 while((ele = setTypeNext(si)) != NULL) {
dd88747b 5942 addReplyBulk(c,ele);
35cabcb5 5943 decrRefCount(ele);
f4f56e1d 5944 }
35cabcb5 5945 setTypeReleaseIterator(si);
d36c4e97 5946 decrRefCount(dstset);
83cdfe18
AG
5947 } else {
5948 /* If we have a target key where to store the resulting set
5949 * create this key with the result set inside */
09241813 5950 dbDelete(c->db,dstkey);
35cabcb5 5951 if (setTypeSize(dstset) > 0) {
09241813 5952 dbAdd(c->db,dstkey,dstset);
35cabcb5 5953 addReplyLongLong(c,setTypeSize(dstset));
3ea27d37 5954 } else {
5955 decrRefCount(dstset);
d36c4e97 5956 addReply(c,shared.czero);
3ea27d37 5957 }
40d224a9 5958 server.dirty++;
5959 }
35cabcb5 5960 zfree(sets);
40d224a9 5961}
5962
5963static void sunionCommand(redisClient *c) {
f4f56e1d 5964 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_UNION);
40d224a9 5965}
5966
5967static void sunionstoreCommand(redisClient *c) {
f4f56e1d 5968 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_UNION);
5969}
5970
5971static void sdiffCommand(redisClient *c) {
5972 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_DIFF);
5973}
5974
5975static void sdiffstoreCommand(redisClient *c) {
5976 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_DIFF);
40d224a9 5977}
5978
6b47e12e 5979/* ==================================== ZSets =============================== */
5980
5981/* ZSETs are ordered sets using two data structures to hold the same elements
5982 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
5983 * data structure.
5984 *
5985 * The elements are added to an hash table mapping Redis objects to scores.
5986 * At the same time the elements are added to a skip list mapping scores
5987 * to Redis objects (so objects are sorted by scores in this "view"). */
5988
5989/* This skiplist implementation is almost a C translation of the original
5990 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
5991 * Alternative to Balanced Trees", modified in three ways:
5992 * a) this implementation allows for repeated values.
5993 * b) the comparison is not just by key (our 'score') but by satellite data.
5994 * c) there is a back pointer, so it's a doubly linked list with the back
5995 * pointers being only at "level 1". This allows to traverse the list
5996 * from tail to head, useful for ZREVRANGE. */
5997
5998static zskiplistNode *zslCreateNode(int level, double score, robj *obj) {
5999 zskiplistNode *zn = zmalloc(sizeof(*zn));
6000
6001 zn->forward = zmalloc(sizeof(zskiplistNode*) * level);
2f4dd7e0 6002 if (level > 1)
2b37892e 6003 zn->span = zmalloc(sizeof(unsigned int) * (level - 1));
2f4dd7e0 6004 else
6005 zn->span = NULL;
6b47e12e 6006 zn->score = score;
6007 zn->obj = obj;
6008 return zn;
6009}
6010
6011static zskiplist *zslCreate(void) {
6012 int j;
6013 zskiplist *zsl;
e0a62c7f 6014
6b47e12e 6015 zsl = zmalloc(sizeof(*zsl));
6016 zsl->level = 1;
cc812361 6017 zsl->length = 0;
6b47e12e 6018 zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
69d95c3e 6019 for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
6b47e12e 6020 zsl->header->forward[j] = NULL;
94e543b5 6021
6022 /* span has space for ZSKIPLIST_MAXLEVEL-1 elements */
6023 if (j < ZSKIPLIST_MAXLEVEL-1)
6024 zsl->header->span[j] = 0;
69d95c3e 6025 }
e3870fab 6026 zsl->header->backward = NULL;
6027 zsl->tail = NULL;
6b47e12e 6028 return zsl;
6029}
6030
fd8ccf44 6031static void zslFreeNode(zskiplistNode *node) {
6032 decrRefCount(node->obj);
ad807e6f 6033 zfree(node->forward);
69d95c3e 6034 zfree(node->span);
fd8ccf44 6035 zfree(node);
6036}
6037
6038static void zslFree(zskiplist *zsl) {
ad807e6f 6039 zskiplistNode *node = zsl->header->forward[0], *next;
fd8ccf44 6040
ad807e6f 6041 zfree(zsl->header->forward);
69d95c3e 6042 zfree(zsl->header->span);
ad807e6f 6043 zfree(zsl->header);
fd8ccf44 6044 while(node) {
599379dd 6045 next = node->forward[0];
fd8ccf44 6046 zslFreeNode(node);
6047 node = next;
6048 }
ad807e6f 6049 zfree(zsl);
fd8ccf44 6050}
6051
6b47e12e 6052static int zslRandomLevel(void) {
6053 int level = 1;
6054 while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
6055 level += 1;
10c2baa5 6056 return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
6b47e12e 6057}
6058
6059static void zslInsert(zskiplist *zsl, double score, robj *obj) {
6060 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
2b37892e 6061 unsigned int rank[ZSKIPLIST_MAXLEVEL];
6b47e12e 6062 int i, level;
6063
6064 x = zsl->header;
6065 for (i = zsl->level-1; i >= 0; i--) {
2b37892e
PN
6066 /* store rank that is crossed to reach the insert position */
6067 rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
69d95c3e 6068
9d60e6e4 6069 while (x->forward[i] &&
6070 (x->forward[i]->score < score ||
6071 (x->forward[i]->score == score &&
69d95c3e 6072 compareStringObjects(x->forward[i]->obj,obj) < 0))) {
a50ea45c 6073 rank[i] += i > 0 ? x->span[i-1] : 1;
6b47e12e 6074 x = x->forward[i];
69d95c3e 6075 }
6b47e12e 6076 update[i] = x;
6077 }
6b47e12e 6078 /* we assume the key is not already inside, since we allow duplicated
6079 * scores, and the re-insertion of score and redis object should never
6080 * happpen since the caller of zslInsert() should test in the hash table
6081 * if the element is already inside or not. */
6082 level = zslRandomLevel();
6083 if (level > zsl->level) {
69d95c3e 6084 for (i = zsl->level; i < level; i++) {
2b37892e 6085 rank[i] = 0;
6b47e12e 6086 update[i] = zsl->header;
2b37892e 6087 update[i]->span[i-1] = zsl->length;
69d95c3e 6088 }
6b47e12e 6089 zsl->level = level;
6090 }
6091 x = zslCreateNode(level,score,obj);
6092 for (i = 0; i < level; i++) {
6093 x->forward[i] = update[i]->forward[i];
6094 update[i]->forward[i] = x;
69d95c3e
PN
6095
6096 /* update span covered by update[i] as x is inserted here */
2b37892e
PN
6097 if (i > 0) {
6098 x->span[i-1] = update[i]->span[i-1] - (rank[0] - rank[i]);
6099 update[i]->span[i-1] = (rank[0] - rank[i]) + 1;
6100 }
6b47e12e 6101 }
69d95c3e
PN
6102
6103 /* increment span for untouched levels */
6104 for (i = level; i < zsl->level; i++) {
2b37892e 6105 update[i]->span[i-1]++;
69d95c3e
PN
6106 }
6107
bb975144 6108 x->backward = (update[0] == zsl->header) ? NULL : update[0];
e3870fab 6109 if (x->forward[0])
6110 x->forward[0]->backward = x;
6111 else
6112 zsl->tail = x;
cc812361 6113 zsl->length++;
6b47e12e 6114}
6115
84105336
PN
6116/* Internal function used by zslDelete, zslDeleteByScore and zslDeleteByRank */
6117void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) {
6118 int i;
6119 for (i = 0; i < zsl->level; i++) {
6120 if (update[i]->forward[i] == x) {
6121 if (i > 0) {
6122 update[i]->span[i-1] += x->span[i-1] - 1;
6123 }
6124 update[i]->forward[i] = x->forward[i];
6125 } else {
6126 /* invariant: i > 0, because update[0]->forward[0]
6127 * is always equal to x */
6128 update[i]->span[i-1] -= 1;
6129 }
6130 }
6131 if (x->forward[0]) {
6132 x->forward[0]->backward = x->backward;
6133 } else {
6134 zsl->tail = x->backward;
6135 }
6136 while(zsl->level > 1 && zsl->header->forward[zsl->level-1] == NULL)
6137 zsl->level--;
6138 zsl->length--;
6139}
6140
50c55df5 6141/* Delete an element with matching score/object from the skiplist. */
fd8ccf44 6142static int zslDelete(zskiplist *zsl, double score, robj *obj) {
e197b441 6143 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
6144 int i;
6145
6146 x = zsl->header;
6147 for (i = zsl->level-1; i >= 0; i--) {
9d60e6e4 6148 while (x->forward[i] &&
6149 (x->forward[i]->score < score ||
6150 (x->forward[i]->score == score &&
6151 compareStringObjects(x->forward[i]->obj,obj) < 0)))
e197b441 6152 x = x->forward[i];
6153 update[i] = x;
6154 }
6155 /* We may have multiple elements with the same score, what we need
6156 * is to find the element with both the right score and object. */
6157 x = x->forward[0];
bf028098 6158 if (x && score == x->score && equalStringObjects(x->obj,obj)) {
84105336 6159 zslDeleteNode(zsl, x, update);
9d60e6e4 6160 zslFreeNode(x);
9d60e6e4 6161 return 1;
6162 } else {
6163 return 0; /* not found */
e197b441 6164 }
6165 return 0; /* not found */
fd8ccf44 6166}
6167
1807985b 6168/* Delete all the elements with score between min and max from the skiplist.
6169 * Min and mx are inclusive, so a score >= min || score <= max is deleted.
6170 * Note that this function takes the reference to the hash table view of the
6171 * sorted set, in order to remove the elements from the hash table too. */
f84d3933 6172static unsigned long zslDeleteRangeByScore(zskiplist *zsl, double min, double max, dict *dict) {
1807985b 6173 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
6174 unsigned long removed = 0;
6175 int i;
6176
6177 x = zsl->header;
6178 for (i = zsl->level-1; i >= 0; i--) {
6179 while (x->forward[i] && x->forward[i]->score < min)
6180 x = x->forward[i];
6181 update[i] = x;
6182 }
6183 /* We may have multiple elements with the same score, what we need
6184 * is to find the element with both the right score and object. */
6185 x = x->forward[0];
6186 while (x && x->score <= max) {
84105336
PN
6187 zskiplistNode *next = x->forward[0];
6188 zslDeleteNode(zsl, x, update);
1807985b 6189 dictDelete(dict,x->obj);
6190 zslFreeNode(x);
1807985b 6191 removed++;
6192 x = next;
6193 }
6194 return removed; /* not found */
6195}
1807985b 6196
9212eafd 6197/* Delete all the elements with rank between start and end from the skiplist.
2424490f 6198 * Start and end are inclusive. Note that start and end need to be 1-based */
9212eafd
PN
6199static unsigned long zslDeleteRangeByRank(zskiplist *zsl, unsigned int start, unsigned int end, dict *dict) {
6200 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
6201 unsigned long traversed = 0, removed = 0;
6202 int i;
6203
9212eafd
PN
6204 x = zsl->header;
6205 for (i = zsl->level-1; i >= 0; i--) {
6206 while (x->forward[i] && (traversed + (i > 0 ? x->span[i-1] : 1)) < start) {
6207 traversed += i > 0 ? x->span[i-1] : 1;
6208 x = x->forward[i];
1807985b 6209 }
9212eafd
PN
6210 update[i] = x;
6211 }
6212
6213 traversed++;
6214 x = x->forward[0];
6215 while (x && traversed <= end) {
84105336
PN
6216 zskiplistNode *next = x->forward[0];
6217 zslDeleteNode(zsl, x, update);
1807985b 6218 dictDelete(dict,x->obj);
6219 zslFreeNode(x);
1807985b 6220 removed++;
9212eafd 6221 traversed++;
1807985b 6222 x = next;
6223 }
9212eafd 6224 return removed;
1807985b 6225}
6226
50c55df5 6227/* Find the first node having a score equal or greater than the specified one.
6228 * Returns NULL if there is no match. */
6229static zskiplistNode *zslFirstWithScore(zskiplist *zsl, double score) {
6230 zskiplistNode *x;
6231 int i;
6232
6233 x = zsl->header;
6234 for (i = zsl->level-1; i >= 0; i--) {
6235 while (x->forward[i] && x->forward[i]->score < score)
6236 x = x->forward[i];
6237 }
6238 /* We may have multiple elements with the same score, what we need
6239 * is to find the element with both the right score and object. */
6240 return x->forward[0];
6241}
6242
27b0ccca
PN
6243/* Find the rank for an element by both score and key.
6244 * Returns 0 when the element cannot be found, rank otherwise.
6245 * Note that the rank is 1-based due to the span of zsl->header to the
6246 * first element. */
003f0840 6247static unsigned long zslistTypeGetRank(zskiplist *zsl, double score, robj *o) {
27b0ccca
PN
6248 zskiplistNode *x;
6249 unsigned long rank = 0;
6250 int i;
6251
6252 x = zsl->header;
6253 for (i = zsl->level-1; i >= 0; i--) {
6254 while (x->forward[i] &&
6255 (x->forward[i]->score < score ||
6256 (x->forward[i]->score == score &&
6257 compareStringObjects(x->forward[i]->obj,o) <= 0))) {
a50ea45c 6258 rank += i > 0 ? x->span[i-1] : 1;
27b0ccca
PN
6259 x = x->forward[i];
6260 }
6261
6262 /* x might be equal to zsl->header, so test if obj is non-NULL */
bf028098 6263 if (x->obj && equalStringObjects(x->obj,o)) {
27b0ccca
PN
6264 return rank;
6265 }
6266 }
6267 return 0;
6268}
6269
e74825c2 6270/* Finds an element by its rank. The rank argument needs to be 1-based. */
003f0840 6271zskiplistNode* zslistTypeGetElementByRank(zskiplist *zsl, unsigned long rank) {
e74825c2
PN
6272 zskiplistNode *x;
6273 unsigned long traversed = 0;
6274 int i;
6275
6276 x = zsl->header;
6277 for (i = zsl->level-1; i >= 0; i--) {
dd88747b 6278 while (x->forward[i] && (traversed + (i>0 ? x->span[i-1] : 1)) <= rank)
6279 {
a50ea45c 6280 traversed += i > 0 ? x->span[i-1] : 1;
e74825c2
PN
6281 x = x->forward[i];
6282 }
e74825c2
PN
6283 if (traversed == rank) {
6284 return x;
6285 }
6286 }
6287 return NULL;
6288}
6289
fd8ccf44 6290/* The actual Z-commands implementations */
6291
7db723ad 6292/* This generic command implements both ZADD and ZINCRBY.
e2665397 6293 * scoreval is the score if the operation is a ZADD (doincrement == 0) or
7db723ad 6294 * the increment if the operation is a ZINCRBY (doincrement == 1). */
e2665397 6295static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, int doincrement) {
fd8ccf44 6296 robj *zsetobj;
6297 zset *zs;
6298 double *score;
6299
5fc9229c 6300 if (isnan(scoreval)) {
6301 addReplySds(c,sdsnew("-ERR provide score is Not A Number (nan)\r\n"));
6302 return;
6303 }
6304
e2665397 6305 zsetobj = lookupKeyWrite(c->db,key);
fd8ccf44 6306 if (zsetobj == NULL) {
6307 zsetobj = createZsetObject();
09241813 6308 dbAdd(c->db,key,zsetobj);
fd8ccf44 6309 } else {
6310 if (zsetobj->type != REDIS_ZSET) {
6311 addReply(c,shared.wrongtypeerr);
6312 return;
6313 }
6314 }
fd8ccf44 6315 zs = zsetobj->ptr;
e2665397 6316
7db723ad 6317 /* Ok now since we implement both ZADD and ZINCRBY here the code
e2665397 6318 * needs to handle the two different conditions. It's all about setting
6319 * '*score', that is, the new score to set, to the right value. */
6320 score = zmalloc(sizeof(double));
6321 if (doincrement) {
6322 dictEntry *de;
6323
6324 /* Read the old score. If the element was not present starts from 0 */
6325 de = dictFind(zs->dict,ele);
6326 if (de) {
6327 double *oldscore = dictGetEntryVal(de);
6328 *score = *oldscore + scoreval;
6329 } else {
6330 *score = scoreval;
6331 }
5fc9229c 6332 if (isnan(*score)) {
6333 addReplySds(c,
6334 sdsnew("-ERR resulting score is Not A Number (nan)\r\n"));
6335 zfree(score);
6336 /* Note that we don't need to check if the zset may be empty and
6337 * should be removed here, as we can only obtain Nan as score if
6338 * there was already an element in the sorted set. */
6339 return;
6340 }
e2665397 6341 } else {
6342 *score = scoreval;
6343 }
6344
6345 /* What follows is a simple remove and re-insert operation that is common
7db723ad 6346 * to both ZADD and ZINCRBY... */
e2665397 6347 if (dictAdd(zs->dict,ele,score) == DICT_OK) {
fd8ccf44 6348 /* case 1: New element */
e2665397 6349 incrRefCount(ele); /* added to hash */
6350 zslInsert(zs->zsl,*score,ele);
6351 incrRefCount(ele); /* added to skiplist */
fd8ccf44 6352 server.dirty++;
e2665397 6353 if (doincrement)
e2665397 6354 addReplyDouble(c,*score);
91d71bfc 6355 else
6356 addReply(c,shared.cone);
fd8ccf44 6357 } else {
6358 dictEntry *de;
6359 double *oldscore;
e0a62c7f 6360
fd8ccf44 6361 /* case 2: Score update operation */
e2665397 6362 de = dictFind(zs->dict,ele);
dfc5e96c 6363 redisAssert(de != NULL);
fd8ccf44 6364 oldscore = dictGetEntryVal(de);
6365 if (*score != *oldscore) {
6366 int deleted;
6367
e2665397 6368 /* Remove and insert the element in the skip list with new score */
6369 deleted = zslDelete(zs->zsl,*oldscore,ele);
dfc5e96c 6370 redisAssert(deleted != 0);
e2665397 6371 zslInsert(zs->zsl,*score,ele);
6372 incrRefCount(ele);
6373 /* Update the score in the hash table */
6374 dictReplace(zs->dict,ele,score);
fd8ccf44 6375 server.dirty++;
2161a965 6376 } else {
6377 zfree(score);
fd8ccf44 6378 }
e2665397 6379 if (doincrement)
6380 addReplyDouble(c,*score);
6381 else
6382 addReply(c,shared.czero);
fd8ccf44 6383 }
6384}
6385
e2665397 6386static void zaddCommand(redisClient *c) {
6387 double scoreval;
6388
bd79a6bd 6389 if (getDoubleFromObjectOrReply(c, c->argv[2], &scoreval, NULL) != REDIS_OK) return;
e2665397 6390 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,0);
6391}
6392
7db723ad 6393static void zincrbyCommand(redisClient *c) {
e2665397 6394 double scoreval;
6395
bd79a6bd 6396 if (getDoubleFromObjectOrReply(c, c->argv[2], &scoreval, NULL) != REDIS_OK) return;
e2665397 6397 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1);
6398}
6399
1b7106e7 6400static void zremCommand(redisClient *c) {
6401 robj *zsetobj;
6402 zset *zs;
dd88747b 6403 dictEntry *de;
6404 double *oldscore;
6405 int deleted;
1b7106e7 6406
dd88747b 6407 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
6408 checkType(c,zsetobj,REDIS_ZSET)) return;
1b7106e7 6409
dd88747b 6410 zs = zsetobj->ptr;
6411 de = dictFind(zs->dict,c->argv[2]);
6412 if (de == NULL) {
6413 addReply(c,shared.czero);
6414 return;
1b7106e7 6415 }
dd88747b 6416 /* Delete from the skiplist */
6417 oldscore = dictGetEntryVal(de);
6418 deleted = zslDelete(zs->zsl,*oldscore,c->argv[2]);
6419 redisAssert(deleted != 0);
6420
6421 /* Delete from the hash table */
6422 dictDelete(zs->dict,c->argv[2]);
6423 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
09241813 6424 if (dictSize(zs->dict) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 6425 server.dirty++;
6426 addReply(c,shared.cone);
1b7106e7 6427}
6428
1807985b 6429static void zremrangebyscoreCommand(redisClient *c) {
bbe025e0
AM
6430 double min;
6431 double max;
dd88747b 6432 long deleted;
1807985b 6433 robj *zsetobj;
6434 zset *zs;
6435
bd79a6bd
PN
6436 if ((getDoubleFromObjectOrReply(c, c->argv[2], &min, NULL) != REDIS_OK) ||
6437 (getDoubleFromObjectOrReply(c, c->argv[3], &max, NULL) != REDIS_OK)) return;
bbe025e0 6438
dd88747b 6439 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
6440 checkType(c,zsetobj,REDIS_ZSET)) return;
1807985b 6441
dd88747b 6442 zs = zsetobj->ptr;
6443 deleted = zslDeleteRangeByScore(zs->zsl,min,max,zs->dict);
6444 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
09241813 6445 if (dictSize(zs->dict) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 6446 server.dirty += deleted;
482b672d 6447 addReplyLongLong(c,deleted);
1807985b 6448}
6449
9212eafd 6450static void zremrangebyrankCommand(redisClient *c) {
bbe025e0
AM
6451 long start;
6452 long end;
dd88747b 6453 int llen;
6454 long deleted;
9212eafd
PN
6455 robj *zsetobj;
6456 zset *zs;
6457
bd79a6bd
PN
6458 if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
6459 (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
bbe025e0 6460
dd88747b 6461 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
6462 checkType(c,zsetobj,REDIS_ZSET)) return;
6463 zs = zsetobj->ptr;
6464 llen = zs->zsl->length;
9212eafd 6465
dd88747b 6466 /* convert negative indexes */
6467 if (start < 0) start = llen+start;
6468 if (end < 0) end = llen+end;
6469 if (start < 0) start = 0;
6470 if (end < 0) end = 0;
9212eafd 6471
dd88747b 6472 /* indexes sanity checks */
6473 if (start > end || start >= llen) {
6474 addReply(c,shared.czero);
6475 return;
9212eafd 6476 }
dd88747b 6477 if (end >= llen) end = llen-1;
6478
6479 /* increment start and end because zsl*Rank functions
6480 * use 1-based rank */
6481 deleted = zslDeleteRangeByRank(zs->zsl,start+1,end+1,zs->dict);
6482 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
09241813 6483 if (dictSize(zs->dict) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 6484 server.dirty += deleted;
482b672d 6485 addReplyLongLong(c, deleted);
9212eafd
PN
6486}
6487
8f92e768
PN
6488typedef struct {
6489 dict *dict;
6490 double weight;
6491} zsetopsrc;
6492
6493static int qsortCompareZsetopsrcByCardinality(const void *s1, const void *s2) {
6494 zsetopsrc *d1 = (void*) s1, *d2 = (void*) s2;
6495 unsigned long size1, size2;
6496 size1 = d1->dict ? dictSize(d1->dict) : 0;
6497 size2 = d2->dict ? dictSize(d2->dict) : 0;
6498 return size1 - size2;
6499}
6500
d2764cd6
PN
6501#define REDIS_AGGR_SUM 1
6502#define REDIS_AGGR_MIN 2
6503#define REDIS_AGGR_MAX 3
bc000c1d 6504#define zunionInterDictValue(_e) (dictGetEntryVal(_e) == NULL ? 1.0 : *(double*)dictGetEntryVal(_e))
d2764cd6
PN
6505
6506inline static void zunionInterAggregate(double *target, double val, int aggregate) {
6507 if (aggregate == REDIS_AGGR_SUM) {
6508 *target = *target + val;
6509 } else if (aggregate == REDIS_AGGR_MIN) {
6510 *target = val < *target ? val : *target;
6511 } else if (aggregate == REDIS_AGGR_MAX) {
6512 *target = val > *target ? val : *target;
6513 } else {
6514 /* safety net */
f83c6cb5 6515 redisPanic("Unknown ZUNION/INTER aggregate type");
d2764cd6
PN
6516 }
6517}
6518
2830ca53 6519static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
bc000c1d 6520 int i, j, setnum;
d2764cd6 6521 int aggregate = REDIS_AGGR_SUM;
8f92e768 6522 zsetopsrc *src;
2830ca53
PN
6523 robj *dstobj;
6524 zset *dstzset;
b287c9bb
PN
6525 dictIterator *di;
6526 dictEntry *de;
6527
bc000c1d
JC
6528 /* expect setnum input keys to be given */
6529 setnum = atoi(c->argv[2]->ptr);
6530 if (setnum < 1) {
5d373da9 6531 addReplySds(c,sdsnew("-ERR at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE\r\n"));
2830ca53 6532 return;
b287c9bb 6533 }
2830ca53
PN
6534
6535 /* test if the expected number of keys would overflow */
bc000c1d 6536 if (3+setnum > c->argc) {
b287c9bb
PN
6537 addReply(c,shared.syntaxerr);
6538 return;
6539 }
6540
2830ca53 6541 /* read keys to be used for input */
bc000c1d
JC
6542 src = zmalloc(sizeof(zsetopsrc) * setnum);
6543 for (i = 0, j = 3; i < setnum; i++, j++) {
6544 robj *obj = lookupKeyWrite(c->db,c->argv[j]);
6545 if (!obj) {
8f92e768 6546 src[i].dict = NULL;
b287c9bb 6547 } else {
bc000c1d
JC
6548 if (obj->type == REDIS_ZSET) {
6549 src[i].dict = ((zset*)obj->ptr)->dict;
6550 } else if (obj->type == REDIS_SET) {
6551 src[i].dict = (obj->ptr);
6552 } else {
8f92e768 6553 zfree(src);
b287c9bb
PN
6554 addReply(c,shared.wrongtypeerr);
6555 return;
6556 }
b287c9bb 6557 }
2830ca53
PN
6558
6559 /* default all weights to 1 */
8f92e768 6560 src[i].weight = 1.0;
b287c9bb
PN
6561 }
6562
2830ca53
PN
6563 /* parse optional extra arguments */
6564 if (j < c->argc) {
d2764cd6 6565 int remaining = c->argc - j;
b287c9bb 6566
2830ca53 6567 while (remaining) {
bc000c1d 6568 if (remaining >= (setnum + 1) && !strcasecmp(c->argv[j]->ptr,"weights")) {
2830ca53 6569 j++; remaining--;
bc000c1d 6570 for (i = 0; i < setnum; i++, j++, remaining--) {
bd79a6bd 6571 if (getDoubleFromObjectOrReply(c, c->argv[j], &src[i].weight, NULL) != REDIS_OK)
bbe025e0 6572 return;
2830ca53 6573 }
d2764cd6
PN
6574 } else if (remaining >= 2 && !strcasecmp(c->argv[j]->ptr,"aggregate")) {
6575 j++; remaining--;
6576 if (!strcasecmp(c->argv[j]->ptr,"sum")) {
6577 aggregate = REDIS_AGGR_SUM;
6578 } else if (!strcasecmp(c->argv[j]->ptr,"min")) {
6579 aggregate = REDIS_AGGR_MIN;
6580 } else if (!strcasecmp(c->argv[j]->ptr,"max")) {
6581 aggregate = REDIS_AGGR_MAX;
6582 } else {
6583 zfree(src);
6584 addReply(c,shared.syntaxerr);
6585 return;
6586 }
6587 j++; remaining--;
2830ca53 6588 } else {
8f92e768 6589 zfree(src);
2830ca53
PN
6590 addReply(c,shared.syntaxerr);
6591 return;
6592 }
6593 }
6594 }
b287c9bb 6595
d2764cd6
PN
6596 /* sort sets from the smallest to largest, this will improve our
6597 * algorithm's performance */
bc000c1d 6598 qsort(src,setnum,sizeof(zsetopsrc),qsortCompareZsetopsrcByCardinality);
d2764cd6 6599
2830ca53
PN
6600 dstobj = createZsetObject();
6601 dstzset = dstobj->ptr;
6602
6603 if (op == REDIS_OP_INTER) {
8f92e768
PN
6604 /* skip going over all entries if the smallest zset is NULL or empty */
6605 if (src[0].dict && dictSize(src[0].dict) > 0) {
6606 /* precondition: as src[0].dict is non-empty and the zsets are ordered
6607 * from small to large, all src[i > 0].dict are non-empty too */
6608 di = dictGetIterator(src[0].dict);
2830ca53 6609 while((de = dictNext(di)) != NULL) {
d2764cd6 6610 double *score = zmalloc(sizeof(double)), value;
bc000c1d 6611 *score = src[0].weight * zunionInterDictValue(de);
2830ca53 6612
bc000c1d 6613 for (j = 1; j < setnum; j++) {
d2764cd6 6614 dictEntry *other = dictFind(src[j].dict,dictGetEntryKey(de));
2830ca53 6615 if (other) {
bc000c1d 6616 value = src[j].weight * zunionInterDictValue(other);
d2764cd6 6617 zunionInterAggregate(score, value, aggregate);
2830ca53
PN
6618 } else {
6619 break;
6620 }
6621 }
b287c9bb 6622
2830ca53 6623 /* skip entry when not present in every source dict */
bc000c1d 6624 if (j != setnum) {
2830ca53
PN
6625 zfree(score);
6626 } else {
6627 robj *o = dictGetEntryKey(de);
6628 dictAdd(dstzset->dict,o,score);
6629 incrRefCount(o); /* added to dictionary */
6630 zslInsert(dstzset->zsl,*score,o);
6631 incrRefCount(o); /* added to skiplist */
b287c9bb
PN
6632 }
6633 }
2830ca53
PN
6634 dictReleaseIterator(di);
6635 }
6636 } else if (op == REDIS_OP_UNION) {
bc000c1d 6637 for (i = 0; i < setnum; i++) {
8f92e768 6638 if (!src[i].dict) continue;
2830ca53 6639
8f92e768 6640 di = dictGetIterator(src[i].dict);
2830ca53
PN
6641 while((de = dictNext(di)) != NULL) {
6642 /* skip key when already processed */
6643 if (dictFind(dstzset->dict,dictGetEntryKey(de)) != NULL) continue;
6644
d2764cd6 6645 double *score = zmalloc(sizeof(double)), value;
bc000c1d 6646 *score = src[i].weight * zunionInterDictValue(de);
2830ca53 6647
d2764cd6
PN
6648 /* because the zsets are sorted by size, its only possible
6649 * for sets at larger indices to hold this entry */
bc000c1d 6650 for (j = (i+1); j < setnum; j++) {
d2764cd6 6651 dictEntry *other = dictFind(src[j].dict,dictGetEntryKey(de));
2830ca53 6652 if (other) {
bc000c1d 6653 value = src[j].weight * zunionInterDictValue(other);
d2764cd6 6654 zunionInterAggregate(score, value, aggregate);
2830ca53
PN
6655 }
6656 }
b287c9bb 6657
2830ca53
PN
6658 robj *o = dictGetEntryKey(de);
6659 dictAdd(dstzset->dict,o,score);
6660 incrRefCount(o); /* added to dictionary */
6661 zslInsert(dstzset->zsl,*score,o);
6662 incrRefCount(o); /* added to skiplist */
6663 }
6664 dictReleaseIterator(di);
b287c9bb 6665 }
2830ca53
PN
6666 } else {
6667 /* unknown operator */
6668 redisAssert(op == REDIS_OP_INTER || op == REDIS_OP_UNION);
b287c9bb
PN
6669 }
6670
09241813 6671 dbDelete(c->db,dstkey);
3ea27d37 6672 if (dstzset->zsl->length) {
09241813 6673 dbAdd(c->db,dstkey,dstobj);
482b672d 6674 addReplyLongLong(c, dstzset->zsl->length);
3ea27d37 6675 server.dirty++;
6676 } else {
8bca8773 6677 decrRefCount(dstobj);
3ea27d37 6678 addReply(c, shared.czero);
6679 }
8f92e768 6680 zfree(src);
b287c9bb
PN
6681}
6682
5d373da9 6683static void zunionstoreCommand(redisClient *c) {
2830ca53 6684 zunionInterGenericCommand(c,c->argv[1], REDIS_OP_UNION);
b287c9bb
PN
6685}
6686
5d373da9 6687static void zinterstoreCommand(redisClient *c) {
2830ca53 6688 zunionInterGenericCommand(c,c->argv[1], REDIS_OP_INTER);
b287c9bb
PN
6689}
6690
e3870fab 6691static void zrangeGenericCommand(redisClient *c, int reverse) {
cc812361 6692 robj *o;
bbe025e0
AM
6693 long start;
6694 long end;
752da584 6695 int withscores = 0;
dd88747b 6696 int llen;
6697 int rangelen, j;
6698 zset *zsetobj;
6699 zskiplist *zsl;
6700 zskiplistNode *ln;
6701 robj *ele;
752da584 6702
bd79a6bd
PN
6703 if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
6704 (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
bbe025e0 6705
752da584 6706 if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) {
6707 withscores = 1;
6708 } else if (c->argc >= 5) {
6709 addReply(c,shared.syntaxerr);
6710 return;
6711 }
cc812361 6712
4e27f268 6713 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
6714 || checkType(c,o,REDIS_ZSET)) return;
dd88747b 6715 zsetobj = o->ptr;
6716 zsl = zsetobj->zsl;
6717 llen = zsl->length;
cc812361 6718
dd88747b 6719 /* convert negative indexes */
6720 if (start < 0) start = llen+start;
6721 if (end < 0) end = llen+end;
6722 if (start < 0) start = 0;
6723 if (end < 0) end = 0;
cc812361 6724
dd88747b 6725 /* indexes sanity checks */
6726 if (start > end || start >= llen) {
6727 /* Out of range start or start > end result in empty list */
6728 addReply(c,shared.emptymultibulk);
6729 return;
6730 }
6731 if (end >= llen) end = llen-1;
6732 rangelen = (end-start)+1;
cc812361 6733
dd88747b 6734 /* check if starting point is trivial, before searching
6735 * the element in log(N) time */
6736 if (reverse) {
003f0840 6737 ln = start == 0 ? zsl->tail : zslistTypeGetElementByRank(zsl, llen-start);
dd88747b 6738 } else {
6739 ln = start == 0 ?
003f0840 6740 zsl->header->forward[0] : zslistTypeGetElementByRank(zsl, start+1);
dd88747b 6741 }
cc812361 6742
dd88747b 6743 /* Return the result in form of a multi-bulk reply */
6744 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",
6745 withscores ? (rangelen*2) : rangelen));
6746 for (j = 0; j < rangelen; j++) {
6747 ele = ln->obj;
6748 addReplyBulk(c,ele);
6749 if (withscores)
6750 addReplyDouble(c,ln->score);
6751 ln = reverse ? ln->backward : ln->forward[0];
cc812361 6752 }
6753}
6754
e3870fab 6755static void zrangeCommand(redisClient *c) {
6756 zrangeGenericCommand(c,0);
6757}
6758
6759static void zrevrangeCommand(redisClient *c) {
6760 zrangeGenericCommand(c,1);
6761}
6762
f44dd428 6763/* This command implements both ZRANGEBYSCORE and ZCOUNT.
6764 * If justcount is non-zero, just the count is returned. */
6765static void genericZrangebyscoreCommand(redisClient *c, int justcount) {
50c55df5 6766 robj *o;
f44dd428 6767 double min, max;
6768 int minex = 0, maxex = 0; /* are min or max exclusive? */
80181f78 6769 int offset = 0, limit = -1;
0500ef27
SH
6770 int withscores = 0;
6771 int badsyntax = 0;
6772
f44dd428 6773 /* Parse the min-max interval. If one of the values is prefixed
6774 * by the "(" character, it's considered "open". For instance
6775 * ZRANGEBYSCORE zset (1.5 (2.5 will match min < x < max
6776 * ZRANGEBYSCORE zset 1.5 2.5 will instead match min <= x <= max */
6777 if (((char*)c->argv[2]->ptr)[0] == '(') {
6778 min = strtod((char*)c->argv[2]->ptr+1,NULL);
6779 minex = 1;
6780 } else {
6781 min = strtod(c->argv[2]->ptr,NULL);
6782 }
6783 if (((char*)c->argv[3]->ptr)[0] == '(') {
6784 max = strtod((char*)c->argv[3]->ptr+1,NULL);
6785 maxex = 1;
6786 } else {
6787 max = strtod(c->argv[3]->ptr,NULL);
6788 }
6789
6790 /* Parse "WITHSCORES": note that if the command was called with
6791 * the name ZCOUNT then we are sure that c->argc == 4, so we'll never
6792 * enter the following paths to parse WITHSCORES and LIMIT. */
0500ef27 6793 if (c->argc == 5 || c->argc == 8) {
3a3978b1 6794 if (strcasecmp(c->argv[c->argc-1]->ptr,"withscores") == 0)
6795 withscores = 1;
6796 else
6797 badsyntax = 1;
0500ef27 6798 }
3a3978b1 6799 if (c->argc != (4 + withscores) && c->argc != (7 + withscores))
0500ef27 6800 badsyntax = 1;
0500ef27 6801 if (badsyntax) {
454d4e43 6802 addReplySds(c,
6803 sdsnew("-ERR wrong number of arguments for ZRANGEBYSCORE\r\n"));
80181f78 6804 return;
0500ef27
SH
6805 }
6806
f44dd428 6807 /* Parse "LIMIT" */
0500ef27 6808 if (c->argc == (7 + withscores) && strcasecmp(c->argv[4]->ptr,"limit")) {
80181f78 6809 addReply(c,shared.syntaxerr);
6810 return;
0500ef27 6811 } else if (c->argc == (7 + withscores)) {
80181f78 6812 offset = atoi(c->argv[5]->ptr);
6813 limit = atoi(c->argv[6]->ptr);
0b13687c 6814 if (offset < 0) offset = 0;
80181f78 6815 }
50c55df5 6816
f44dd428 6817 /* Ok, lookup the key and get the range */
50c55df5 6818 o = lookupKeyRead(c->db,c->argv[1]);
6819 if (o == NULL) {
4e27f268 6820 addReply(c,justcount ? shared.czero : shared.emptymultibulk);
50c55df5 6821 } else {
6822 if (o->type != REDIS_ZSET) {
6823 addReply(c,shared.wrongtypeerr);
6824 } else {
6825 zset *zsetobj = o->ptr;
6826 zskiplist *zsl = zsetobj->zsl;
6827 zskiplistNode *ln;
f44dd428 6828 robj *ele, *lenobj = NULL;
6829 unsigned long rangelen = 0;
50c55df5 6830
f44dd428 6831 /* Get the first node with the score >= min, or with
6832 * score > min if 'minex' is true. */
50c55df5 6833 ln = zslFirstWithScore(zsl,min);
f44dd428 6834 while (minex && ln && ln->score == min) ln = ln->forward[0];
6835
50c55df5 6836 if (ln == NULL) {
6837 /* No element matching the speciifed interval */
f44dd428 6838 addReply(c,justcount ? shared.czero : shared.emptymultibulk);
50c55df5 6839 return;
6840 }
6841
6842 /* We don't know in advance how many matching elements there
6843 * are in the list, so we push this object that will represent
6844 * the multi-bulk length in the output buffer, and will "fix"
6845 * it later */
f44dd428 6846 if (!justcount) {
6847 lenobj = createObject(REDIS_STRING,NULL);
6848 addReply(c,lenobj);
6849 decrRefCount(lenobj);
6850 }
50c55df5 6851
f44dd428 6852 while(ln && (maxex ? (ln->score < max) : (ln->score <= max))) {
80181f78 6853 if (offset) {
6854 offset--;
6855 ln = ln->forward[0];
6856 continue;
6857 }
6858 if (limit == 0) break;
f44dd428 6859 if (!justcount) {
6860 ele = ln->obj;
dd88747b 6861 addReplyBulk(c,ele);
f44dd428 6862 if (withscores)
6863 addReplyDouble(c,ln->score);
6864 }
50c55df5 6865 ln = ln->forward[0];
6866 rangelen++;
80181f78 6867 if (limit > 0) limit--;
50c55df5 6868 }
f44dd428 6869 if (justcount) {
482b672d 6870 addReplyLongLong(c,(long)rangelen);
f44dd428 6871 } else {
6872 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",
6873 withscores ? (rangelen*2) : rangelen);
6874 }
50c55df5 6875 }
6876 }
6877}
6878
f44dd428 6879static void zrangebyscoreCommand(redisClient *c) {
6880 genericZrangebyscoreCommand(c,0);
6881}
6882
6883static void zcountCommand(redisClient *c) {
6884 genericZrangebyscoreCommand(c,1);
6885}
6886
3c41331e 6887static void zcardCommand(redisClient *c) {
e197b441 6888 robj *o;
6889 zset *zs;
dd88747b 6890
6891 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
6892 checkType(c,o,REDIS_ZSET)) return;
6893
6894 zs = o->ptr;
6895 addReplyUlong(c,zs->zsl->length);
e197b441 6896}
6897
6e333bbe 6898static void zscoreCommand(redisClient *c) {
6899 robj *o;
6900 zset *zs;
dd88747b 6901 dictEntry *de;
6902
6903 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
6904 checkType(c,o,REDIS_ZSET)) return;
6905
6906 zs = o->ptr;
6907 de = dictFind(zs->dict,c->argv[2]);
6908 if (!de) {
96d8b4ee 6909 addReply(c,shared.nullbulk);
6e333bbe 6910 } else {
dd88747b 6911 double *score = dictGetEntryVal(de);
6e333bbe 6912
dd88747b 6913 addReplyDouble(c,*score);
6e333bbe 6914 }
6915}
6916
798d9e55 6917static void zrankGenericCommand(redisClient *c, int reverse) {
69d95c3e 6918 robj *o;
dd88747b 6919 zset *zs;
6920 zskiplist *zsl;
6921 dictEntry *de;
6922 unsigned long rank;
6923 double *score;
6924
6925 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
6926 checkType(c,o,REDIS_ZSET)) return;
6927
6928 zs = o->ptr;
6929 zsl = zs->zsl;
6930 de = dictFind(zs->dict,c->argv[2]);
6931 if (!de) {
69d95c3e
PN
6932 addReply(c,shared.nullbulk);
6933 return;
6934 }
69d95c3e 6935
dd88747b 6936 score = dictGetEntryVal(de);
003f0840 6937 rank = zslistTypeGetRank(zsl, *score, c->argv[2]);
dd88747b 6938 if (rank) {
6939 if (reverse) {
482b672d 6940 addReplyLongLong(c, zsl->length - rank);
27b0ccca 6941 } else {
482b672d 6942 addReplyLongLong(c, rank-1);
69d95c3e 6943 }
dd88747b 6944 } else {
6945 addReply(c,shared.nullbulk);
978c2c94 6946 }
6947}
6948
798d9e55
PN
6949static void zrankCommand(redisClient *c) {
6950 zrankGenericCommand(c, 0);
6951}
6952
6953static void zrevrankCommand(redisClient *c) {
6954 zrankGenericCommand(c, 1);
6955}
6956
7fb16bac
PN
6957/* ========================= Hashes utility functions ======================= */
6958#define REDIS_HASH_KEY 1
6959#define REDIS_HASH_VALUE 2
978c2c94 6960
7fb16bac
PN
6961/* Check the length of a number of objects to see if we need to convert a
6962 * zipmap to a real hash. Note that we only check string encoded objects
6963 * as their string length can be queried in constant time. */
d1578a33 6964static void hashTypeTryConversion(robj *subject, robj **argv, int start, int end) {
7fb16bac
PN
6965 int i;
6966 if (subject->encoding != REDIS_ENCODING_ZIPMAP) return;
978c2c94 6967
7fb16bac
PN
6968 for (i = start; i <= end; i++) {
6969 if (argv[i]->encoding == REDIS_ENCODING_RAW &&
6970 sdslen(argv[i]->ptr) > server.hash_max_zipmap_value)
6971 {
6972 convertToRealHash(subject);
978c2c94 6973 return;
6974 }
6975 }
7fb16bac 6976}
bae2c7ec 6977
97224de7 6978/* Encode given objects in-place when the hash uses a dict. */
d1578a33 6979static void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2) {
97224de7 6980 if (subject->encoding == REDIS_ENCODING_HT) {
3f973463
PN
6981 if (o1) *o1 = tryObjectEncoding(*o1);
6982 if (o2) *o2 = tryObjectEncoding(*o2);
97224de7
PN
6983 }
6984}
6985
7fb16bac 6986/* Get the value from a hash identified by key. Returns either a string
a3f3af86
PN
6987 * object or NULL if the value cannot be found. The refcount of the object
6988 * is always increased by 1 when the value was found. */
d1578a33 6989static robj *hashTypeGet(robj *o, robj *key) {
7fb16bac 6990 robj *value = NULL;
978c2c94 6991 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
7fb16bac
PN
6992 unsigned char *v;
6993 unsigned int vlen;
6994 key = getDecodedObject(key);
6995 if (zipmapGet(o->ptr,key->ptr,sdslen(key->ptr),&v,&vlen)) {
6996 value = createStringObject((char*)v,vlen);
6997 }
6998 decrRefCount(key);
6999 } else {
7000 dictEntry *de = dictFind(o->ptr,key);
7001 if (de != NULL) {
7002 value = dictGetEntryVal(de);
a3f3af86 7003 incrRefCount(value);
7fb16bac
PN
7004 }
7005 }
7006 return value;
7007}
978c2c94 7008
7fb16bac
PN
7009/* Test if the key exists in the given hash. Returns 1 if the key
7010 * exists and 0 when it doesn't. */
d1578a33 7011static int hashTypeExists(robj *o, robj *key) {
7fb16bac
PN
7012 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
7013 key = getDecodedObject(key);
7014 if (zipmapExists(o->ptr,key->ptr,sdslen(key->ptr))) {
7015 decrRefCount(key);
7016 return 1;
7017 }
7018 decrRefCount(key);
7019 } else {
7020 if (dictFind(o->ptr,key) != NULL) {
7021 return 1;
7022 }
7023 }
7024 return 0;
7025}
bae2c7ec 7026
7fb16bac
PN
7027/* Add an element, discard the old if the key already exists.
7028 * Return 0 on insert and 1 on update. */
d1578a33 7029static int hashTypeSet(robj *o, robj *key, robj *value) {
7fb16bac
PN
7030 int update = 0;
7031 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
7032 key = getDecodedObject(key);
7033 value = getDecodedObject(value);
7034 o->ptr = zipmapSet(o->ptr,
7035 key->ptr,sdslen(key->ptr),
7036 value->ptr,sdslen(value->ptr), &update);
7037 decrRefCount(key);
7038 decrRefCount(value);
7039
7040 /* Check if the zipmap needs to be upgraded to a real hash table */
7041 if (zipmapLen(o->ptr) > server.hash_max_zipmap_entries)
bae2c7ec 7042 convertToRealHash(o);
978c2c94 7043 } else {
7fb16bac
PN
7044 if (dictReplace(o->ptr,key,value)) {
7045 /* Insert */
7046 incrRefCount(key);
978c2c94 7047 } else {
7fb16bac 7048 /* Update */
978c2c94 7049 update = 1;
7050 }
7fb16bac 7051 incrRefCount(value);
978c2c94 7052 }
7fb16bac 7053 return update;
978c2c94 7054}
7055
7fb16bac
PN
7056/* Delete an element from a hash.
7057 * Return 1 on deleted and 0 on not found. */
d1578a33 7058static int hashTypeDelete(robj *o, robj *key) {
7fb16bac
PN
7059 int deleted = 0;
7060 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
7061 key = getDecodedObject(key);
7062 o->ptr = zipmapDel(o->ptr,key->ptr,sdslen(key->ptr), &deleted);
7063 decrRefCount(key);
7064 } else {
7065 deleted = dictDelete((dict*)o->ptr,key) == DICT_OK;
7066 /* Always check if the dictionary needs a resize after a delete. */
7067 if (deleted && htNeedsResize(o->ptr)) dictResize(o->ptr);
d33278d1 7068 }
7fb16bac
PN
7069 return deleted;
7070}
d33278d1 7071
7fb16bac 7072/* Return the number of elements in a hash. */
d1578a33 7073static unsigned long hashTypeLength(robj *o) {
7fb16bac
PN
7074 return (o->encoding == REDIS_ENCODING_ZIPMAP) ?
7075 zipmapLen((unsigned char*)o->ptr) : dictSize((dict*)o->ptr);
7076}
7077
7078/* Structure to hold hash iteration abstration. Note that iteration over
7079 * hashes involves both fields and values. Because it is possible that
7080 * not both are required, store pointers in the iterator to avoid
7081 * unnecessary memory allocation for fields/values. */
7082typedef struct {
7083 int encoding;
7084 unsigned char *zi;
7085 unsigned char *zk, *zv;
7086 unsigned int zklen, zvlen;
7087
7088 dictIterator *di;
7089 dictEntry *de;
d1578a33 7090} hashTypeIterator;
7fb16bac 7091
d1578a33
PN
7092static hashTypeIterator *hashTypeInitIterator(robj *subject) {
7093 hashTypeIterator *hi = zmalloc(sizeof(hashTypeIterator));
7fb16bac
PN
7094 hi->encoding = subject->encoding;
7095 if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
7096 hi->zi = zipmapRewind(subject->ptr);
7097 } else if (hi->encoding == REDIS_ENCODING_HT) {
7098 hi->di = dictGetIterator(subject->ptr);
d33278d1 7099 } else {
7fb16bac 7100 redisAssert(NULL);
d33278d1 7101 }
c44d3b56 7102 return hi;
7fb16bac 7103}
d33278d1 7104
d1578a33 7105static void hashTypeReleaseIterator(hashTypeIterator *hi) {
7fb16bac
PN
7106 if (hi->encoding == REDIS_ENCODING_HT) {
7107 dictReleaseIterator(hi->di);
d33278d1 7108 }
c44d3b56 7109 zfree(hi);
7fb16bac 7110}
d33278d1 7111
7fb16bac
PN
7112/* Move to the next entry in the hash. Return REDIS_OK when the next entry
7113 * could be found and REDIS_ERR when the iterator reaches the end. */
d1578a33 7114static int hashTypeNext(hashTypeIterator *hi) {
7fb16bac
PN
7115 if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
7116 if ((hi->zi = zipmapNext(hi->zi, &hi->zk, &hi->zklen,
7117 &hi->zv, &hi->zvlen)) == NULL) return REDIS_ERR;
7118 } else {
7119 if ((hi->de = dictNext(hi->di)) == NULL) return REDIS_ERR;
7120 }
7121 return REDIS_OK;
7122}
d33278d1 7123
0c390abc 7124/* Get key or value object at current iteration position.
a3f3af86 7125 * This increases the refcount of the field object by 1. */
d1578a33 7126static robj *hashTypeCurrent(hashTypeIterator *hi, int what) {
7fb16bac
PN
7127 robj *o;
7128 if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
7129 if (what & REDIS_HASH_KEY) {
7130 o = createStringObject((char*)hi->zk,hi->zklen);
7131 } else {
7132 o = createStringObject((char*)hi->zv,hi->zvlen);
d33278d1 7133 }
d33278d1 7134 } else {
7fb16bac
PN
7135 if (what & REDIS_HASH_KEY) {
7136 o = dictGetEntryKey(hi->de);
7137 } else {
7138 o = dictGetEntryVal(hi->de);
d33278d1 7139 }
a3f3af86 7140 incrRefCount(o);
d33278d1 7141 }
7fb16bac 7142 return o;
d33278d1
PN
7143}
7144
d1578a33 7145static robj *hashTypeLookupWriteOrCreate(redisClient *c, robj *key) {
7fb16bac 7146 robj *o = lookupKeyWrite(c->db,key);
01426b05
PN
7147 if (o == NULL) {
7148 o = createHashObject();
09241813 7149 dbAdd(c->db,key,o);
01426b05
PN
7150 } else {
7151 if (o->type != REDIS_HASH) {
7152 addReply(c,shared.wrongtypeerr);
7fb16bac 7153 return NULL;
01426b05
PN
7154 }
7155 }
7fb16bac
PN
7156 return o;
7157}
01426b05 7158
7fb16bac
PN
7159/* ============================= Hash commands ============================== */
7160static void hsetCommand(redisClient *c) {
6e9e463f 7161 int update;
7fb16bac 7162 robj *o;
bbe025e0 7163
d1578a33
PN
7164 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7165 hashTypeTryConversion(o,c->argv,2,3);
7166 hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);
7167 update = hashTypeSet(o,c->argv[2],c->argv[3]);
6e9e463f 7168 addReply(c, update ? shared.czero : shared.cone);
7fb16bac
PN
7169 server.dirty++;
7170}
01426b05 7171
1f1c7695
PN
7172static void hsetnxCommand(redisClient *c) {
7173 robj *o;
d1578a33
PN
7174 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7175 hashTypeTryConversion(o,c->argv,2,3);
1f1c7695 7176
d1578a33 7177 if (hashTypeExists(o, c->argv[2])) {
1f1c7695 7178 addReply(c, shared.czero);
01426b05 7179 } else {
d1578a33
PN
7180 hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);
7181 hashTypeSet(o,c->argv[2],c->argv[3]);
1f1c7695
PN
7182 addReply(c, shared.cone);
7183 server.dirty++;
7184 }
7185}
01426b05 7186
7fb16bac
PN
7187static void hmsetCommand(redisClient *c) {
7188 int i;
7189 robj *o;
01426b05 7190
7fb16bac
PN
7191 if ((c->argc % 2) == 1) {
7192 addReplySds(c,sdsnew("-ERR wrong number of arguments for HMSET\r\n"));
7193 return;
7194 }
01426b05 7195
d1578a33
PN
7196 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7197 hashTypeTryConversion(o,c->argv,2,c->argc-1);
7fb16bac 7198 for (i = 2; i < c->argc; i += 2) {
d1578a33
PN
7199 hashTypeTryObjectEncoding(o,&c->argv[i], &c->argv[i+1]);
7200 hashTypeSet(o,c->argv[i],c->argv[i+1]);
7fb16bac
PN
7201 }
7202 addReply(c, shared.ok);
edc2f63a 7203 server.dirty++;
7fb16bac
PN
7204}
7205
7206static void hincrbyCommand(redisClient *c) {
7207 long long value, incr;
7208 robj *o, *current, *new;
7209
bd79a6bd 7210 if (getLongLongFromObjectOrReply(c,c->argv[3],&incr,NULL) != REDIS_OK) return;
d1578a33
PN
7211 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7212 if ((current = hashTypeGet(o,c->argv[2])) != NULL) {
946342c1
PN
7213 if (getLongLongFromObjectOrReply(c,current,&value,
7214 "hash value is not an integer") != REDIS_OK) {
7215 decrRefCount(current);
7216 return;
7217 }
a3f3af86 7218 decrRefCount(current);
7fb16bac
PN
7219 } else {
7220 value = 0;
01426b05
PN
7221 }
7222
7fb16bac 7223 value += incr;
3f973463 7224 new = createStringObjectFromLongLong(value);
d1578a33
PN
7225 hashTypeTryObjectEncoding(o,&c->argv[2],NULL);
7226 hashTypeSet(o,c->argv[2],new);
7fb16bac
PN
7227 decrRefCount(new);
7228 addReplyLongLong(c,value);
01426b05 7229 server.dirty++;
01426b05
PN
7230}
7231
978c2c94 7232static void hgetCommand(redisClient *c) {
7fb16bac 7233 robj *o, *value;
dd88747b 7234 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
7235 checkType(c,o,REDIS_HASH)) return;
7236
d1578a33 7237 if ((value = hashTypeGet(o,c->argv[2])) != NULL) {
7fb16bac 7238 addReplyBulk(c,value);
a3f3af86 7239 decrRefCount(value);
dd88747b 7240 } else {
7fb16bac 7241 addReply(c,shared.nullbulk);
69d95c3e 7242 }
69d95c3e
PN
7243}
7244
09aeb579
PN
7245static void hmgetCommand(redisClient *c) {
7246 int i;
7fb16bac
PN
7247 robj *o, *value;
7248 o = lookupKeyRead(c->db,c->argv[1]);
7249 if (o != NULL && o->type != REDIS_HASH) {
7250 addReply(c,shared.wrongtypeerr);
09aeb579
PN
7251 }
7252
7fb16bac
PN
7253 /* Note the check for o != NULL happens inside the loop. This is
7254 * done because objects that cannot be found are considered to be
7255 * an empty hash. The reply should then be a series of NULLs. */
09aeb579 7256 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-2));
7fb16bac 7257 for (i = 2; i < c->argc; i++) {
d1578a33 7258 if (o != NULL && (value = hashTypeGet(o,c->argv[i])) != NULL) {
7fb16bac 7259 addReplyBulk(c,value);
a3f3af86 7260 decrRefCount(value);
7fb16bac
PN
7261 } else {
7262 addReply(c,shared.nullbulk);
09aeb579
PN
7263 }
7264 }
7265}
7266
07efaf74 7267static void hdelCommand(redisClient *c) {
dd88747b 7268 robj *o;
dd88747b 7269 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
7270 checkType(c,o,REDIS_HASH)) return;
07efaf74 7271
d1578a33
PN
7272 if (hashTypeDelete(o,c->argv[2])) {
7273 if (hashTypeLength(o) == 0) dbDelete(c->db,c->argv[1]);
7fb16bac
PN
7274 addReply(c,shared.cone);
7275 server.dirty++;
dd88747b 7276 } else {
7fb16bac 7277 addReply(c,shared.czero);
07efaf74 7278 }
7279}
7280
92b27fe9 7281static void hlenCommand(redisClient *c) {
7282 robj *o;
dd88747b 7283 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
92b27fe9 7284 checkType(c,o,REDIS_HASH)) return;
7285
d1578a33 7286 addReplyUlong(c,hashTypeLength(o));
92b27fe9 7287}
7288
78409a0f 7289static void genericHgetallCommand(redisClient *c, int flags) {
7fb16bac 7290 robj *o, *lenobj, *obj;
78409a0f 7291 unsigned long count = 0;
d1578a33 7292 hashTypeIterator *hi;
78409a0f 7293
4e27f268 7294 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
78409a0f 7295 || checkType(c,o,REDIS_HASH)) return;
7296
7297 lenobj = createObject(REDIS_STRING,NULL);
7298 addReply(c,lenobj);
7299 decrRefCount(lenobj);
7300
d1578a33
PN
7301 hi = hashTypeInitIterator(o);
7302 while (hashTypeNext(hi) != REDIS_ERR) {
7fb16bac 7303 if (flags & REDIS_HASH_KEY) {
d1578a33 7304 obj = hashTypeCurrent(hi,REDIS_HASH_KEY);
7fb16bac 7305 addReplyBulk(c,obj);
a3f3af86 7306 decrRefCount(obj);
7fb16bac 7307 count++;
78409a0f 7308 }
7fb16bac 7309 if (flags & REDIS_HASH_VALUE) {
d1578a33 7310 obj = hashTypeCurrent(hi,REDIS_HASH_VALUE);
7fb16bac 7311 addReplyBulk(c,obj);
a3f3af86 7312 decrRefCount(obj);
7fb16bac 7313 count++;
78409a0f 7314 }
78409a0f 7315 }
d1578a33 7316 hashTypeReleaseIterator(hi);
7fb16bac 7317
78409a0f 7318 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",count);
7319}
7320
7321static void hkeysCommand(redisClient *c) {
7fb16bac 7322 genericHgetallCommand(c,REDIS_HASH_KEY);
78409a0f 7323}
7324
7325static void hvalsCommand(redisClient *c) {
7fb16bac 7326 genericHgetallCommand(c,REDIS_HASH_VALUE);
78409a0f 7327}
7328
7329static void hgetallCommand(redisClient *c) {
7fb16bac 7330 genericHgetallCommand(c,REDIS_HASH_KEY|REDIS_HASH_VALUE);
78409a0f 7331}
7332
a86f14b1 7333static void hexistsCommand(redisClient *c) {
7334 robj *o;
a86f14b1 7335 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
7336 checkType(c,o,REDIS_HASH)) return;
7337
d1578a33 7338 addReply(c, hashTypeExists(o,c->argv[2]) ? shared.cone : shared.czero);
a86f14b1 7339}
7340
ada386b2 7341static void convertToRealHash(robj *o) {
7342 unsigned char *key, *val, *p, *zm = o->ptr;
7343 unsigned int klen, vlen;
7344 dict *dict = dictCreate(&hashDictType,NULL);
7345
7346 assert(o->type == REDIS_HASH && o->encoding != REDIS_ENCODING_HT);
7347 p = zipmapRewind(zm);
7348 while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
7349 robj *keyobj, *valobj;
7350
7351 keyobj = createStringObject((char*)key,klen);
7352 valobj = createStringObject((char*)val,vlen);
05df7621 7353 keyobj = tryObjectEncoding(keyobj);
7354 valobj = tryObjectEncoding(valobj);
ada386b2 7355 dictAdd(dict,keyobj,valobj);
7356 }
7357 o->encoding = REDIS_ENCODING_HT;
7358 o->ptr = dict;
7359 zfree(zm);
7360}
7361
6b47e12e 7362/* ========================= Non type-specific commands ==================== */
7363
ed9b544e 7364static void flushdbCommand(redisClient *c) {
ca37e9cd 7365 server.dirty += dictSize(c->db->dict);
9b30e1a2 7366 touchWatchedKeysOnFlush(c->db->id);
3305306f 7367 dictEmpty(c->db->dict);
7368 dictEmpty(c->db->expires);
ed9b544e 7369 addReply(c,shared.ok);
ed9b544e 7370}
7371
7372static void flushallCommand(redisClient *c) {
9b30e1a2 7373 touchWatchedKeysOnFlush(-1);
ca37e9cd 7374 server.dirty += emptyDb();
ed9b544e 7375 addReply(c,shared.ok);
500ece7c 7376 if (server.bgsavechildpid != -1) {
7377 kill(server.bgsavechildpid,SIGKILL);
7378 rdbRemoveTempFile(server.bgsavechildpid);
7379 }
f78fd11b 7380 rdbSave(server.dbfilename);
ca37e9cd 7381 server.dirty++;
ed9b544e 7382}
7383
56906eef 7384static redisSortOperation *createSortOperation(int type, robj *pattern) {
ed9b544e 7385 redisSortOperation *so = zmalloc(sizeof(*so));
ed9b544e 7386 so->type = type;
7387 so->pattern = pattern;
7388 return so;
7389}
7390
7391/* Return the value associated to the key with a name obtained
55017f9d
PN
7392 * substituting the first occurence of '*' in 'pattern' with 'subst'.
7393 * The returned object will always have its refcount increased by 1
7394 * when it is non-NULL. */
56906eef 7395static robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
6d7d1370 7396 char *p, *f;
ed9b544e 7397 sds spat, ssub;
6d7d1370
PN
7398 robj keyobj, fieldobj, *o;
7399 int prefixlen, sublen, postfixlen, fieldlen;
ed9b544e 7400 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
7401 struct {
f1017b3f 7402 long len;
7403 long free;
ed9b544e 7404 char buf[REDIS_SORTKEY_MAX+1];
6d7d1370 7405 } keyname, fieldname;
ed9b544e 7406
28173a49 7407 /* If the pattern is "#" return the substitution object itself in order
7408 * to implement the "SORT ... GET #" feature. */
7409 spat = pattern->ptr;
7410 if (spat[0] == '#' && spat[1] == '\0') {
55017f9d 7411 incrRefCount(subst);
28173a49 7412 return subst;
7413 }
7414
7415 /* The substitution object may be specially encoded. If so we create
9d65a1bb 7416 * a decoded object on the fly. Otherwise getDecodedObject will just
7417 * increment the ref count, that we'll decrement later. */
7418 subst = getDecodedObject(subst);
942a3961 7419
ed9b544e 7420 ssub = subst->ptr;
7421 if (sdslen(spat)+sdslen(ssub)-1 > REDIS_SORTKEY_MAX) return NULL;
7422 p = strchr(spat,'*');
ed5a857a 7423 if (!p) {
7424 decrRefCount(subst);
7425 return NULL;
7426 }
ed9b544e 7427
6d7d1370
PN
7428 /* Find out if we're dealing with a hash dereference. */
7429 if ((f = strstr(p+1, "->")) != NULL) {
7430 fieldlen = sdslen(spat)-(f-spat);
7431 /* this also copies \0 character */
7432 memcpy(fieldname.buf,f+2,fieldlen-1);
7433 fieldname.len = fieldlen-2;
7434 } else {
7435 fieldlen = 0;
7436 }
7437
ed9b544e 7438 prefixlen = p-spat;
7439 sublen = sdslen(ssub);
6d7d1370 7440 postfixlen = sdslen(spat)-(prefixlen+1)-fieldlen;
ed9b544e 7441 memcpy(keyname.buf,spat,prefixlen);
7442 memcpy(keyname.buf+prefixlen,ssub,sublen);
7443 memcpy(keyname.buf+prefixlen+sublen,p+1,postfixlen);
7444 keyname.buf[prefixlen+sublen+postfixlen] = '\0';
7445 keyname.len = prefixlen+sublen+postfixlen;
942a3961 7446 decrRefCount(subst);
7447
6d7d1370
PN
7448 /* Lookup substituted key */
7449 initStaticStringObject(keyobj,((char*)&keyname)+(sizeof(long)*2));
7450 o = lookupKeyRead(db,&keyobj);
55017f9d
PN
7451 if (o == NULL) return NULL;
7452
7453 if (fieldlen > 0) {
7454 if (o->type != REDIS_HASH || fieldname.len < 1) return NULL;
6d7d1370 7455
705dad38
PN
7456 /* Retrieve value from hash by the field name. This operation
7457 * already increases the refcount of the returned object. */
6d7d1370 7458 initStaticStringObject(fieldobj,((char*)&fieldname)+(sizeof(long)*2));
d1578a33 7459 o = hashTypeGet(o, &fieldobj);
705dad38 7460 } else {
55017f9d 7461 if (o->type != REDIS_STRING) return NULL;
b6f07345 7462
705dad38
PN
7463 /* Every object that this function returns needs to have its refcount
7464 * increased. sortCommand decreases it again. */
7465 incrRefCount(o);
6d7d1370
PN
7466 }
7467
7468 return o;
ed9b544e 7469}
7470
7471/* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
7472 * the additional parameter is not standard but a BSD-specific we have to
7473 * pass sorting parameters via the global 'server' structure */
7474static int sortCompare(const void *s1, const void *s2) {
7475 const redisSortObject *so1 = s1, *so2 = s2;
7476 int cmp;
7477
7478 if (!server.sort_alpha) {
7479 /* Numeric sorting. Here it's trivial as we precomputed scores */
7480 if (so1->u.score > so2->u.score) {
7481 cmp = 1;
7482 } else if (so1->u.score < so2->u.score) {
7483 cmp = -1;
7484 } else {
7485 cmp = 0;
7486 }
7487 } else {
7488 /* Alphanumeric sorting */
7489 if (server.sort_bypattern) {
7490 if (!so1->u.cmpobj || !so2->u.cmpobj) {
7491 /* At least one compare object is NULL */
7492 if (so1->u.cmpobj == so2->u.cmpobj)
7493 cmp = 0;
7494 else if (so1->u.cmpobj == NULL)
7495 cmp = -1;
7496 else
7497 cmp = 1;
7498 } else {
7499 /* We have both the objects, use strcoll */
7500 cmp = strcoll(so1->u.cmpobj->ptr,so2->u.cmpobj->ptr);
7501 }
7502 } else {
08ee9b57 7503 /* Compare elements directly. */
7504 cmp = compareStringObjects(so1->obj,so2->obj);
ed9b544e 7505 }
7506 }
7507 return server.sort_desc ? -cmp : cmp;
7508}
7509
7510/* The SORT command is the most complex command in Redis. Warning: this code
7511 * is optimized for speed and a bit less for readability */
7512static void sortCommand(redisClient *c) {
ed9b544e 7513 list *operations;
a03611e1 7514 unsigned int outputlen = 0;
ed9b544e 7515 int desc = 0, alpha = 0;
7516 int limit_start = 0, limit_count = -1, start, end;
7517 int j, dontsort = 0, vectorlen;
7518 int getop = 0; /* GET operation counter */
443c6409 7519 robj *sortval, *sortby = NULL, *storekey = NULL;
ed9b544e 7520 redisSortObject *vector; /* Resulting vector to sort */
7521
7522 /* Lookup the key to sort. It must be of the right types */
3305306f 7523 sortval = lookupKeyRead(c->db,c->argv[1]);
7524 if (sortval == NULL) {
4e27f268 7525 addReply(c,shared.emptymultibulk);
ed9b544e 7526 return;
7527 }
a5eb649b 7528 if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST &&
7529 sortval->type != REDIS_ZSET)
7530 {
c937aa89 7531 addReply(c,shared.wrongtypeerr);
ed9b544e 7532 return;
7533 }
7534
7535 /* Create a list of operations to perform for every sorted element.
7536 * Operations can be GET/DEL/INCR/DECR */
7537 operations = listCreate();
092dac2a 7538 listSetFreeMethod(operations,zfree);
ed9b544e 7539 j = 2;
7540
7541 /* Now we need to protect sortval incrementing its count, in the future
7542 * SORT may have options able to overwrite/delete keys during the sorting
7543 * and the sorted key itself may get destroied */
7544 incrRefCount(sortval);
7545
7546 /* The SORT command has an SQL-alike syntax, parse it */
7547 while(j < c->argc) {
7548 int leftargs = c->argc-j-1;
7549 if (!strcasecmp(c->argv[j]->ptr,"asc")) {
7550 desc = 0;
7551 } else if (!strcasecmp(c->argv[j]->ptr,"desc")) {
7552 desc = 1;
7553 } else if (!strcasecmp(c->argv[j]->ptr,"alpha")) {
7554 alpha = 1;
7555 } else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) {
7556 limit_start = atoi(c->argv[j+1]->ptr);
7557 limit_count = atoi(c->argv[j+2]->ptr);
7558 j+=2;
443c6409 7559 } else if (!strcasecmp(c->argv[j]->ptr,"store") && leftargs >= 1) {
7560 storekey = c->argv[j+1];
7561 j++;
ed9b544e 7562 } else if (!strcasecmp(c->argv[j]->ptr,"by") && leftargs >= 1) {
7563 sortby = c->argv[j+1];
7564 /* If the BY pattern does not contain '*', i.e. it is constant,
7565 * we don't need to sort nor to lookup the weight keys. */
7566 if (strchr(c->argv[j+1]->ptr,'*') == NULL) dontsort = 1;
7567 j++;
7568 } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
7569 listAddNodeTail(operations,createSortOperation(
7570 REDIS_SORT_GET,c->argv[j+1]));
7571 getop++;
7572 j++;
ed9b544e 7573 } else {
7574 decrRefCount(sortval);
7575 listRelease(operations);
c937aa89 7576 addReply(c,shared.syntaxerr);
ed9b544e 7577 return;
7578 }
7579 j++;
7580 }
7581
7582 /* Load the sorting vector with all the objects to sort */
a5eb649b 7583 switch(sortval->type) {
003f0840 7584 case REDIS_LIST: vectorlen = listTypeLength(sortval); break;
a5eb649b 7585 case REDIS_SET: vectorlen = dictSize((dict*)sortval->ptr); break;
7586 case REDIS_ZSET: vectorlen = dictSize(((zset*)sortval->ptr)->dict); break;
f83c6cb5 7587 default: vectorlen = 0; redisPanic("Bad SORT type"); /* Avoid GCC warning */
a5eb649b 7588 }
ed9b544e 7589 vector = zmalloc(sizeof(redisSortObject)*vectorlen);
ed9b544e 7590 j = 0;
a5eb649b 7591
ed9b544e 7592 if (sortval->type == REDIS_LIST) {
003f0840
PN
7593 listTypeIterator *li = listTypeInitIterator(sortval,0,REDIS_TAIL);
7594 listTypeEntry entry;
7595 while(listTypeNext(li,&entry)) {
7596 vector[j].obj = listTypeGet(&entry);
ed9b544e 7597 vector[j].u.score = 0;
7598 vector[j].u.cmpobj = NULL;
ed9b544e 7599 j++;
7600 }
003f0840 7601 listTypeReleaseIterator(li);
ed9b544e 7602 } else {
a5eb649b 7603 dict *set;
ed9b544e 7604 dictIterator *di;
7605 dictEntry *setele;
7606
a5eb649b 7607 if (sortval->type == REDIS_SET) {
7608 set = sortval->ptr;
7609 } else {
7610 zset *zs = sortval->ptr;
7611 set = zs->dict;
7612 }
7613
ed9b544e 7614 di = dictGetIterator(set);
ed9b544e 7615 while((setele = dictNext(di)) != NULL) {
7616 vector[j].obj = dictGetEntryKey(setele);
7617 vector[j].u.score = 0;
7618 vector[j].u.cmpobj = NULL;
7619 j++;
7620 }
7621 dictReleaseIterator(di);
7622 }
dfc5e96c 7623 redisAssert(j == vectorlen);
ed9b544e 7624
7625 /* Now it's time to load the right scores in the sorting vector */
7626 if (dontsort == 0) {
7627 for (j = 0; j < vectorlen; j++) {
6d7d1370 7628 robj *byval;
ed9b544e 7629 if (sortby) {
6d7d1370 7630 /* lookup value to sort by */
3305306f 7631 byval = lookupKeyByPattern(c->db,sortby,vector[j].obj);
705dad38 7632 if (!byval) continue;
ed9b544e 7633 } else {
6d7d1370
PN
7634 /* use object itself to sort by */
7635 byval = vector[j].obj;
7636 }
7637
7638 if (alpha) {
08ee9b57 7639 if (sortby) vector[j].u.cmpobj = getDecodedObject(byval);
6d7d1370
PN
7640 } else {
7641 if (byval->encoding == REDIS_ENCODING_RAW) {
7642 vector[j].u.score = strtod(byval->ptr,NULL);
16fa22f1 7643 } else if (byval->encoding == REDIS_ENCODING_INT) {
6d7d1370
PN
7644 /* Don't need to decode the object if it's
7645 * integer-encoded (the only encoding supported) so
7646 * far. We can just cast it */
16fa22f1
PN
7647 vector[j].u.score = (long)byval->ptr;
7648 } else {
7649 redisAssert(1 != 1);
942a3961 7650 }
ed9b544e 7651 }
6d7d1370 7652
705dad38
PN
7653 /* when the object was retrieved using lookupKeyByPattern,
7654 * its refcount needs to be decreased. */
7655 if (sortby) {
7656 decrRefCount(byval);
ed9b544e 7657 }
7658 }
7659 }
7660
7661 /* We are ready to sort the vector... perform a bit of sanity check
7662 * on the LIMIT option too. We'll use a partial version of quicksort. */
7663 start = (limit_start < 0) ? 0 : limit_start;
7664 end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1;
7665 if (start >= vectorlen) {
7666 start = vectorlen-1;
7667 end = vectorlen-2;
7668 }
7669 if (end >= vectorlen) end = vectorlen-1;
7670
7671 if (dontsort == 0) {
7672 server.sort_desc = desc;
7673 server.sort_alpha = alpha;
7674 server.sort_bypattern = sortby ? 1 : 0;
5f5b9840 7675 if (sortby && (start != 0 || end != vectorlen-1))
7676 pqsort(vector,vectorlen,sizeof(redisSortObject),sortCompare, start,end);
7677 else
7678 qsort(vector,vectorlen,sizeof(redisSortObject),sortCompare);
ed9b544e 7679 }
7680
7681 /* Send command output to the output buffer, performing the specified
7682 * GET/DEL/INCR/DECR operations if any. */
7683 outputlen = getop ? getop*(end-start+1) : end-start+1;
443c6409 7684 if (storekey == NULL) {
7685 /* STORE option not specified, sent the sorting result to client */
7686 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",outputlen));
7687 for (j = start; j <= end; j++) {
7688 listNode *ln;
c7df85a4 7689 listIter li;
7690
dd88747b 7691 if (!getop) addReplyBulk(c,vector[j].obj);
c7df85a4 7692 listRewind(operations,&li);
7693 while((ln = listNext(&li))) {
443c6409 7694 redisSortOperation *sop = ln->value;
7695 robj *val = lookupKeyByPattern(c->db,sop->pattern,
7696 vector[j].obj);
7697
7698 if (sop->type == REDIS_SORT_GET) {
55017f9d 7699 if (!val) {
443c6409 7700 addReply(c,shared.nullbulk);
7701 } else {
dd88747b 7702 addReplyBulk(c,val);
55017f9d 7703 decrRefCount(val);
443c6409 7704 }
7705 } else {
dfc5e96c 7706 redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
443c6409 7707 }
7708 }
ed9b544e 7709 }
443c6409 7710 } else {
74e0f445 7711 robj *sobj = createZiplistObject();
443c6409 7712
7713 /* STORE option specified, set the sorting result as a List object */
7714 for (j = start; j <= end; j++) {
7715 listNode *ln;
c7df85a4 7716 listIter li;
7717
443c6409 7718 if (!getop) {
003f0840 7719 listTypePush(sobj,vector[j].obj,REDIS_TAIL);
a03611e1
PN
7720 } else {
7721 listRewind(operations,&li);
7722 while((ln = listNext(&li))) {
7723 redisSortOperation *sop = ln->value;
7724 robj *val = lookupKeyByPattern(c->db,sop->pattern,
7725 vector[j].obj);
7726
7727 if (sop->type == REDIS_SORT_GET) {
7728 if (!val) val = createStringObject("",0);
7729
003f0840 7730 /* listTypePush does an incrRefCount, so we should take care
a03611e1
PN
7731 * care of the incremented refcount caused by either
7732 * lookupKeyByPattern or createStringObject("",0) */
003f0840 7733 listTypePush(sobj,val,REDIS_TAIL);
a03611e1 7734 decrRefCount(val);
443c6409 7735 } else {
a03611e1
PN
7736 /* always fails */
7737 redisAssert(sop->type == REDIS_SORT_GET);
443c6409 7738 }
ed9b544e 7739 }
ed9b544e 7740 }
ed9b544e 7741 }
846d8b3e 7742 dbReplace(c->db,storekey,sobj);
443c6409 7743 /* Note: we add 1 because the DB is dirty anyway since even if the
7744 * SORT result is empty a new key is set and maybe the old content
7745 * replaced. */
7746 server.dirty += 1+outputlen;
7747 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",outputlen));
ed9b544e 7748 }
7749
7750 /* Cleanup */
a03611e1
PN
7751 if (sortval->type == REDIS_LIST)
7752 for (j = 0; j < vectorlen; j++)
7753 decrRefCount(vector[j].obj);
ed9b544e 7754 decrRefCount(sortval);
7755 listRelease(operations);
7756 for (j = 0; j < vectorlen; j++) {
16fa22f1 7757 if (alpha && vector[j].u.cmpobj)
ed9b544e 7758 decrRefCount(vector[j].u.cmpobj);
7759 }
7760 zfree(vector);
7761}
7762
ec6c7a1d 7763/* Convert an amount of bytes into a human readable string in the form
7764 * of 100B, 2G, 100M, 4K, and so forth. */
7765static void bytesToHuman(char *s, unsigned long long n) {
7766 double d;
7767
7768 if (n < 1024) {
7769 /* Bytes */
7770 sprintf(s,"%lluB",n);
7771 return;
7772 } else if (n < (1024*1024)) {
7773 d = (double)n/(1024);
7774 sprintf(s,"%.2fK",d);
7775 } else if (n < (1024LL*1024*1024)) {
7776 d = (double)n/(1024*1024);
7777 sprintf(s,"%.2fM",d);
7778 } else if (n < (1024LL*1024*1024*1024)) {
7779 d = (double)n/(1024LL*1024*1024);
b72f6a4b 7780 sprintf(s,"%.2fG",d);
ec6c7a1d 7781 }
7782}
7783
1c85b79f 7784/* Create the string returned by the INFO command. This is decoupled
7785 * by the INFO command itself as we need to report the same information
7786 * on memory corruption problems. */
7787static sds genRedisInfoString(void) {
ed9b544e 7788 sds info;
7789 time_t uptime = time(NULL)-server.stat_starttime;
c3cb078d 7790 int j;
ec6c7a1d 7791 char hmem[64];
55a8298f 7792
b72f6a4b 7793 bytesToHuman(hmem,zmalloc_used_memory());
ed9b544e 7794 info = sdscatprintf(sdsempty(),
7795 "redis_version:%s\r\n"
5436146c
PN
7796 "redis_git_sha1:%s\r\n"
7797 "redis_git_dirty:%d\r\n"
f1017b3f 7798 "arch_bits:%s\r\n"
7a932b74 7799 "multiplexing_api:%s\r\n"
0d7170a4 7800 "process_id:%ld\r\n"
682ac724 7801 "uptime_in_seconds:%ld\r\n"
7802 "uptime_in_days:%ld\r\n"
ed9b544e 7803 "connected_clients:%d\r\n"
7804 "connected_slaves:%d\r\n"
f86a74e9 7805 "blocked_clients:%d\r\n"
5fba9f71 7806 "used_memory:%zu\r\n"
ec6c7a1d 7807 "used_memory_human:%s\r\n"
ed9b544e 7808 "changes_since_last_save:%lld\r\n"
be2bb6b0 7809 "bgsave_in_progress:%d\r\n"
682ac724 7810 "last_save_time:%ld\r\n"
b3fad521 7811 "bgrewriteaof_in_progress:%d\r\n"
ed9b544e 7812 "total_connections_received:%lld\r\n"
7813 "total_commands_processed:%lld\r\n"
2a6a2ed1 7814 "expired_keys:%lld\r\n"
3be2c9d7 7815 "hash_max_zipmap_entries:%zu\r\n"
7816 "hash_max_zipmap_value:%zu\r\n"
ffc6b7f8 7817 "pubsub_channels:%ld\r\n"
7818 "pubsub_patterns:%u\r\n"
7d98e08c 7819 "vm_enabled:%d\r\n"
a0f643ea 7820 "role:%s\r\n"
ed9b544e 7821 ,REDIS_VERSION,
5436146c 7822 REDIS_GIT_SHA1,
274e45e3 7823 strtol(REDIS_GIT_DIRTY,NULL,10) > 0,
f1017b3f 7824 (sizeof(long) == 8) ? "64" : "32",
7a932b74 7825 aeGetApiName(),
0d7170a4 7826 (long) getpid(),
a0f643ea 7827 uptime,
7828 uptime/(3600*24),
ed9b544e 7829 listLength(server.clients)-listLength(server.slaves),
7830 listLength(server.slaves),
d5d55fc3 7831 server.blpop_blocked_clients,
b72f6a4b 7832 zmalloc_used_memory(),
ec6c7a1d 7833 hmem,
ed9b544e 7834 server.dirty,
9d65a1bb 7835 server.bgsavechildpid != -1,
ed9b544e 7836 server.lastsave,
b3fad521 7837 server.bgrewritechildpid != -1,
ed9b544e 7838 server.stat_numconnections,
7839 server.stat_numcommands,
2a6a2ed1 7840 server.stat_expiredkeys,
55a8298f 7841 server.hash_max_zipmap_entries,
7842 server.hash_max_zipmap_value,
ffc6b7f8 7843 dictSize(server.pubsub_channels),
7844 listLength(server.pubsub_patterns),
7d98e08c 7845 server.vm_enabled != 0,
a0f643ea 7846 server.masterhost == NULL ? "master" : "slave"
ed9b544e 7847 );
a0f643ea 7848 if (server.masterhost) {
7849 info = sdscatprintf(info,
7850 "master_host:%s\r\n"
7851 "master_port:%d\r\n"
7852 "master_link_status:%s\r\n"
7853 "master_last_io_seconds_ago:%d\r\n"
7854 ,server.masterhost,
7855 server.masterport,
7856 (server.replstate == REDIS_REPL_CONNECTED) ?
7857 "up" : "down",
f72b934d 7858 server.master ? ((int)(time(NULL)-server.master->lastinteraction)) : -1
a0f643ea 7859 );
7860 }
7d98e08c 7861 if (server.vm_enabled) {
1064ef87 7862 lockThreadedIO();
7d98e08c 7863 info = sdscatprintf(info,
7864 "vm_conf_max_memory:%llu\r\n"
7865 "vm_conf_page_size:%llu\r\n"
7866 "vm_conf_pages:%llu\r\n"
7867 "vm_stats_used_pages:%llu\r\n"
7868 "vm_stats_swapped_objects:%llu\r\n"
7869 "vm_stats_swappin_count:%llu\r\n"
7870 "vm_stats_swappout_count:%llu\r\n"
b9bc0eef 7871 "vm_stats_io_newjobs_len:%lu\r\n"
7872 "vm_stats_io_processing_len:%lu\r\n"
7873 "vm_stats_io_processed_len:%lu\r\n"
25fd2cb2 7874 "vm_stats_io_active_threads:%lu\r\n"
d5d55fc3 7875 "vm_stats_blocked_clients:%lu\r\n"
7d98e08c 7876 ,(unsigned long long) server.vm_max_memory,
7877 (unsigned long long) server.vm_page_size,
7878 (unsigned long long) server.vm_pages,
7879 (unsigned long long) server.vm_stats_used_pages,
7880 (unsigned long long) server.vm_stats_swapped_objects,
7881 (unsigned long long) server.vm_stats_swapins,
b9bc0eef 7882 (unsigned long long) server.vm_stats_swapouts,
7883 (unsigned long) listLength(server.io_newjobs),
7884 (unsigned long) listLength(server.io_processing),
7885 (unsigned long) listLength(server.io_processed),
d5d55fc3 7886 (unsigned long) server.io_active_threads,
7887 (unsigned long) server.vm_blocked_clients
7d98e08c 7888 );
1064ef87 7889 unlockThreadedIO();
7d98e08c 7890 }
c3cb078d 7891 for (j = 0; j < server.dbnum; j++) {
7892 long long keys, vkeys;
7893
7894 keys = dictSize(server.db[j].dict);
7895 vkeys = dictSize(server.db[j].expires);
7896 if (keys || vkeys) {
9d65a1bb 7897 info = sdscatprintf(info, "db%d:keys=%lld,expires=%lld\r\n",
c3cb078d 7898 j, keys, vkeys);
7899 }
7900 }
1c85b79f 7901 return info;
7902}
7903
7904static void infoCommand(redisClient *c) {
7905 sds info = genRedisInfoString();
83c6a618 7906 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n",
7907 (unsigned long)sdslen(info)));
ed9b544e 7908 addReplySds(c,info);
70003d28 7909 addReply(c,shared.crlf);
ed9b544e 7910}
7911
3305306f 7912static void monitorCommand(redisClient *c) {
7913 /* ignore MONITOR if aleady slave or in monitor mode */
7914 if (c->flags & REDIS_SLAVE) return;
7915
7916 c->flags |= (REDIS_SLAVE|REDIS_MONITOR);
7917 c->slaveseldb = 0;
6b47e12e 7918 listAddNodeTail(server.monitors,c);
3305306f 7919 addReply(c,shared.ok);
7920}
7921
7922/* ================================= Expire ================================= */
7923static int removeExpire(redisDb *db, robj *key) {
09241813 7924 if (dictDelete(db->expires,key->ptr) == DICT_OK) {
3305306f 7925 return 1;
7926 } else {
7927 return 0;
7928 }
7929}
7930
7931static int setExpire(redisDb *db, robj *key, time_t when) {
09241813 7932 sds copy = sdsdup(key->ptr);
7933 if (dictAdd(db->expires,copy,(void*)when) == DICT_ERR) {
7934 sdsfree(copy);
3305306f 7935 return 0;
7936 } else {
3305306f 7937 return 1;
7938 }
7939}
7940
bb32ede5 7941/* Return the expire time of the specified key, or -1 if no expire
7942 * is associated with this key (i.e. the key is non volatile) */
7943static time_t getExpire(redisDb *db, robj *key) {
7944 dictEntry *de;
7945
7946 /* No expire? return ASAP */
7947 if (dictSize(db->expires) == 0 ||
09241813 7948 (de = dictFind(db->expires,key->ptr)) == NULL) return -1;
bb32ede5 7949
7950 return (time_t) dictGetEntryVal(de);
7951}
7952
3305306f 7953static int expireIfNeeded(redisDb *db, robj *key) {
7954 time_t when;
7955 dictEntry *de;
7956
7957 /* No expire? return ASAP */
7958 if (dictSize(db->expires) == 0 ||
09241813 7959 (de = dictFind(db->expires,key->ptr)) == NULL) return 0;
3305306f 7960
7961 /* Lookup the expire */
7962 when = (time_t) dictGetEntryVal(de);
7963 if (time(NULL) <= when) return 0;
7964
7965 /* Delete the key */
09241813 7966 dbDelete(db,key);
2a6a2ed1 7967 server.stat_expiredkeys++;
09241813 7968 return 1;
3305306f 7969}
7970
7971static int deleteIfVolatile(redisDb *db, robj *key) {
7972 dictEntry *de;
7973
7974 /* No expire? return ASAP */
7975 if (dictSize(db->expires) == 0 ||
09241813 7976 (de = dictFind(db->expires,key->ptr)) == NULL) return 0;
3305306f 7977
7978 /* Delete the key */
0c66a471 7979 server.dirty++;
2a6a2ed1 7980 server.stat_expiredkeys++;
09241813 7981 dictDelete(db->expires,key->ptr);
7982 return dictDelete(db->dict,key->ptr) == DICT_OK;
3305306f 7983}
7984
bbe025e0 7985static void expireGenericCommand(redisClient *c, robj *key, robj *param, long offset) {
3305306f 7986 dictEntry *de;
bbe025e0
AM
7987 time_t seconds;
7988
bd79a6bd 7989 if (getLongFromObjectOrReply(c, param, &seconds, NULL) != REDIS_OK) return;
bbe025e0
AM
7990
7991 seconds -= offset;
3305306f 7992
09241813 7993 de = dictFind(c->db->dict,key->ptr);
3305306f 7994 if (de == NULL) {
7995 addReply(c,shared.czero);
7996 return;
7997 }
d4dd6556 7998 if (seconds <= 0) {
09241813 7999 if (dbDelete(c->db,key)) server.dirty++;
43e5ccdf 8000 addReply(c, shared.cone);
3305306f 8001 return;
8002 } else {
8003 time_t when = time(NULL)+seconds;
802e8373 8004 if (setExpire(c->db,key,when)) {
3305306f 8005 addReply(c,shared.cone);
77423026 8006 server.dirty++;
8007 } else {
3305306f 8008 addReply(c,shared.czero);
77423026 8009 }
3305306f 8010 return;
8011 }
8012}
8013
802e8373 8014static void expireCommand(redisClient *c) {
bbe025e0 8015 expireGenericCommand(c,c->argv[1],c->argv[2],0);
802e8373 8016}
8017
8018static void expireatCommand(redisClient *c) {
bbe025e0 8019 expireGenericCommand(c,c->argv[1],c->argv[2],time(NULL));
802e8373 8020}
8021
fd88489a 8022static void ttlCommand(redisClient *c) {
8023 time_t expire;
8024 int ttl = -1;
8025
8026 expire = getExpire(c->db,c->argv[1]);
8027 if (expire != -1) {
8028 ttl = (int) (expire-time(NULL));
8029 if (ttl < 0) ttl = -1;
8030 }
8031 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",ttl));
8032}
8033
6e469882 8034/* ================================ MULTI/EXEC ============================== */
8035
8036/* Client state initialization for MULTI/EXEC */
8037static void initClientMultiState(redisClient *c) {
8038 c->mstate.commands = NULL;
8039 c->mstate.count = 0;
8040}
8041
8042/* Release all the resources associated with MULTI/EXEC state */
8043static void freeClientMultiState(redisClient *c) {
8044 int j;
8045
8046 for (j = 0; j < c->mstate.count; j++) {
8047 int i;
8048 multiCmd *mc = c->mstate.commands+j;
8049
8050 for (i = 0; i < mc->argc; i++)
8051 decrRefCount(mc->argv[i]);
8052 zfree(mc->argv);
8053 }
8054 zfree(c->mstate.commands);
8055}
8056
8057/* Add a new command into the MULTI commands queue */
8058static void queueMultiCommand(redisClient *c, struct redisCommand *cmd) {
8059 multiCmd *mc;
8060 int j;
8061
8062 c->mstate.commands = zrealloc(c->mstate.commands,
8063 sizeof(multiCmd)*(c->mstate.count+1));
8064 mc = c->mstate.commands+c->mstate.count;
8065 mc->cmd = cmd;
8066 mc->argc = c->argc;
8067 mc->argv = zmalloc(sizeof(robj*)*c->argc);
8068 memcpy(mc->argv,c->argv,sizeof(robj*)*c->argc);
8069 for (j = 0; j < c->argc; j++)
8070 incrRefCount(mc->argv[j]);
8071 c->mstate.count++;
8072}
8073
8074static void multiCommand(redisClient *c) {
6531c94d 8075 if (c->flags & REDIS_MULTI) {
8076 addReplySds(c,sdsnew("-ERR MULTI calls can not be nested\r\n"));
8077 return;
8078 }
6e469882 8079 c->flags |= REDIS_MULTI;
36c548f0 8080 addReply(c,shared.ok);
6e469882 8081}
8082
18b6cb76
DJ
8083static void discardCommand(redisClient *c) {
8084 if (!(c->flags & REDIS_MULTI)) {
8085 addReplySds(c,sdsnew("-ERR DISCARD without MULTI\r\n"));
8086 return;
8087 }
8088
8089 freeClientMultiState(c);
8090 initClientMultiState(c);
8091 c->flags &= (~REDIS_MULTI);
a2645226 8092 unwatchAllKeys(c);
18b6cb76
DJ
8093 addReply(c,shared.ok);
8094}
8095
66c8853f 8096/* Send a MULTI command to all the slaves and AOF file. Check the execCommand
8097 * implememntation for more information. */
8098static void execCommandReplicateMulti(redisClient *c) {
8099 struct redisCommand *cmd;
8100 robj *multistring = createStringObject("MULTI",5);
8101
8102 cmd = lookupCommand("multi");
8103 if (server.appendonly)
8104 feedAppendOnlyFile(cmd,c->db->id,&multistring,1);
8105 if (listLength(server.slaves))
8106 replicationFeedSlaves(server.slaves,c->db->id,&multistring,1);
8107 decrRefCount(multistring);
8108}
8109
6e469882 8110static void execCommand(redisClient *c) {
8111 int j;
8112 robj **orig_argv;
8113 int orig_argc;
8114
8115 if (!(c->flags & REDIS_MULTI)) {
8116 addReplySds(c,sdsnew("-ERR EXEC without MULTI\r\n"));
8117 return;
8118 }
8119
37ab76c9 8120 /* Check if we need to abort the EXEC if some WATCHed key was touched.
8121 * A failed EXEC will return a multi bulk nil object. */
8122 if (c->flags & REDIS_DIRTY_CAS) {
8123 freeClientMultiState(c);
8124 initClientMultiState(c);
8125 c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS);
8126 unwatchAllKeys(c);
8127 addReply(c,shared.nullmultibulk);
8128 return;
8129 }
8130
66c8853f 8131 /* Replicate a MULTI request now that we are sure the block is executed.
8132 * This way we'll deliver the MULTI/..../EXEC block as a whole and
8133 * both the AOF and the replication link will have the same consistency
8134 * and atomicity guarantees. */
8135 execCommandReplicateMulti(c);
8136
8137 /* Exec all the queued commands */
1ad4d316 8138 unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */
6e469882 8139 orig_argv = c->argv;
8140 orig_argc = c->argc;
8141 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->mstate.count));
8142 for (j = 0; j < c->mstate.count; j++) {
8143 c->argc = c->mstate.commands[j].argc;
8144 c->argv = c->mstate.commands[j].argv;
8145 call(c,c->mstate.commands[j].cmd);
8146 }
8147 c->argv = orig_argv;
8148 c->argc = orig_argc;
8149 freeClientMultiState(c);
8150 initClientMultiState(c);
1ad4d316 8151 c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS);
66c8853f 8152 /* Make sure the EXEC command is always replicated / AOF, since we
8153 * always send the MULTI command (we can't know beforehand if the
8154 * next operations will contain at least a modification to the DB). */
8155 server.dirty++;
6e469882 8156}
8157
4409877e 8158/* =========================== Blocking Operations ========================= */
8159
8160/* Currently Redis blocking operations support is limited to list POP ops,
8161 * so the current implementation is not fully generic, but it is also not
8162 * completely specific so it will not require a rewrite to support new
8163 * kind of blocking operations in the future.
8164 *
8165 * Still it's important to note that list blocking operations can be already
8166 * used as a notification mechanism in order to implement other blocking
8167 * operations at application level, so there must be a very strong evidence
8168 * of usefulness and generality before new blocking operations are implemented.
8169 *
8170 * This is how the current blocking POP works, we use BLPOP as example:
8171 * - If the user calls BLPOP and the key exists and contains a non empty list
8172 * then LPOP is called instead. So BLPOP is semantically the same as LPOP
8173 * if there is not to block.
8174 * - If instead BLPOP is called and the key does not exists or the list is
8175 * empty we need to block. In order to do so we remove the notification for
8176 * new data to read in the client socket (so that we'll not serve new
8177 * requests if the blocking request is not served). Also we put the client
37ab76c9 8178 * in a dictionary (db->blocking_keys) mapping keys to a list of clients
4409877e 8179 * blocking for this keys.
8180 * - If a PUSH operation against a key with blocked clients waiting is
8181 * performed, we serve the first in the list: basically instead to push
8182 * the new element inside the list we return it to the (first / oldest)
8183 * blocking client, unblock the client, and remove it form the list.
8184 *
8185 * The above comment and the source code should be enough in order to understand
8186 * the implementation and modify / fix it later.
8187 */
8188
8189/* Set a client in blocking mode for the specified key, with the specified
8190 * timeout */
b177fd30 8191static void blockForKeys(redisClient *c, robj **keys, int numkeys, time_t timeout) {
4409877e 8192 dictEntry *de;
8193 list *l;
b177fd30 8194 int j;
4409877e 8195
37ab76c9 8196 c->blocking_keys = zmalloc(sizeof(robj*)*numkeys);
8197 c->blocking_keys_num = numkeys;
4409877e 8198 c->blockingto = timeout;
b177fd30 8199 for (j = 0; j < numkeys; j++) {
8200 /* Add the key in the client structure, to map clients -> keys */
37ab76c9 8201 c->blocking_keys[j] = keys[j];
b177fd30 8202 incrRefCount(keys[j]);
4409877e 8203
b177fd30 8204 /* And in the other "side", to map keys -> clients */
37ab76c9 8205 de = dictFind(c->db->blocking_keys,keys[j]);
b177fd30 8206 if (de == NULL) {
8207 int retval;
8208
8209 /* For every key we take a list of clients blocked for it */
8210 l = listCreate();
37ab76c9 8211 retval = dictAdd(c->db->blocking_keys,keys[j],l);
b177fd30 8212 incrRefCount(keys[j]);
8213 assert(retval == DICT_OK);
8214 } else {
8215 l = dictGetEntryVal(de);
8216 }
8217 listAddNodeTail(l,c);
4409877e 8218 }
b177fd30 8219 /* Mark the client as a blocked client */
4409877e 8220 c->flags |= REDIS_BLOCKED;
d5d55fc3 8221 server.blpop_blocked_clients++;
4409877e 8222}
8223
8224/* Unblock a client that's waiting in a blocking operation such as BLPOP */
b0d8747d 8225static void unblockClientWaitingData(redisClient *c) {
4409877e 8226 dictEntry *de;
8227 list *l;
b177fd30 8228 int j;
4409877e 8229
37ab76c9 8230 assert(c->blocking_keys != NULL);
b177fd30 8231 /* The client may wait for multiple keys, so unblock it for every key. */
37ab76c9 8232 for (j = 0; j < c->blocking_keys_num; j++) {
b177fd30 8233 /* Remove this client from the list of clients waiting for this key. */
37ab76c9 8234 de = dictFind(c->db->blocking_keys,c->blocking_keys[j]);
b177fd30 8235 assert(de != NULL);
8236 l = dictGetEntryVal(de);
8237 listDelNode(l,listSearchKey(l,c));
8238 /* If the list is empty we need to remove it to avoid wasting memory */
8239 if (listLength(l) == 0)
37ab76c9 8240 dictDelete(c->db->blocking_keys,c->blocking_keys[j]);
8241 decrRefCount(c->blocking_keys[j]);
b177fd30 8242 }
8243 /* Cleanup the client structure */
37ab76c9 8244 zfree(c->blocking_keys);
8245 c->blocking_keys = NULL;
4409877e 8246 c->flags &= (~REDIS_BLOCKED);
d5d55fc3 8247 server.blpop_blocked_clients--;
5921aa36 8248 /* We want to process data if there is some command waiting
b0d8747d 8249 * in the input buffer. Note that this is safe even if
8250 * unblockClientWaitingData() gets called from freeClient() because
8251 * freeClient() will be smart enough to call this function
8252 * *after* c->querybuf was set to NULL. */
4409877e 8253 if (c->querybuf && sdslen(c->querybuf) > 0) processInputBuffer(c);
8254}
8255
8256/* This should be called from any function PUSHing into lists.
8257 * 'c' is the "pushing client", 'key' is the key it is pushing data against,
8258 * 'ele' is the element pushed.
8259 *
8260 * If the function returns 0 there was no client waiting for a list push
8261 * against this key.
8262 *
8263 * If the function returns 1 there was a client waiting for a list push
8264 * against this key, the element was passed to this client thus it's not
8265 * needed to actually add it to the list and the caller should return asap. */
8266static int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
8267 struct dictEntry *de;
8268 redisClient *receiver;
8269 list *l;
8270 listNode *ln;
8271
37ab76c9 8272 de = dictFind(c->db->blocking_keys,key);
4409877e 8273 if (de == NULL) return 0;
8274 l = dictGetEntryVal(de);
8275 ln = listFirst(l);
8276 assert(ln != NULL);
8277 receiver = ln->value;
4409877e 8278
b177fd30 8279 addReplySds(receiver,sdsnew("*2\r\n"));
dd88747b 8280 addReplyBulk(receiver,key);
8281 addReplyBulk(receiver,ele);
b0d8747d 8282 unblockClientWaitingData(receiver);
4409877e 8283 return 1;
8284}
8285
8286/* Blocking RPOP/LPOP */
8287static void blockingPopGenericCommand(redisClient *c, int where) {
8288 robj *o;
8289 time_t timeout;
b177fd30 8290 int j;
4409877e 8291
b177fd30 8292 for (j = 1; j < c->argc-1; j++) {
8293 o = lookupKeyWrite(c->db,c->argv[j]);
8294 if (o != NULL) {
8295 if (o->type != REDIS_LIST) {
8296 addReply(c,shared.wrongtypeerr);
4409877e 8297 return;
b177fd30 8298 } else {
8299 list *list = o->ptr;
8300 if (listLength(list) != 0) {
8301 /* If the list contains elements fall back to the usual
8302 * non-blocking POP operation */
8303 robj *argv[2], **orig_argv;
8304 int orig_argc;
e0a62c7f 8305
b177fd30 8306 /* We need to alter the command arguments before to call
8307 * popGenericCommand() as the command takes a single key. */
8308 orig_argv = c->argv;
8309 orig_argc = c->argc;
8310 argv[1] = c->argv[j];
8311 c->argv = argv;
8312 c->argc = 2;
8313
8314 /* Also the return value is different, we need to output
8315 * the multi bulk reply header and the key name. The
8316 * "real" command will add the last element (the value)
8317 * for us. If this souds like an hack to you it's just
8318 * because it is... */
8319 addReplySds(c,sdsnew("*2\r\n"));
dd88747b 8320 addReplyBulk(c,argv[1]);
b177fd30 8321 popGenericCommand(c,where);
8322
8323 /* Fix the client structure with the original stuff */
8324 c->argv = orig_argv;
8325 c->argc = orig_argc;
8326 return;
8327 }
4409877e 8328 }
8329 }
8330 }
8331 /* If the list is empty or the key does not exists we must block */
b177fd30 8332 timeout = strtol(c->argv[c->argc-1]->ptr,NULL,10);
4409877e 8333 if (timeout > 0) timeout += time(NULL);
b177fd30 8334 blockForKeys(c,c->argv+1,c->argc-2,timeout);
4409877e 8335}
8336
8337static void blpopCommand(redisClient *c) {
8338 blockingPopGenericCommand(c,REDIS_HEAD);
8339}
8340
8341static void brpopCommand(redisClient *c) {
8342 blockingPopGenericCommand(c,REDIS_TAIL);
8343}
8344
ed9b544e 8345/* =============================== Replication ============================= */
8346
a4d1ba9a 8347static int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 8348 ssize_t nwritten, ret = size;
8349 time_t start = time(NULL);
8350
8351 timeout++;
8352 while(size) {
8353 if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
8354 nwritten = write(fd,ptr,size);
8355 if (nwritten == -1) return -1;
8356 ptr += nwritten;
8357 size -= nwritten;
8358 }
8359 if ((time(NULL)-start) > timeout) {
8360 errno = ETIMEDOUT;
8361 return -1;
8362 }
8363 }
8364 return ret;
8365}
8366
a4d1ba9a 8367static int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 8368 ssize_t nread, totread = 0;
8369 time_t start = time(NULL);
8370
8371 timeout++;
8372 while(size) {
8373 if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
8374 nread = read(fd,ptr,size);
8375 if (nread == -1) return -1;
8376 ptr += nread;
8377 size -= nread;
8378 totread += nread;
8379 }
8380 if ((time(NULL)-start) > timeout) {
8381 errno = ETIMEDOUT;
8382 return -1;
8383 }
8384 }
8385 return totread;
8386}
8387
8388static int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
8389 ssize_t nread = 0;
8390
8391 size--;
8392 while(size) {
8393 char c;
8394
8395 if (syncRead(fd,&c,1,timeout) == -1) return -1;
8396 if (c == '\n') {
8397 *ptr = '\0';
8398 if (nread && *(ptr-1) == '\r') *(ptr-1) = '\0';
8399 return nread;
8400 } else {
8401 *ptr++ = c;
8402 *ptr = '\0';
8403 nread++;
8404 }
8405 }
8406 return nread;
8407}
8408
8409static void syncCommand(redisClient *c) {
40d224a9 8410 /* ignore SYNC if aleady slave or in monitor mode */
8411 if (c->flags & REDIS_SLAVE) return;
8412
8413 /* SYNC can't be issued when the server has pending data to send to
8414 * the client about already issued commands. We need a fresh reply
8415 * buffer registering the differences between the BGSAVE and the current
8416 * dataset, so that we can copy to other slaves if needed. */
8417 if (listLength(c->reply) != 0) {
8418 addReplySds(c,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
8419 return;
8420 }
8421
8422 redisLog(REDIS_NOTICE,"Slave ask for synchronization");
8423 /* Here we need to check if there is a background saving operation
8424 * in progress, or if it is required to start one */
9d65a1bb 8425 if (server.bgsavechildpid != -1) {
40d224a9 8426 /* Ok a background save is in progress. Let's check if it is a good
8427 * one for replication, i.e. if there is another slave that is
8428 * registering differences since the server forked to save */
8429 redisClient *slave;
8430 listNode *ln;
c7df85a4 8431 listIter li;
40d224a9 8432
c7df85a4 8433 listRewind(server.slaves,&li);
8434 while((ln = listNext(&li))) {
40d224a9 8435 slave = ln->value;
8436 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break;
40d224a9 8437 }
8438 if (ln) {
8439 /* Perfect, the server is already registering differences for
8440 * another slave. Set the right state, and copy the buffer. */
8441 listRelease(c->reply);
8442 c->reply = listDup(slave->reply);
40d224a9 8443 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
8444 redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC");
8445 } else {
8446 /* No way, we need to wait for the next BGSAVE in order to
8447 * register differences */
8448 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
8449 redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
8450 }
8451 } else {
8452 /* Ok we don't have a BGSAVE in progress, let's start one */
8453 redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
8454 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
8455 redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE");
8456 addReplySds(c,sdsnew("-ERR Unalbe to perform background save\r\n"));
8457 return;
8458 }
8459 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
8460 }
6208b3a7 8461 c->repldbfd = -1;
40d224a9 8462 c->flags |= REDIS_SLAVE;
8463 c->slaveseldb = 0;
6b47e12e 8464 listAddNodeTail(server.slaves,c);
40d224a9 8465 return;
8466}
8467
6208b3a7 8468static void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
8469 redisClient *slave = privdata;
8470 REDIS_NOTUSED(el);
8471 REDIS_NOTUSED(mask);
8472 char buf[REDIS_IOBUF_LEN];
8473 ssize_t nwritten, buflen;
8474
8475 if (slave->repldboff == 0) {
8476 /* Write the bulk write count before to transfer the DB. In theory here
8477 * we don't know how much room there is in the output buffer of the
8478 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
8479 * operations) will never be smaller than the few bytes we need. */
8480 sds bulkcount;
8481
8482 bulkcount = sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
8483 slave->repldbsize);
8484 if (write(fd,bulkcount,sdslen(bulkcount)) != (signed)sdslen(bulkcount))
8485 {
8486 sdsfree(bulkcount);
8487 freeClient(slave);
8488 return;
8489 }
8490 sdsfree(bulkcount);
8491 }
8492 lseek(slave->repldbfd,slave->repldboff,SEEK_SET);
8493 buflen = read(slave->repldbfd,buf,REDIS_IOBUF_LEN);
8494 if (buflen <= 0) {
8495 redisLog(REDIS_WARNING,"Read error sending DB to slave: %s",
8496 (buflen == 0) ? "premature EOF" : strerror(errno));
8497 freeClient(slave);
8498 return;
8499 }
8500 if ((nwritten = write(fd,buf,buflen)) == -1) {
f870935d 8501 redisLog(REDIS_VERBOSE,"Write error sending DB to slave: %s",
6208b3a7 8502 strerror(errno));
8503 freeClient(slave);
8504 return;
8505 }
8506 slave->repldboff += nwritten;
8507 if (slave->repldboff == slave->repldbsize) {
8508 close(slave->repldbfd);
8509 slave->repldbfd = -1;
8510 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
8511 slave->replstate = REDIS_REPL_ONLINE;
8512 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
266373b2 8513 sendReplyToClient, slave) == AE_ERR) {
6208b3a7 8514 freeClient(slave);
8515 return;
8516 }
8517 addReplySds(slave,sdsempty());
8518 redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
8519 }
8520}
ed9b544e 8521
a3b21203 8522/* This function is called at the end of every backgrond saving.
8523 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
8524 * otherwise REDIS_ERR is passed to the function.
8525 *
8526 * The goal of this function is to handle slaves waiting for a successful
8527 * background saving in order to perform non-blocking synchronization. */
8528static void updateSlavesWaitingBgsave(int bgsaveerr) {
6208b3a7 8529 listNode *ln;
8530 int startbgsave = 0;
c7df85a4 8531 listIter li;
ed9b544e 8532
c7df85a4 8533 listRewind(server.slaves,&li);
8534 while((ln = listNext(&li))) {
6208b3a7 8535 redisClient *slave = ln->value;
ed9b544e 8536
6208b3a7 8537 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) {
8538 startbgsave = 1;
8539 slave->replstate = REDIS_REPL_WAIT_BGSAVE_END;
8540 } else if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
dde65f3f 8541 struct redis_stat buf;
e0a62c7f 8542
6208b3a7 8543 if (bgsaveerr != REDIS_OK) {
8544 freeClient(slave);
8545 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE child returned an error");
8546 continue;
8547 }
8548 if ((slave->repldbfd = open(server.dbfilename,O_RDONLY)) == -1 ||
dde65f3f 8549 redis_fstat(slave->repldbfd,&buf) == -1) {
6208b3a7 8550 freeClient(slave);
8551 redisLog(REDIS_WARNING,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno));
8552 continue;
8553 }
8554 slave->repldboff = 0;
8555 slave->repldbsize = buf.st_size;
8556 slave->replstate = REDIS_REPL_SEND_BULK;
8557 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
266373b2 8558 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE, sendBulkToSlave, slave) == AE_ERR) {
6208b3a7 8559 freeClient(slave);
8560 continue;
8561 }
8562 }
ed9b544e 8563 }
6208b3a7 8564 if (startbgsave) {
8565 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
c7df85a4 8566 listIter li;
8567
8568 listRewind(server.slaves,&li);
6208b3a7 8569 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE failed");
c7df85a4 8570 while((ln = listNext(&li))) {
6208b3a7 8571 redisClient *slave = ln->value;
ed9b544e 8572
6208b3a7 8573 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START)
8574 freeClient(slave);
8575 }
8576 }
8577 }
ed9b544e 8578}
8579
8580static int syncWithMaster(void) {
d0ccebcf 8581 char buf[1024], tmpfile[256], authcmd[1024];
18e61fa2 8582 long dumpsize;
ed9b544e 8583 int fd = anetTcpConnect(NULL,server.masterhost,server.masterport);
8c5abee8 8584 int dfd, maxtries = 5;
ed9b544e 8585
8586 if (fd == -1) {
8587 redisLog(REDIS_WARNING,"Unable to connect to MASTER: %s",
8588 strerror(errno));
8589 return REDIS_ERR;
8590 }
d0ccebcf 8591
8592 /* AUTH with the master if required. */
8593 if(server.masterauth) {
8594 snprintf(authcmd, 1024, "AUTH %s\r\n", server.masterauth);
8595 if (syncWrite(fd, authcmd, strlen(server.masterauth)+7, 5) == -1) {
8596 close(fd);
8597 redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",
8598 strerror(errno));
8599 return REDIS_ERR;
8600 }
8601 /* Read the AUTH result. */
8602 if (syncReadLine(fd,buf,1024,3600) == -1) {
8603 close(fd);
8604 redisLog(REDIS_WARNING,"I/O error reading auth result from MASTER: %s",
8605 strerror(errno));
8606 return REDIS_ERR;
8607 }
8608 if (buf[0] != '+') {
8609 close(fd);
8610 redisLog(REDIS_WARNING,"Cannot AUTH to MASTER, is the masterauth password correct?");
8611 return REDIS_ERR;
8612 }
8613 }
8614
ed9b544e 8615 /* Issue the SYNC command */
8616 if (syncWrite(fd,"SYNC \r\n",7,5) == -1) {
8617 close(fd);
8618 redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
8619 strerror(errno));
8620 return REDIS_ERR;
8621 }
8622 /* Read the bulk write count */
8c4d91fc 8623 if (syncReadLine(fd,buf,1024,3600) == -1) {
ed9b544e 8624 close(fd);
8625 redisLog(REDIS_WARNING,"I/O error reading bulk count from MASTER: %s",
8626 strerror(errno));
8627 return REDIS_ERR;
8628 }
4aa701c1 8629 if (buf[0] != '$') {
8630 close(fd);
8631 redisLog(REDIS_WARNING,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
8632 return REDIS_ERR;
8633 }
18e61fa2 8634 dumpsize = strtol(buf+1,NULL,10);
8635 redisLog(REDIS_NOTICE,"Receiving %ld bytes data dump from MASTER",dumpsize);
ed9b544e 8636 /* Read the bulk write data on a temp file */
8c5abee8 8637 while(maxtries--) {
8638 snprintf(tmpfile,256,
8639 "temp-%d.%ld.rdb",(int)time(NULL),(long int)getpid());
8640 dfd = open(tmpfile,O_CREAT|O_WRONLY|O_EXCL,0644);
8641 if (dfd != -1) break;
5de9ad7c 8642 sleep(1);
8c5abee8 8643 }
ed9b544e 8644 if (dfd == -1) {
8645 close(fd);
8646 redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
8647 return REDIS_ERR;
8648 }
8649 while(dumpsize) {
8650 int nread, nwritten;
8651
8652 nread = read(fd,buf,(dumpsize < 1024)?dumpsize:1024);
8653 if (nread == -1) {
8654 redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
8655 strerror(errno));
8656 close(fd);
8657 close(dfd);
8658 return REDIS_ERR;
8659 }
8660 nwritten = write(dfd,buf,nread);
8661 if (nwritten == -1) {
8662 redisLog(REDIS_WARNING,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
8663 close(fd);
8664 close(dfd);
8665 return REDIS_ERR;
8666 }
8667 dumpsize -= nread;
8668 }
8669 close(dfd);
8670 if (rename(tmpfile,server.dbfilename) == -1) {
8671 redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
8672 unlink(tmpfile);
8673 close(fd);
8674 return REDIS_ERR;
8675 }
8676 emptyDb();
f78fd11b 8677 if (rdbLoad(server.dbfilename) != REDIS_OK) {
ed9b544e 8678 redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
8679 close(fd);
8680 return REDIS_ERR;
8681 }
8682 server.master = createClient(fd);
8683 server.master->flags |= REDIS_MASTER;
179b3952 8684 server.master->authenticated = 1;
ed9b544e 8685 server.replstate = REDIS_REPL_CONNECTED;
8686 return REDIS_OK;
8687}
8688
321b0e13 8689static void slaveofCommand(redisClient *c) {
8690 if (!strcasecmp(c->argv[1]->ptr,"no") &&
8691 !strcasecmp(c->argv[2]->ptr,"one")) {
8692 if (server.masterhost) {
8693 sdsfree(server.masterhost);
8694 server.masterhost = NULL;
8695 if (server.master) freeClient(server.master);
8696 server.replstate = REDIS_REPL_NONE;
8697 redisLog(REDIS_NOTICE,"MASTER MODE enabled (user request)");
8698 }
8699 } else {
8700 sdsfree(server.masterhost);
8701 server.masterhost = sdsdup(c->argv[1]->ptr);
8702 server.masterport = atoi(c->argv[2]->ptr);
8703 if (server.master) freeClient(server.master);
8704 server.replstate = REDIS_REPL_CONNECT;
8705 redisLog(REDIS_NOTICE,"SLAVE OF %s:%d enabled (user request)",
8706 server.masterhost, server.masterport);
8707 }
8708 addReply(c,shared.ok);
8709}
8710
3fd78bcd 8711/* ============================ Maxmemory directive ======================== */
8712
a5819310 8713/* Try to free one object form the pre-allocated objects free list.
8714 * This is useful under low mem conditions as by default we take 1 million
8715 * free objects allocated. On success REDIS_OK is returned, otherwise
8716 * REDIS_ERR. */
8717static int tryFreeOneObjectFromFreelist(void) {
f870935d 8718 robj *o;
8719
a5819310 8720 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
8721 if (listLength(server.objfreelist)) {
8722 listNode *head = listFirst(server.objfreelist);
8723 o = listNodeValue(head);
8724 listDelNode(server.objfreelist,head);
8725 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
8726 zfree(o);
8727 return REDIS_OK;
8728 } else {
8729 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
8730 return REDIS_ERR;
8731 }
f870935d 8732}
8733
3fd78bcd 8734/* This function gets called when 'maxmemory' is set on the config file to limit
8735 * the max memory used by the server, and we are out of memory.
8736 * This function will try to, in order:
8737 *
8738 * - Free objects from the free list
8739 * - Try to remove keys with an EXPIRE set
8740 *
8741 * It is not possible to free enough memory to reach used-memory < maxmemory
8742 * the server will start refusing commands that will enlarge even more the
8743 * memory usage.
8744 */
8745static void freeMemoryIfNeeded(void) {
8746 while (server.maxmemory && zmalloc_used_memory() > server.maxmemory) {
a5819310 8747 int j, k, freed = 0;
8748
8749 if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
8750 for (j = 0; j < server.dbnum; j++) {
8751 int minttl = -1;
8752 robj *minkey = NULL;
8753 struct dictEntry *de;
8754
8755 if (dictSize(server.db[j].expires)) {
8756 freed = 1;
8757 /* From a sample of three keys drop the one nearest to
8758 * the natural expire */
8759 for (k = 0; k < 3; k++) {
8760 time_t t;
8761
8762 de = dictGetRandomKey(server.db[j].expires);
8763 t = (time_t) dictGetEntryVal(de);
8764 if (minttl == -1 || t < minttl) {
8765 minkey = dictGetEntryKey(de);
8766 minttl = t;
3fd78bcd 8767 }
3fd78bcd 8768 }
09241813 8769 dbDelete(server.db+j,minkey);
3fd78bcd 8770 }
3fd78bcd 8771 }
a5819310 8772 if (!freed) return; /* nothing to free... */
3fd78bcd 8773 }
8774}
8775
f80dff62 8776/* ============================== Append Only file ========================== */
8777
560db612 8778/* Called when the user switches from "appendonly yes" to "appendonly no"
8779 * at runtime using the CONFIG command. */
8780static void stopAppendOnly(void) {
8781 flushAppendOnlyFile();
8782 aof_fsync(server.appendfd);
8783 close(server.appendfd);
8784
8785 server.appendfd = -1;
8786 server.appendseldb = -1;
8787 server.appendonly = 0;
8788 /* rewrite operation in progress? kill it, wait child exit */
8789 if (server.bgsavechildpid != -1) {
8790 int statloc;
8791
8792 if (kill(server.bgsavechildpid,SIGKILL) != -1)
8793 wait3(&statloc,0,NULL);
8794 /* reset the buffer accumulating changes while the child saves */
8795 sdsfree(server.bgrewritebuf);
8796 server.bgrewritebuf = sdsempty();
8797 server.bgsavechildpid = -1;
8798 }
8799}
8800
8801/* Called when the user switches from "appendonly no" to "appendonly yes"
8802 * at runtime using the CONFIG command. */
8803static int startAppendOnly(void) {
8804 server.appendonly = 1;
8805 server.lastfsync = time(NULL);
8806 server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
8807 if (server.appendfd == -1) {
8808 redisLog(REDIS_WARNING,"Used tried to switch on AOF via CONFIG, but I can't open the AOF file: %s",strerror(errno));
8809 return REDIS_ERR;
8810 }
8811 if (rewriteAppendOnlyFileBackground() == REDIS_ERR) {
8812 server.appendonly = 0;
8813 close(server.appendfd);
8814 redisLog(REDIS_WARNING,"Used tried to switch on AOF via CONFIG, I can't trigger a background AOF rewrite operation. Check the above logs for more info about the error.",strerror(errno));
8815 return REDIS_ERR;
8816 }
8817 return REDIS_OK;
8818}
8819
28ed1f33 8820/* Write the append only file buffer on disk.
8821 *
8822 * Since we are required to write the AOF before replying to the client,
8823 * and the only way the client socket can get a write is entering when the
8824 * the event loop, we accumulate all the AOF writes in a memory
8825 * buffer and write it on disk using this function just before entering
8826 * the event loop again. */
8827static void flushAppendOnlyFile(void) {
8828 time_t now;
8829 ssize_t nwritten;
8830
8831 if (sdslen(server.aofbuf) == 0) return;
8832
8833 /* We want to perform a single write. This should be guaranteed atomic
8834 * at least if the filesystem we are writing is a real physical one.
8835 * While this will save us against the server being killed I don't think
8836 * there is much to do about the whole server stopping for power problems
8837 * or alike */
8838 nwritten = write(server.appendfd,server.aofbuf,sdslen(server.aofbuf));
8839 if (nwritten != (signed)sdslen(server.aofbuf)) {
8840 /* Ooops, we are in troubles. The best thing to do for now is
8841 * aborting instead of giving the illusion that everything is
8842 * working as expected. */
8843 if (nwritten == -1) {
8844 redisLog(REDIS_WARNING,"Exiting on error writing to the append-only file: %s",strerror(errno));
8845 } else {
8846 redisLog(REDIS_WARNING,"Exiting on short write while writing to the append-only file: %s",strerror(errno));
8847 }
8848 exit(1);
8849 }
8850 sdsfree(server.aofbuf);
8851 server.aofbuf = sdsempty();
8852
38db9171 8853 /* Don't Fsync if no-appendfsync-on-rewrite is set to yes and we have
8854 * childs performing heavy I/O on disk. */
8855 if (server.no_appendfsync_on_rewrite &&
8856 (server.bgrewritechildpid != -1 || server.bgsavechildpid != -1))
8857 return;
28ed1f33 8858 /* Fsync if needed */
8859 now = time(NULL);
8860 if (server.appendfsync == APPENDFSYNC_ALWAYS ||
8861 (server.appendfsync == APPENDFSYNC_EVERYSEC &&
8862 now-server.lastfsync > 1))
8863 {
8864 /* aof_fsync is defined as fdatasync() for Linux in order to avoid
8865 * flushing metadata. */
8866 aof_fsync(server.appendfd); /* Let's try to get this data on the disk */
8867 server.lastfsync = now;
8868 }
8869}
8870
9376e434
PN
8871static sds catAppendOnlyGenericCommand(sds buf, int argc, robj **argv) {
8872 int j;
8873 buf = sdscatprintf(buf,"*%d\r\n",argc);
8874 for (j = 0; j < argc; j++) {
8875 robj *o = getDecodedObject(argv[j]);
8876 buf = sdscatprintf(buf,"$%lu\r\n",(unsigned long)sdslen(o->ptr));
8877 buf = sdscatlen(buf,o->ptr,sdslen(o->ptr));
8878 buf = sdscatlen(buf,"\r\n",2);
8879 decrRefCount(o);
8880 }
8881 return buf;
8882}
8883
8884static sds catAppendOnlyExpireAtCommand(sds buf, robj *key, robj *seconds) {
8885 int argc = 3;
8886 long when;
8887 robj *argv[3];
8888
8889 /* Make sure we can use strtol */
8890 seconds = getDecodedObject(seconds);
8891 when = time(NULL)+strtol(seconds->ptr,NULL,10);
8892 decrRefCount(seconds);
8893
8894 argv[0] = createStringObject("EXPIREAT",8);
8895 argv[1] = key;
8896 argv[2] = createObject(REDIS_STRING,
8897 sdscatprintf(sdsempty(),"%ld",when));
8898 buf = catAppendOnlyGenericCommand(buf, argc, argv);
8899 decrRefCount(argv[0]);
8900 decrRefCount(argv[2]);
8901 return buf;
8902}
8903
f80dff62 8904static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {
8905 sds buf = sdsempty();
f80dff62 8906 robj *tmpargv[3];
8907
8908 /* The DB this command was targetting is not the same as the last command
8909 * we appendend. To issue a SELECT command is needed. */
8910 if (dictid != server.appendseldb) {
8911 char seldb[64];
8912
8913 snprintf(seldb,sizeof(seldb),"%d",dictid);
682ac724 8914 buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
83c6a618 8915 (unsigned long)strlen(seldb),seldb);
f80dff62 8916 server.appendseldb = dictid;
8917 }
8918
f80dff62 8919 if (cmd->proc == expireCommand) {
9376e434
PN
8920 /* Translate EXPIRE into EXPIREAT */
8921 buf = catAppendOnlyExpireAtCommand(buf,argv[1],argv[2]);
8922 } else if (cmd->proc == setexCommand) {
8923 /* Translate SETEX to SET and EXPIREAT */
8924 tmpargv[0] = createStringObject("SET",3);
f80dff62 8925 tmpargv[1] = argv[1];
9376e434
PN
8926 tmpargv[2] = argv[3];
8927 buf = catAppendOnlyGenericCommand(buf,3,tmpargv);
8928 decrRefCount(tmpargv[0]);
8929 buf = catAppendOnlyExpireAtCommand(buf,argv[1],argv[2]);
8930 } else {
8931 buf = catAppendOnlyGenericCommand(buf,argc,argv);
f80dff62 8932 }
8933
28ed1f33 8934 /* Append to the AOF buffer. This will be flushed on disk just before
8935 * of re-entering the event loop, so before the client will get a
8936 * positive reply about the operation performed. */
8937 server.aofbuf = sdscatlen(server.aofbuf,buf,sdslen(buf));
8938
85a83172 8939 /* If a background append only file rewriting is in progress we want to
8940 * accumulate the differences between the child DB and the current one
8941 * in a buffer, so that when the child process will do its work we
8942 * can append the differences to the new append only file. */
8943 if (server.bgrewritechildpid != -1)
8944 server.bgrewritebuf = sdscatlen(server.bgrewritebuf,buf,sdslen(buf));
8945
8946 sdsfree(buf);
f80dff62 8947}
8948
8949/* In Redis commands are always executed in the context of a client, so in
8950 * order to load the append only file we need to create a fake client. */
8951static struct redisClient *createFakeClient(void) {
8952 struct redisClient *c = zmalloc(sizeof(*c));
8953
8954 selectDb(c,0);
8955 c->fd = -1;
8956 c->querybuf = sdsempty();
8957 c->argc = 0;
8958 c->argv = NULL;
8959 c->flags = 0;
9387d17d 8960 /* We set the fake client as a slave waiting for the synchronization
8961 * so that Redis will not try to send replies to this client. */
8962 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
f80dff62 8963 c->reply = listCreate();
8964 listSetFreeMethod(c->reply,decrRefCount);
8965 listSetDupMethod(c->reply,dupClientReplyValue);
4132ad8d 8966 initClientMultiState(c);
f80dff62 8967 return c;
8968}
8969
8970static void freeFakeClient(struct redisClient *c) {
8971 sdsfree(c->querybuf);
8972 listRelease(c->reply);
4132ad8d 8973 freeClientMultiState(c);
f80dff62 8974 zfree(c);
8975}
8976
8977/* Replay the append log file. On error REDIS_OK is returned. On non fatal
8978 * error (the append only file is zero-length) REDIS_ERR is returned. On
8979 * fatal error an error message is logged and the program exists. */
8980int loadAppendOnlyFile(char *filename) {
8981 struct redisClient *fakeClient;
8982 FILE *fp = fopen(filename,"r");
8983 struct redis_stat sb;
4132ad8d 8984 int appendonly = server.appendonly;
f80dff62 8985
8986 if (redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0)
8987 return REDIS_ERR;
8988
8989 if (fp == NULL) {
8990 redisLog(REDIS_WARNING,"Fatal error: can't open the append log file for reading: %s",strerror(errno));
8991 exit(1);
8992 }
8993
4132ad8d
PN
8994 /* Temporarily disable AOF, to prevent EXEC from feeding a MULTI
8995 * to the same file we're about to read. */
8996 server.appendonly = 0;
8997
f80dff62 8998 fakeClient = createFakeClient();
8999 while(1) {
9000 int argc, j;
9001 unsigned long len;
9002 robj **argv;
9003 char buf[128];
9004 sds argsds;
9005 struct redisCommand *cmd;
a89b7013 9006 int force_swapout;
f80dff62 9007
9008 if (fgets(buf,sizeof(buf),fp) == NULL) {
9009 if (feof(fp))
9010 break;
9011 else
9012 goto readerr;
9013 }
9014 if (buf[0] != '*') goto fmterr;
9015 argc = atoi(buf+1);
9016 argv = zmalloc(sizeof(robj*)*argc);
9017 for (j = 0; j < argc; j++) {
9018 if (fgets(buf,sizeof(buf),fp) == NULL) goto readerr;
9019 if (buf[0] != '$') goto fmterr;
9020 len = strtol(buf+1,NULL,10);
9021 argsds = sdsnewlen(NULL,len);
0f151ef1 9022 if (len && fread(argsds,len,1,fp) == 0) goto fmterr;
f80dff62 9023 argv[j] = createObject(REDIS_STRING,argsds);
9024 if (fread(buf,2,1,fp) == 0) goto fmterr; /* discard CRLF */
9025 }
9026
9027 /* Command lookup */
9028 cmd = lookupCommand(argv[0]->ptr);
9029 if (!cmd) {
9030 redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", argv[0]->ptr);
9031 exit(1);
9032 }
bdcb92f2 9033 /* Try object encoding */
f80dff62 9034 if (cmd->flags & REDIS_CMD_BULK)
05df7621 9035 argv[argc-1] = tryObjectEncoding(argv[argc-1]);
f80dff62 9036 /* Run the command in the context of a fake client */
9037 fakeClient->argc = argc;
9038 fakeClient->argv = argv;
9039 cmd->proc(fakeClient);
9040 /* Discard the reply objects list from the fake client */
9041 while(listLength(fakeClient->reply))
9042 listDelNode(fakeClient->reply,listFirst(fakeClient->reply));
9043 /* Clean up, ready for the next command */
9044 for (j = 0; j < argc; j++) decrRefCount(argv[j]);
9045 zfree(argv);
b492cf00 9046 /* Handle swapping while loading big datasets when VM is on */
a89b7013 9047 force_swapout = 0;
9048 if ((zmalloc_used_memory() - server.vm_max_memory) > 1024*1024*32)
9049 force_swapout = 1;
9050
9051 if (server.vm_enabled && force_swapout) {
b492cf00 9052 while (zmalloc_used_memory() > server.vm_max_memory) {
a69a0c9c 9053 if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
b492cf00 9054 }
9055 }
f80dff62 9056 }
4132ad8d
PN
9057
9058 /* This point can only be reached when EOF is reached without errors.
9059 * If the client is in the middle of a MULTI/EXEC, log error and quit. */
9060 if (fakeClient->flags & REDIS_MULTI) goto readerr;
9061
f80dff62 9062 fclose(fp);
9063 freeFakeClient(fakeClient);
4132ad8d 9064 server.appendonly = appendonly;
f80dff62 9065 return REDIS_OK;
9066
9067readerr:
9068 if (feof(fp)) {
9069 redisLog(REDIS_WARNING,"Unexpected end of file reading the append only file");
9070 } else {
9071 redisLog(REDIS_WARNING,"Unrecoverable error reading the append only file: %s", strerror(errno));
9072 }
9073 exit(1);
9074fmterr:
9075 redisLog(REDIS_WARNING,"Bad file format reading the append only file");
9076 exit(1);
9077}
9078
9c8e3cee 9079/* Write binary-safe string into a file in the bulkformat
9080 * $<count>\r\n<payload>\r\n */
9081static int fwriteBulkString(FILE *fp, char *s, unsigned long len) {
9eaef89f
PN
9082 char cbuf[128];
9083 int clen;
9084 cbuf[0] = '$';
9085 clen = 1+ll2string(cbuf+1,sizeof(cbuf)-1,len);
9086 cbuf[clen++] = '\r';
9087 cbuf[clen++] = '\n';
9088 if (fwrite(cbuf,clen,1,fp) == 0) return 0;
9089 if (len > 0 && fwrite(s,len,1,fp) == 0) return 0;
9c8e3cee 9090 if (fwrite("\r\n",2,1,fp) == 0) return 0;
9091 return 1;
9092}
9093
9d65a1bb 9094/* Write a double value in bulk format $<count>\r\n<payload>\r\n */
9095static int fwriteBulkDouble(FILE *fp, double d) {
9096 char buf[128], dbuf[128];
9097
9098 snprintf(dbuf,sizeof(dbuf),"%.17g\r\n",d);
9099 snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(dbuf)-2);
9100 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
9101 if (fwrite(dbuf,strlen(dbuf),1,fp) == 0) return 0;
9102 return 1;
9103}
9104
9105/* Write a long value in bulk format $<count>\r\n<payload>\r\n */
9eaef89f
PN
9106static int fwriteBulkLongLong(FILE *fp, long long l) {
9107 char bbuf[128], lbuf[128];
9108 unsigned int blen, llen;
9109 llen = ll2string(lbuf,32,l);
9110 blen = snprintf(bbuf,sizeof(bbuf),"$%u\r\n%s\r\n",llen,lbuf);
9111 if (fwrite(bbuf,blen,1,fp) == 0) return 0;
9d65a1bb 9112 return 1;
9113}
9114
9eaef89f
PN
9115/* Delegate writing an object to writing a bulk string or bulk long long. */
9116static int fwriteBulkObject(FILE *fp, robj *obj) {
9117 /* Avoid using getDecodedObject to help copy-on-write (we are often
9118 * in a child process when this function is called). */
9119 if (obj->encoding == REDIS_ENCODING_INT) {
9120 return fwriteBulkLongLong(fp,(long)obj->ptr);
9121 } else if (obj->encoding == REDIS_ENCODING_RAW) {
9122 return fwriteBulkString(fp,obj->ptr,sdslen(obj->ptr));
9123 } else {
9124 redisPanic("Unknown string encoding");
9125 }
9126}
9127
9d65a1bb 9128/* Write a sequence of commands able to fully rebuild the dataset into
9129 * "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
9130static int rewriteAppendOnlyFile(char *filename) {
9131 dictIterator *di = NULL;
9132 dictEntry *de;
9133 FILE *fp;
9134 char tmpfile[256];
9135 int j;
9136 time_t now = time(NULL);
9137
9138 /* Note that we have to use a different temp name here compared to the
9139 * one used by rewriteAppendOnlyFileBackground() function. */
9140 snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid());
9141 fp = fopen(tmpfile,"w");
9142 if (!fp) {
9143 redisLog(REDIS_WARNING, "Failed rewriting the append only file: %s", strerror(errno));
9144 return REDIS_ERR;
9145 }
9146 for (j = 0; j < server.dbnum; j++) {
9147 char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n";
9148 redisDb *db = server.db+j;
9149 dict *d = db->dict;
9150 if (dictSize(d) == 0) continue;
9151 di = dictGetIterator(d);
9152 if (!di) {
9153 fclose(fp);
9154 return REDIS_ERR;
9155 }
9156
9157 /* SELECT the new DB */
9158 if (fwrite(selectcmd,sizeof(selectcmd)-1,1,fp) == 0) goto werr;
9eaef89f 9159 if (fwriteBulkLongLong(fp,j) == 0) goto werr;
9d65a1bb 9160
9161 /* Iterate this DB writing every entry */
9162 while((de = dictNext(di)) != NULL) {
09241813 9163 sds keystr = dictGetEntryKey(de);
9164 robj key, *o;
e7546c63 9165 time_t expiretime;
9166 int swapped;
9167
09241813 9168 keystr = dictGetEntryKey(de);
560db612 9169 o = dictGetEntryVal(de);
09241813 9170 initStaticStringObject(key,keystr);
b9bc0eef 9171 /* If the value for this key is swapped, load a preview in memory.
9172 * We use a "swapped" flag to remember if we need to free the
9173 * value object instead to just increment the ref count anyway
9174 * in order to avoid copy-on-write of pages if we are forked() */
560db612 9175 if (!server.vm_enabled || o->storage == REDIS_VM_MEMORY ||
9176 o->storage == REDIS_VM_SWAPPING) {
e7546c63 9177 swapped = 0;
9178 } else {
560db612 9179 o = vmPreviewObject(o);
e7546c63 9180 swapped = 1;
9181 }
09241813 9182 expiretime = getExpire(db,&key);
9d65a1bb 9183
9184 /* Save the key and associated value */
9d65a1bb 9185 if (o->type == REDIS_STRING) {
9186 /* Emit a SET command */
9187 char cmd[]="*3\r\n$3\r\nSET\r\n";
9188 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
9189 /* Key and value */
09241813 9190 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9191 if (fwriteBulkObject(fp,o) == 0) goto werr;
9d65a1bb 9192 } else if (o->type == REDIS_LIST) {
9193 /* Emit the RPUSHes needed to rebuild the list */
6ddc908a
PN
9194 char cmd[]="*3\r\n$5\r\nRPUSH\r\n";
9195 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
9196 unsigned char *zl = o->ptr;
9197 unsigned char *p = ziplistIndex(zl,0);
9198 unsigned char *vstr;
9199 unsigned int vlen;
9200 long long vlong;
9201
9202 while(ziplistGet(p,&vstr,&vlen,&vlong)) {
9203 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
846d8b3e 9204 if (fwriteBulkObject(fp,&key) == 0) goto werr;
6ddc908a
PN
9205 if (vstr) {
9206 if (fwriteBulkString(fp,(char*)vstr,vlen) == 0)
9207 goto werr;
9208 } else {
9209 if (fwriteBulkLongLong(fp,vlong) == 0)
9210 goto werr;
9211 }
9212 p = ziplistNext(zl,p);
9213 }
9214 } else if (o->encoding == REDIS_ENCODING_LIST) {
9215 list *list = o->ptr;
9216 listNode *ln;
9217 listIter li;
9218
9219 listRewind(list,&li);
9220 while((ln = listNext(&li))) {
9221 robj *eleobj = listNodeValue(ln);
9222
9223 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
846d8b3e 9224 if (fwriteBulkObject(fp,&key) == 0) goto werr;
6ddc908a
PN
9225 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
9226 }
9227 } else {
9228 redisPanic("Unknown list encoding");
9d65a1bb 9229 }
9230 } else if (o->type == REDIS_SET) {
9231 /* Emit the SADDs needed to rebuild the set */
9232 dict *set = o->ptr;
9233 dictIterator *di = dictGetIterator(set);
9234 dictEntry *de;
9235
9236 while((de = dictNext(di)) != NULL) {
9237 char cmd[]="*3\r\n$4\r\nSADD\r\n";
9238 robj *eleobj = dictGetEntryKey(de);
9239
9240 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9241 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9242 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
9d65a1bb 9243 }
9244 dictReleaseIterator(di);
9245 } else if (o->type == REDIS_ZSET) {
9246 /* Emit the ZADDs needed to rebuild the sorted set */
9247 zset *zs = o->ptr;
9248 dictIterator *di = dictGetIterator(zs->dict);
9249 dictEntry *de;
9250
9251 while((de = dictNext(di)) != NULL) {
9252 char cmd[]="*4\r\n$4\r\nZADD\r\n";
9253 robj *eleobj = dictGetEntryKey(de);
9254 double *score = dictGetEntryVal(de);
9255
9256 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9257 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9d65a1bb 9258 if (fwriteBulkDouble(fp,*score) == 0) goto werr;
9c8e3cee 9259 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
9d65a1bb 9260 }
9261 dictReleaseIterator(di);
9c8e3cee 9262 } else if (o->type == REDIS_HASH) {
9263 char cmd[]="*4\r\n$4\r\nHSET\r\n";
9264
9265 /* Emit the HSETs needed to rebuild the hash */
9266 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
9267 unsigned char *p = zipmapRewind(o->ptr);
9268 unsigned char *field, *val;
9269 unsigned int flen, vlen;
9270
9271 while((p = zipmapNext(p,&field,&flen,&val,&vlen)) != NULL) {
9272 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9273 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9274 if (fwriteBulkString(fp,(char*)field,flen) == -1)
9275 return -1;
9276 if (fwriteBulkString(fp,(char*)val,vlen) == -1)
9277 return -1;
9278 }
9279 } else {
9280 dictIterator *di = dictGetIterator(o->ptr);
9281 dictEntry *de;
9282
9283 while((de = dictNext(di)) != NULL) {
9284 robj *field = dictGetEntryKey(de);
9285 robj *val = dictGetEntryVal(de);
9286
9287 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9288 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9289 if (fwriteBulkObject(fp,field) == -1) return -1;
9290 if (fwriteBulkObject(fp,val) == -1) return -1;
9291 }
9292 dictReleaseIterator(di);
9293 }
9d65a1bb 9294 } else {
f83c6cb5 9295 redisPanic("Unknown object type");
9d65a1bb 9296 }
9297 /* Save the expire time */
9298 if (expiretime != -1) {
e96e4fbf 9299 char cmd[]="*3\r\n$8\r\nEXPIREAT\r\n";
9d65a1bb 9300 /* If this key is already expired skip it */
9301 if (expiretime < now) continue;
9302 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9303 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9eaef89f 9304 if (fwriteBulkLongLong(fp,expiretime) == 0) goto werr;
9d65a1bb 9305 }
b9bc0eef 9306 if (swapped) decrRefCount(o);
9d65a1bb 9307 }
9308 dictReleaseIterator(di);
9309 }
9310
9311 /* Make sure data will not remain on the OS's output buffers */
9312 fflush(fp);
b0bd87f6 9313 aof_fsync(fileno(fp));
9d65a1bb 9314 fclose(fp);
e0a62c7f 9315
9d65a1bb 9316 /* Use RENAME to make sure the DB file is changed atomically only
9317 * if the generate DB file is ok. */
9318 if (rename(tmpfile,filename) == -1) {
9319 redisLog(REDIS_WARNING,"Error moving temp append only file on the final destination: %s", strerror(errno));
9320 unlink(tmpfile);
9321 return REDIS_ERR;
9322 }
9323 redisLog(REDIS_NOTICE,"SYNC append only file rewrite performed");
9324 return REDIS_OK;
9325
9326werr:
9327 fclose(fp);
9328 unlink(tmpfile);
e96e4fbf 9329 redisLog(REDIS_WARNING,"Write error writing append only file on disk: %s", strerror(errno));
9d65a1bb 9330 if (di) dictReleaseIterator(di);
9331 return REDIS_ERR;
9332}
9333
9334/* This is how rewriting of the append only file in background works:
9335 *
9336 * 1) The user calls BGREWRITEAOF
9337 * 2) Redis calls this function, that forks():
9338 * 2a) the child rewrite the append only file in a temp file.
9339 * 2b) the parent accumulates differences in server.bgrewritebuf.
9340 * 3) When the child finished '2a' exists.
9341 * 4) The parent will trap the exit code, if it's OK, will append the
9342 * data accumulated into server.bgrewritebuf into the temp file, and
9343 * finally will rename(2) the temp file in the actual file name.
9344 * The the new file is reopened as the new append only file. Profit!
9345 */
9346static int rewriteAppendOnlyFileBackground(void) {
9347 pid_t childpid;
9348
9349 if (server.bgrewritechildpid != -1) return REDIS_ERR;
054e426d 9350 if (server.vm_enabled) waitEmptyIOJobsQueue();
9d65a1bb 9351 if ((childpid = fork()) == 0) {
9352 /* Child */
9353 char tmpfile[256];
9d65a1bb 9354
054e426d 9355 if (server.vm_enabled) vmReopenSwapFile();
9356 close(server.fd);
9d65a1bb 9357 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
9358 if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
478c2c6f 9359 _exit(0);
9d65a1bb 9360 } else {
478c2c6f 9361 _exit(1);
9d65a1bb 9362 }
9363 } else {
9364 /* Parent */
9365 if (childpid == -1) {
9366 redisLog(REDIS_WARNING,
9367 "Can't rewrite append only file in background: fork: %s",
9368 strerror(errno));
9369 return REDIS_ERR;
9370 }
9371 redisLog(REDIS_NOTICE,
9372 "Background append only file rewriting started by pid %d",childpid);
9373 server.bgrewritechildpid = childpid;
884d4b39 9374 updateDictResizePolicy();
85a83172 9375 /* We set appendseldb to -1 in order to force the next call to the
9376 * feedAppendOnlyFile() to issue a SELECT command, so the differences
9377 * accumulated by the parent into server.bgrewritebuf will start
9378 * with a SELECT statement and it will be safe to merge. */
9379 server.appendseldb = -1;
9d65a1bb 9380 return REDIS_OK;
9381 }
9382 return REDIS_OK; /* unreached */
9383}
9384
9385static void bgrewriteaofCommand(redisClient *c) {
9386 if (server.bgrewritechildpid != -1) {
9387 addReplySds(c,sdsnew("-ERR background append only file rewriting already in progress\r\n"));
9388 return;
9389 }
9390 if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
49b99ab4 9391 char *status = "+Background append only file rewriting started\r\n";
9392 addReplySds(c,sdsnew(status));
9d65a1bb 9393 } else {
9394 addReply(c,shared.err);
9395 }
9396}
9397
9398static void aofRemoveTempFile(pid_t childpid) {
9399 char tmpfile[256];
9400
9401 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) childpid);
9402 unlink(tmpfile);
9403}
9404
996cb5f7 9405/* Virtual Memory is composed mainly of two subsystems:
9406 * - Blocking Virutal Memory
9407 * - Threaded Virtual Memory I/O
9408 * The two parts are not fully decoupled, but functions are split among two
9409 * different sections of the source code (delimited by comments) in order to
9410 * make more clear what functionality is about the blocking VM and what about
9411 * the threaded (not blocking) VM.
9412 *
9413 * Redis VM design:
9414 *
9415 * Redis VM is a blocking VM (one that blocks reading swapped values from
9416 * disk into memory when a value swapped out is needed in memory) that is made
9417 * unblocking by trying to examine the command argument vector in order to
9418 * load in background values that will likely be needed in order to exec
9419 * the command. The command is executed only once all the relevant keys
9420 * are loaded into memory.
9421 *
9422 * This basically is almost as simple of a blocking VM, but almost as parallel
9423 * as a fully non-blocking VM.
9424 */
9425
560db612 9426/* =================== Virtual Memory - Blocking Side ====================== */
2e5eb04e 9427
560db612 9428/* Create a VM pointer object. This kind of objects are used in place of
9429 * values in the key -> value hash table, for swapped out objects. */
9430static vmpointer *createVmPointer(int vtype) {
9431 vmpointer *vp = zmalloc(sizeof(vmpointer));
2e5eb04e 9432
560db612 9433 vp->type = REDIS_VMPOINTER;
9434 vp->storage = REDIS_VM_SWAPPED;
9435 vp->vtype = vtype;
9436 return vp;
2e5eb04e 9437}
9438
75680a3c 9439static void vmInit(void) {
9440 off_t totsize;
996cb5f7 9441 int pipefds[2];
bcaa7a4f 9442 size_t stacksize;
8b5bb414 9443 struct flock fl;
75680a3c 9444
4ad37480 9445 if (server.vm_max_threads != 0)
9446 zmalloc_enable_thread_safeness(); /* we need thread safe zmalloc() */
9447
054e426d 9448 redisLog(REDIS_NOTICE,"Using '%s' as swap file",server.vm_swap_file);
8b5bb414 9449 /* Try to open the old swap file, otherwise create it */
6fa987e3 9450 if ((server.vm_fp = fopen(server.vm_swap_file,"r+b")) == NULL) {
9451 server.vm_fp = fopen(server.vm_swap_file,"w+b");
9452 }
75680a3c 9453 if (server.vm_fp == NULL) {
6fa987e3 9454 redisLog(REDIS_WARNING,
8b5bb414 9455 "Can't open the swap file: %s. Exiting.",
6fa987e3 9456 strerror(errno));
75680a3c 9457 exit(1);
9458 }
9459 server.vm_fd = fileno(server.vm_fp);
8b5bb414 9460 /* Lock the swap file for writing, this is useful in order to avoid
9461 * another instance to use the same swap file for a config error. */
9462 fl.l_type = F_WRLCK;
9463 fl.l_whence = SEEK_SET;
9464 fl.l_start = fl.l_len = 0;
9465 if (fcntl(server.vm_fd,F_SETLK,&fl) == -1) {
9466 redisLog(REDIS_WARNING,
9467 "Can't lock the swap file at '%s': %s. Make sure it is not used by another Redis instance.", server.vm_swap_file, strerror(errno));
9468 exit(1);
9469 }
9470 /* Initialize */
75680a3c 9471 server.vm_next_page = 0;
9472 server.vm_near_pages = 0;
7d98e08c 9473 server.vm_stats_used_pages = 0;
9474 server.vm_stats_swapped_objects = 0;
9475 server.vm_stats_swapouts = 0;
9476 server.vm_stats_swapins = 0;
75680a3c 9477 totsize = server.vm_pages*server.vm_page_size;
9478 redisLog(REDIS_NOTICE,"Allocating %lld bytes of swap file",totsize);
9479 if (ftruncate(server.vm_fd,totsize) == -1) {
9480 redisLog(REDIS_WARNING,"Can't ftruncate swap file: %s. Exiting.",
9481 strerror(errno));
9482 exit(1);
9483 } else {
9484 redisLog(REDIS_NOTICE,"Swap file allocated with success");
9485 }
7d30035d 9486 server.vm_bitmap = zmalloc((server.vm_pages+7)/8);
f870935d 9487 redisLog(REDIS_VERBOSE,"Allocated %lld bytes page table for %lld pages",
4ef8de8a 9488 (long long) (server.vm_pages+7)/8, server.vm_pages);
7d30035d 9489 memset(server.vm_bitmap,0,(server.vm_pages+7)/8);
92f8e882 9490
996cb5f7 9491 /* Initialize threaded I/O (used by Virtual Memory) */
9492 server.io_newjobs = listCreate();
9493 server.io_processing = listCreate();
9494 server.io_processed = listCreate();
d5d55fc3 9495 server.io_ready_clients = listCreate();
92f8e882 9496 pthread_mutex_init(&server.io_mutex,NULL);
a5819310 9497 pthread_mutex_init(&server.obj_freelist_mutex,NULL);
9498 pthread_mutex_init(&server.io_swapfile_mutex,NULL);
92f8e882 9499 server.io_active_threads = 0;
996cb5f7 9500 if (pipe(pipefds) == -1) {
9501 redisLog(REDIS_WARNING,"Unable to intialized VM: pipe(2): %s. Exiting."
9502 ,strerror(errno));
9503 exit(1);
9504 }
9505 server.io_ready_pipe_read = pipefds[0];
9506 server.io_ready_pipe_write = pipefds[1];
9507 redisAssert(anetNonBlock(NULL,server.io_ready_pipe_read) != ANET_ERR);
bcaa7a4f 9508 /* LZF requires a lot of stack */
9509 pthread_attr_init(&server.io_threads_attr);
9510 pthread_attr_getstacksize(&server.io_threads_attr, &stacksize);
9511 while (stacksize < REDIS_THREAD_STACK_SIZE) stacksize *= 2;
9512 pthread_attr_setstacksize(&server.io_threads_attr, stacksize);
b9bc0eef 9513 /* Listen for events in the threaded I/O pipe */
9514 if (aeCreateFileEvent(server.el, server.io_ready_pipe_read, AE_READABLE,
9515 vmThreadedIOCompletedJob, NULL) == AE_ERR)
9516 oom("creating file event");
75680a3c 9517}
9518
06224fec 9519/* Mark the page as used */
9520static void vmMarkPageUsed(off_t page) {
9521 off_t byte = page/8;
9522 int bit = page&7;
970e10bb 9523 redisAssert(vmFreePage(page) == 1);
06224fec 9524 server.vm_bitmap[byte] |= 1<<bit;
9525}
9526
9527/* Mark N contiguous pages as used, with 'page' being the first. */
9528static void vmMarkPagesUsed(off_t page, off_t count) {
9529 off_t j;
9530
9531 for (j = 0; j < count; j++)
7d30035d 9532 vmMarkPageUsed(page+j);
7d98e08c 9533 server.vm_stats_used_pages += count;
7c775e09 9534 redisLog(REDIS_DEBUG,"Mark USED pages: %lld pages at %lld\n",
9535 (long long)count, (long long)page);
06224fec 9536}
9537
9538/* Mark the page as free */
9539static void vmMarkPageFree(off_t page) {
9540 off_t byte = page/8;
9541 int bit = page&7;
970e10bb 9542 redisAssert(vmFreePage(page) == 0);
06224fec 9543 server.vm_bitmap[byte] &= ~(1<<bit);
9544}
9545
9546/* Mark N contiguous pages as free, with 'page' being the first. */
9547static void vmMarkPagesFree(off_t page, off_t count) {
9548 off_t j;
9549
9550 for (j = 0; j < count; j++)
7d30035d 9551 vmMarkPageFree(page+j);
7d98e08c 9552 server.vm_stats_used_pages -= count;
7c775e09 9553 redisLog(REDIS_DEBUG,"Mark FREE pages: %lld pages at %lld\n",
9554 (long long)count, (long long)page);
06224fec 9555}
9556
9557/* Test if the page is free */
9558static int vmFreePage(off_t page) {
9559 off_t byte = page/8;
9560 int bit = page&7;
7d30035d 9561 return (server.vm_bitmap[byte] & (1<<bit)) == 0;
06224fec 9562}
9563
9564/* Find N contiguous free pages storing the first page of the cluster in *first.
e0a62c7f 9565 * Returns REDIS_OK if it was able to find N contiguous pages, otherwise
3a66edc7 9566 * REDIS_ERR is returned.
06224fec 9567 *
9568 * This function uses a simple algorithm: we try to allocate
9569 * REDIS_VM_MAX_NEAR_PAGES sequentially, when we reach this limit we start
9570 * again from the start of the swap file searching for free spaces.
9571 *
9572 * If it looks pretty clear that there are no free pages near our offset
9573 * we try to find less populated places doing a forward jump of
9574 * REDIS_VM_MAX_RANDOM_JUMP, then we start scanning again a few pages
9575 * without hurry, and then we jump again and so forth...
e0a62c7f 9576 *
06224fec 9577 * This function can be improved using a free list to avoid to guess
9578 * too much, since we could collect data about freed pages.
9579 *
9580 * note: I implemented this function just after watching an episode of
9581 * Battlestar Galactica, where the hybrid was continuing to say "JUMP!"
9582 */
c7df85a4 9583static int vmFindContiguousPages(off_t *first, off_t n) {
06224fec 9584 off_t base, offset = 0, since_jump = 0, numfree = 0;
9585
9586 if (server.vm_near_pages == REDIS_VM_MAX_NEAR_PAGES) {
9587 server.vm_near_pages = 0;
9588 server.vm_next_page = 0;
9589 }
9590 server.vm_near_pages++; /* Yet another try for pages near to the old ones */
9591 base = server.vm_next_page;
9592
9593 while(offset < server.vm_pages) {
9594 off_t this = base+offset;
9595
9596 /* If we overflow, restart from page zero */
9597 if (this >= server.vm_pages) {
9598 this -= server.vm_pages;
9599 if (this == 0) {
9600 /* Just overflowed, what we found on tail is no longer
9601 * interesting, as it's no longer contiguous. */
9602 numfree = 0;
9603 }
9604 }
9605 if (vmFreePage(this)) {
9606 /* This is a free page */
9607 numfree++;
9608 /* Already got N free pages? Return to the caller, with success */
9609 if (numfree == n) {
7d30035d 9610 *first = this-(n-1);
9611 server.vm_next_page = this+1;
7c775e09 9612 redisLog(REDIS_DEBUG, "FOUND CONTIGUOUS PAGES: %lld pages at %lld\n", (long long) n, (long long) *first);
3a66edc7 9613 return REDIS_OK;
06224fec 9614 }
9615 } else {
9616 /* The current one is not a free page */
9617 numfree = 0;
9618 }
9619
9620 /* Fast-forward if the current page is not free and we already
9621 * searched enough near this place. */
9622 since_jump++;
9623 if (!numfree && since_jump >= REDIS_VM_MAX_RANDOM_JUMP/4) {
9624 offset += random() % REDIS_VM_MAX_RANDOM_JUMP;
9625 since_jump = 0;
9626 /* Note that even if we rewind after the jump, we are don't need
9627 * to make sure numfree is set to zero as we only jump *if* it
9628 * is set to zero. */
9629 } else {
9630 /* Otherwise just check the next page */
9631 offset++;
9632 }
9633 }
3a66edc7 9634 return REDIS_ERR;
9635}
9636
a5819310 9637/* Write the specified object at the specified page of the swap file */
9638static int vmWriteObjectOnSwap(robj *o, off_t page) {
9639 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
9640 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
9641 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
9642 redisLog(REDIS_WARNING,
9ebed7cf 9643 "Critical VM problem in vmWriteObjectOnSwap(): can't seek: %s",
a5819310 9644 strerror(errno));
9645 return REDIS_ERR;
9646 }
9647 rdbSaveObject(server.vm_fp,o);
ba76a8f9 9648 fflush(server.vm_fp);
a5819310 9649 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
9650 return REDIS_OK;
9651}
9652
a4798f73 9653/* Transfers the 'val' object to disk. Store all the information
9654 * a 'vmpointer' object containing all the information needed to load the
9655 * object back later is returned.
9656 *
3a66edc7 9657 * If we can't find enough contiguous empty pages to swap the object on disk
a4798f73 9658 * NULL is returned. */
560db612 9659static vmpointer *vmSwapObjectBlocking(robj *val) {
b9bc0eef 9660 off_t pages = rdbSavedObjectPages(val,NULL);
3a66edc7 9661 off_t page;
560db612 9662 vmpointer *vp;
3a66edc7 9663
560db612 9664 assert(val->storage == REDIS_VM_MEMORY);
9665 assert(val->refcount == 1);
9666 if (vmFindContiguousPages(&page,pages) == REDIS_ERR) return NULL;
9667 if (vmWriteObjectOnSwap(val,page) == REDIS_ERR) return NULL;
9668
9669 vp = createVmPointer(val->type);
9670 vp->page = page;
9671 vp->usedpages = pages;
3a66edc7 9672 decrRefCount(val); /* Deallocate the object from memory. */
9673 vmMarkPagesUsed(page,pages);
560db612 9674 redisLog(REDIS_DEBUG,"VM: object %p swapped out at %lld (%lld pages)",
9675 (void*) val,
7d30035d 9676 (unsigned long long) page, (unsigned long long) pages);
7d98e08c 9677 server.vm_stats_swapped_objects++;
9678 server.vm_stats_swapouts++;
560db612 9679 return vp;
3a66edc7 9680}
9681
a5819310 9682static robj *vmReadObjectFromSwap(off_t page, int type) {
9683 robj *o;
3a66edc7 9684
a5819310 9685 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
9686 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
3a66edc7 9687 redisLog(REDIS_WARNING,
d5d55fc3 9688 "Unrecoverable VM problem in vmReadObjectFromSwap(): can't seek: %s",
3a66edc7 9689 strerror(errno));
478c2c6f 9690 _exit(1);
3a66edc7 9691 }
a5819310 9692 o = rdbLoadObject(type,server.vm_fp);
9693 if (o == NULL) {
d5d55fc3 9694 redisLog(REDIS_WARNING, "Unrecoverable VM problem in vmReadObjectFromSwap(): can't load object from swap file: %s", strerror(errno));
478c2c6f 9695 _exit(1);
3a66edc7 9696 }
a5819310 9697 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
9698 return o;
9699}
9700
560db612 9701/* Load the specified object from swap to memory.
a5819310 9702 * The newly allocated object is returned.
9703 *
9704 * If preview is true the unserialized object is returned to the caller but
560db612 9705 * the pages are not marked as freed, nor the vp object is freed. */
9706static robj *vmGenericLoadObject(vmpointer *vp, int preview) {
a5819310 9707 robj *val;
9708
560db612 9709 redisAssert(vp->type == REDIS_VMPOINTER &&
9710 (vp->storage == REDIS_VM_SWAPPED || vp->storage == REDIS_VM_LOADING));
9711 val = vmReadObjectFromSwap(vp->page,vp->vtype);
7e69548d 9712 if (!preview) {
560db612 9713 redisLog(REDIS_DEBUG, "VM: object %p loaded from disk", (void*)vp);
9714 vmMarkPagesFree(vp->page,vp->usedpages);
9715 zfree(vp);
7d98e08c 9716 server.vm_stats_swapped_objects--;
38aba9a1 9717 } else {
560db612 9718 redisLog(REDIS_DEBUG, "VM: object %p previewed from disk", (void*)vp);
7e69548d 9719 }
7d98e08c 9720 server.vm_stats_swapins++;
3a66edc7 9721 return val;
06224fec 9722}
9723
560db612 9724/* Plain object loading, from swap to memory.
9725 *
9726 * 'o' is actually a redisVmPointer structure that will be freed by the call.
9727 * The return value is the loaded object. */
9728static robj *vmLoadObject(robj *o) {
996cb5f7 9729 /* If we are loading the object in background, stop it, we
9730 * need to load this object synchronously ASAP. */
560db612 9731 if (o->storage == REDIS_VM_LOADING)
9732 vmCancelThreadedIOJob(o);
9733 return vmGenericLoadObject((vmpointer*)o,0);
7e69548d 9734}
9735
9736/* Just load the value on disk, without to modify the key.
9737 * This is useful when we want to perform some operation on the value
9738 * without to really bring it from swap to memory, like while saving the
9739 * dataset or rewriting the append only log. */
560db612 9740static robj *vmPreviewObject(robj *o) {
9741 return vmGenericLoadObject((vmpointer*)o,1);
7e69548d 9742}
9743
4ef8de8a 9744/* How a good candidate is this object for swapping?
9745 * The better candidate it is, the greater the returned value.
9746 *
9747 * Currently we try to perform a fast estimation of the object size in
9748 * memory, and combine it with aging informations.
9749 *
9750 * Basically swappability = idle-time * log(estimated size)
9751 *
9752 * Bigger objects are preferred over smaller objects, but not
9753 * proportionally, this is why we use the logarithm. This algorithm is
9754 * just a first try and will probably be tuned later. */
9755static double computeObjectSwappability(robj *o) {
560db612 9756 /* actual age can be >= minage, but not < minage. As we use wrapping
9757 * 21 bit clocks with minutes resolution for the LRU. */
9758 time_t minage = abs(server.lruclock - o->lru);
4ef8de8a 9759 long asize = 0;
9760 list *l;
9761 dict *d;
9762 struct dictEntry *de;
9763 int z;
9764
560db612 9765 if (minage <= 0) return 0;
4ef8de8a 9766 switch(o->type) {
9767 case REDIS_STRING:
9768 if (o->encoding != REDIS_ENCODING_RAW) {
9769 asize = sizeof(*o);
9770 } else {
9771 asize = sdslen(o->ptr)+sizeof(*o)+sizeof(long)*2;
9772 }
9773 break;
9774 case REDIS_LIST:
9775 l = o->ptr;
9776 listNode *ln = listFirst(l);
9777
9778 asize = sizeof(list);
9779 if (ln) {
9780 robj *ele = ln->value;
9781 long elesize;
9782
9783 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
560db612 9784 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
4ef8de8a 9785 asize += (sizeof(listNode)+elesize)*listLength(l);
9786 }
9787 break;
9788 case REDIS_SET:
9789 case REDIS_ZSET:
9790 z = (o->type == REDIS_ZSET);
9791 d = z ? ((zset*)o->ptr)->dict : o->ptr;
9792
9793 asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
9794 if (z) asize += sizeof(zset)-sizeof(dict);
9795 if (dictSize(d)) {
9796 long elesize;
9797 robj *ele;
9798
9799 de = dictGetRandomKey(d);
9800 ele = dictGetEntryKey(de);
9801 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
560db612 9802 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
4ef8de8a 9803 asize += (sizeof(struct dictEntry)+elesize)*dictSize(d);
9804 if (z) asize += sizeof(zskiplistNode)*dictSize(d);
9805 }
9806 break;
a97b9060 9807 case REDIS_HASH:
9808 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
9809 unsigned char *p = zipmapRewind((unsigned char*)o->ptr);
9810 unsigned int len = zipmapLen((unsigned char*)o->ptr);
9811 unsigned int klen, vlen;
9812 unsigned char *key, *val;
9813
9814 if ((p = zipmapNext(p,&key,&klen,&val,&vlen)) == NULL) {
9815 klen = 0;
9816 vlen = 0;
9817 }
9818 asize = len*(klen+vlen+3);
9819 } else if (o->encoding == REDIS_ENCODING_HT) {
9820 d = o->ptr;
9821 asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
9822 if (dictSize(d)) {
9823 long elesize;
9824 robj *ele;
9825
9826 de = dictGetRandomKey(d);
9827 ele = dictGetEntryKey(de);
9828 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
560db612 9829 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
a97b9060 9830 ele = dictGetEntryVal(de);
9831 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
560db612 9832 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
a97b9060 9833 asize += (sizeof(struct dictEntry)+elesize)*dictSize(d);
9834 }
9835 }
9836 break;
4ef8de8a 9837 }
560db612 9838 return (double)minage*log(1+asize);
4ef8de8a 9839}
9840
9841/* Try to swap an object that's a good candidate for swapping.
9842 * Returns REDIS_OK if the object was swapped, REDIS_ERR if it's not possible
a69a0c9c 9843 * to swap any object at all.
9844 *
9845 * If 'usethreaded' is true, Redis will try to swap the object in background
9846 * using I/O threads. */
9847static int vmSwapOneObject(int usethreads) {
4ef8de8a 9848 int j, i;
9849 struct dictEntry *best = NULL;
9850 double best_swappability = 0;
b9bc0eef 9851 redisDb *best_db = NULL;
44262c58 9852 robj *val;
9853 sds key;
4ef8de8a 9854
9855 for (j = 0; j < server.dbnum; j++) {
9856 redisDb *db = server.db+j;
b72f6a4b 9857 /* Why maxtries is set to 100?
9858 * Because this way (usually) we'll find 1 object even if just 1% - 2%
9859 * are swappable objects */
b0d8747d 9860 int maxtries = 100;
4ef8de8a 9861
9862 if (dictSize(db->dict) == 0) continue;
9863 for (i = 0; i < 5; i++) {
9864 dictEntry *de;
9865 double swappability;
9866
e3cadb8a 9867 if (maxtries) maxtries--;
4ef8de8a 9868 de = dictGetRandomKey(db->dict);
4ef8de8a 9869 val = dictGetEntryVal(de);
1064ef87 9870 /* Only swap objects that are currently in memory.
9871 *
560db612 9872 * Also don't swap shared objects: not a good idea in general and
9873 * we need to ensure that the main thread does not touch the
1064ef87 9874 * object while the I/O thread is using it, but we can't
9875 * control other keys without adding additional mutex. */
560db612 9876 if (val->storage != REDIS_VM_MEMORY || val->refcount != 1) {
e3cadb8a 9877 if (maxtries) i--; /* don't count this try */
9878 continue;
9879 }
4ef8de8a 9880 swappability = computeObjectSwappability(val);
9881 if (!best || swappability > best_swappability) {
9882 best = de;
9883 best_swappability = swappability;
b9bc0eef 9884 best_db = db;
4ef8de8a 9885 }
9886 }
9887 }
7c775e09 9888 if (best == NULL) return REDIS_ERR;
4ef8de8a 9889 key = dictGetEntryKey(best);
9890 val = dictGetEntryVal(best);
9891
e3cadb8a 9892 redisLog(REDIS_DEBUG,"Key with best swappability: %s, %f",
44262c58 9893 key, best_swappability);
4ef8de8a 9894
4ef8de8a 9895 /* Swap it */
a69a0c9c 9896 if (usethreads) {
4c8f2370 9897 robj *keyobj = createStringObject(key,sdslen(key));
9898 vmSwapObjectThreaded(keyobj,val,best_db);
9899 decrRefCount(keyobj);
4ef8de8a 9900 return REDIS_OK;
9901 } else {
560db612 9902 vmpointer *vp;
9903
9904 if ((vp = vmSwapObjectBlocking(val)) != NULL) {
9905 dictGetEntryVal(best) = vp;
a69a0c9c 9906 return REDIS_OK;
9907 } else {
9908 return REDIS_ERR;
9909 }
4ef8de8a 9910 }
9911}
9912
a69a0c9c 9913static int vmSwapOneObjectBlocking() {
9914 return vmSwapOneObject(0);
9915}
9916
9917static int vmSwapOneObjectThreaded() {
9918 return vmSwapOneObject(1);
9919}
9920
7e69548d 9921/* Return true if it's safe to swap out objects in a given moment.
9922 * Basically we don't want to swap objects out while there is a BGSAVE
9923 * or a BGAEOREWRITE running in backgroud. */
9924static int vmCanSwapOut(void) {
9925 return (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1);
9926}
9927
996cb5f7 9928/* =================== Virtual Memory - Threaded I/O ======================= */
9929
b9bc0eef 9930static void freeIOJob(iojob *j) {
d5d55fc3 9931 if ((j->type == REDIS_IOJOB_PREPARE_SWAP ||
9932 j->type == REDIS_IOJOB_DO_SWAP ||
9933 j->type == REDIS_IOJOB_LOAD) && j->val != NULL)
560db612 9934 {
e4ed181d 9935 /* we fix the storage type, otherwise decrRefCount() will try to
9936 * kill the I/O thread Job (that does no longer exists). */
9937 if (j->val->storage == REDIS_VM_SWAPPING)
560db612 9938 j->val->storage = REDIS_VM_MEMORY;
b9bc0eef 9939 decrRefCount(j->val);
560db612 9940 }
9941 decrRefCount(j->key);
b9bc0eef 9942 zfree(j);
9943}
9944
996cb5f7 9945/* Every time a thread finished a Job, it writes a byte into the write side
9946 * of an unix pipe in order to "awake" the main thread, and this function
9947 * is called. */
9948static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
9949 int mask)
9950{
9951 char buf[1];
b0d8747d 9952 int retval, processed = 0, toprocess = -1, trytoswap = 1;
996cb5f7 9953 REDIS_NOTUSED(el);
9954 REDIS_NOTUSED(mask);
9955 REDIS_NOTUSED(privdata);
9956
9957 /* For every byte we read in the read side of the pipe, there is one
9958 * I/O job completed to process. */
9959 while((retval = read(fd,buf,1)) == 1) {
b9bc0eef 9960 iojob *j;
9961 listNode *ln;
b9bc0eef 9962 struct dictEntry *de;
9963
996cb5f7 9964 redisLog(REDIS_DEBUG,"Processing I/O completed job");
b9bc0eef 9965
9966 /* Get the processed element (the oldest one) */
9967 lockThreadedIO();
1064ef87 9968 assert(listLength(server.io_processed) != 0);
f6c0bba8 9969 if (toprocess == -1) {
9970 toprocess = (listLength(server.io_processed)*REDIS_MAX_COMPLETED_JOBS_PROCESSED)/100;
9971 if (toprocess <= 0) toprocess = 1;
9972 }
b9bc0eef 9973 ln = listFirst(server.io_processed);
9974 j = ln->value;
9975 listDelNode(server.io_processed,ln);
9976 unlockThreadedIO();
9977 /* If this job is marked as canceled, just ignore it */
9978 if (j->canceled) {
9979 freeIOJob(j);
9980 continue;
9981 }
9982 /* Post process it in the main thread, as there are things we
9983 * can do just here to avoid race conditions and/or invasive locks */
560db612 9984 redisLog(REDIS_DEBUG,"COMPLETED Job type: %d, ID %p, key: %s", j->type, (void*)j->id, (unsigned char*)j->key->ptr);
44262c58 9985 de = dictFind(j->db->dict,j->key->ptr);
e4ed181d 9986 redisAssert(de != NULL);
b9bc0eef 9987 if (j->type == REDIS_IOJOB_LOAD) {
d5d55fc3 9988 redisDb *db;
560db612 9989 vmpointer *vp = dictGetEntryVal(de);
d5d55fc3 9990
b9bc0eef 9991 /* Key loaded, bring it at home */
560db612 9992 vmMarkPagesFree(vp->page,vp->usedpages);
b9bc0eef 9993 redisLog(REDIS_DEBUG, "VM: object %s loaded from disk (threaded)",
560db612 9994 (unsigned char*) j->key->ptr);
b9bc0eef 9995 server.vm_stats_swapped_objects--;
9996 server.vm_stats_swapins++;
d5d55fc3 9997 dictGetEntryVal(de) = j->val;
9998 incrRefCount(j->val);
9999 db = j->db;
d5d55fc3 10000 /* Handle clients waiting for this key to be loaded. */
560db612 10001 handleClientsBlockedOnSwappedKey(db,j->key);
10002 freeIOJob(j);
10003 zfree(vp);
b9bc0eef 10004 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
10005 /* Now we know the amount of pages required to swap this object.
10006 * Let's find some space for it, and queue this task again
10007 * rebranded as REDIS_IOJOB_DO_SWAP. */
054e426d 10008 if (!vmCanSwapOut() ||
10009 vmFindContiguousPages(&j->page,j->pages) == REDIS_ERR)
10010 {
10011 /* Ooops... no space or we can't swap as there is
10012 * a fork()ed Redis trying to save stuff on disk. */
560db612 10013 j->val->storage = REDIS_VM_MEMORY; /* undo operation */
b9bc0eef 10014 freeIOJob(j);
10015 } else {
c7df85a4 10016 /* Note that we need to mark this pages as used now,
10017 * if the job will be canceled, we'll mark them as freed
10018 * again. */
10019 vmMarkPagesUsed(j->page,j->pages);
b9bc0eef 10020 j->type = REDIS_IOJOB_DO_SWAP;
10021 lockThreadedIO();
10022 queueIOJob(j);
10023 unlockThreadedIO();
10024 }
10025 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
560db612 10026 vmpointer *vp;
b9bc0eef 10027
10028 /* Key swapped. We can finally free some memory. */
560db612 10029 if (j->val->storage != REDIS_VM_SWAPPING) {
10030 vmpointer *vp = (vmpointer*) j->id;
10031 printf("storage: %d\n",vp->storage);
10032 printf("key->name: %s\n",(char*)j->key->ptr);
6c96ba7d 10033 printf("val: %p\n",(void*)j->val);
10034 printf("val->type: %d\n",j->val->type);
10035 printf("val->ptr: %s\n",(char*)j->val->ptr);
10036 }
560db612 10037 redisAssert(j->val->storage == REDIS_VM_SWAPPING);
10038 vp = createVmPointer(j->val->type);
10039 vp->page = j->page;
10040 vp->usedpages = j->pages;
10041 dictGetEntryVal(de) = vp;
e4ed181d 10042 /* Fix the storage otherwise decrRefCount will attempt to
10043 * remove the associated I/O job */
10044 j->val->storage = REDIS_VM_MEMORY;
560db612 10045 decrRefCount(j->val);
b9bc0eef 10046 redisLog(REDIS_DEBUG,
10047 "VM: object %s swapped out at %lld (%lld pages) (threaded)",
560db612 10048 (unsigned char*) j->key->ptr,
b9bc0eef 10049 (unsigned long long) j->page, (unsigned long long) j->pages);
10050 server.vm_stats_swapped_objects++;
10051 server.vm_stats_swapouts++;
10052 freeIOJob(j);
f11b8647 10053 /* Put a few more swap requests in queue if we are still
10054 * out of memory */
b0d8747d 10055 if (trytoswap && vmCanSwapOut() &&
10056 zmalloc_used_memory() > server.vm_max_memory)
10057 {
f11b8647 10058 int more = 1;
10059 while(more) {
10060 lockThreadedIO();
10061 more = listLength(server.io_newjobs) <
10062 (unsigned) server.vm_max_threads;
10063 unlockThreadedIO();
10064 /* Don't waste CPU time if swappable objects are rare. */
b0d8747d 10065 if (vmSwapOneObjectThreaded() == REDIS_ERR) {
10066 trytoswap = 0;
10067 break;
10068 }
f11b8647 10069 }
10070 }
b9bc0eef 10071 }
c953f24b 10072 processed++;
f6c0bba8 10073 if (processed == toprocess) return;
996cb5f7 10074 }
10075 if (retval < 0 && errno != EAGAIN) {
10076 redisLog(REDIS_WARNING,
10077 "WARNING: read(2) error in vmThreadedIOCompletedJob() %s",
10078 strerror(errno));
10079 }
10080}
10081
10082static void lockThreadedIO(void) {
10083 pthread_mutex_lock(&server.io_mutex);
10084}
10085
10086static void unlockThreadedIO(void) {
10087 pthread_mutex_unlock(&server.io_mutex);
10088}
10089
10090/* Remove the specified object from the threaded I/O queue if still not
10091 * processed, otherwise make sure to flag it as canceled. */
10092static void vmCancelThreadedIOJob(robj *o) {
10093 list *lists[3] = {
6c96ba7d 10094 server.io_newjobs, /* 0 */
10095 server.io_processing, /* 1 */
10096 server.io_processed /* 2 */
996cb5f7 10097 };
10098 int i;
10099
10100 assert(o->storage == REDIS_VM_LOADING || o->storage == REDIS_VM_SWAPPING);
2e111efe 10101again:
996cb5f7 10102 lockThreadedIO();
560db612 10103 /* Search for a matching object in one of the queues */
996cb5f7 10104 for (i = 0; i < 3; i++) {
10105 listNode *ln;
c7df85a4 10106 listIter li;
996cb5f7 10107
c7df85a4 10108 listRewind(lists[i],&li);
10109 while ((ln = listNext(&li)) != NULL) {
996cb5f7 10110 iojob *job = ln->value;
10111
6c96ba7d 10112 if (job->canceled) continue; /* Skip this, already canceled. */
560db612 10113 if (job->id == o) {
dbc289ae 10114 redisLog(REDIS_DEBUG,"*** CANCELED %p (key %s) (type %d) (LIST ID %d)\n",
10115 (void*)job, (char*)job->key->ptr, job->type, i);
427a2153 10116 /* Mark the pages as free since the swap didn't happened
10117 * or happened but is now discarded. */
970e10bb 10118 if (i != 1 && job->type == REDIS_IOJOB_DO_SWAP)
427a2153 10119 vmMarkPagesFree(job->page,job->pages);
10120 /* Cancel the job. It depends on the list the job is
10121 * living in. */
996cb5f7 10122 switch(i) {
10123 case 0: /* io_newjobs */
6c96ba7d 10124 /* If the job was yet not processed the best thing to do
996cb5f7 10125 * is to remove it from the queue at all */
6c96ba7d 10126 freeIOJob(job);
996cb5f7 10127 listDelNode(lists[i],ln);
10128 break;
10129 case 1: /* io_processing */
d5d55fc3 10130 /* Oh Shi- the thread is messing with the Job:
10131 *
10132 * Probably it's accessing the object if this is a
10133 * PREPARE_SWAP or DO_SWAP job.
10134 * If it's a LOAD job it may be reading from disk and
10135 * if we don't wait for the job to terminate before to
10136 * cancel it, maybe in a few microseconds data can be
10137 * corrupted in this pages. So the short story is:
10138 *
10139 * Better to wait for the job to move into the
10140 * next queue (processed)... */
10141
10142 /* We try again and again until the job is completed. */
10143 unlockThreadedIO();
10144 /* But let's wait some time for the I/O thread
10145 * to finish with this job. After all this condition
10146 * should be very rare. */
10147 usleep(1);
10148 goto again;
996cb5f7 10149 case 2: /* io_processed */
2e111efe 10150 /* The job was already processed, that's easy...
10151 * just mark it as canceled so that we'll ignore it
10152 * when processing completed jobs. */
996cb5f7 10153 job->canceled = 1;
10154 break;
10155 }
c7df85a4 10156 /* Finally we have to adjust the storage type of the object
10157 * in order to "UNDO" the operaiton. */
996cb5f7 10158 if (o->storage == REDIS_VM_LOADING)
10159 o->storage = REDIS_VM_SWAPPED;
10160 else if (o->storage == REDIS_VM_SWAPPING)
10161 o->storage = REDIS_VM_MEMORY;
10162 unlockThreadedIO();
e4ed181d 10163 redisLog(REDIS_DEBUG,"*** DONE");
996cb5f7 10164 return;
10165 }
10166 }
10167 }
10168 unlockThreadedIO();
560db612 10169 printf("Not found: %p\n", (void*)o);
10170 redisAssert(1 != 1); /* We should never reach this */
996cb5f7 10171}
10172
b9bc0eef 10173static void *IOThreadEntryPoint(void *arg) {
10174 iojob *j;
10175 listNode *ln;
10176 REDIS_NOTUSED(arg);
10177
10178 pthread_detach(pthread_self());
10179 while(1) {
10180 /* Get a new job to process */
10181 lockThreadedIO();
10182 if (listLength(server.io_newjobs) == 0) {
10183 /* No new jobs in queue, exit. */
9ebed7cf 10184 redisLog(REDIS_DEBUG,"Thread %ld exiting, nothing to do",
10185 (long) pthread_self());
b9bc0eef 10186 server.io_active_threads--;
10187 unlockThreadedIO();
10188 return NULL;
10189 }
10190 ln = listFirst(server.io_newjobs);
10191 j = ln->value;
10192 listDelNode(server.io_newjobs,ln);
10193 /* Add the job in the processing queue */
10194 j->thread = pthread_self();
10195 listAddNodeTail(server.io_processing,j);
10196 ln = listLast(server.io_processing); /* We use ln later to remove it */
10197 unlockThreadedIO();
9ebed7cf 10198 redisLog(REDIS_DEBUG,"Thread %ld got a new job (type %d): %p about key '%s'",
10199 (long) pthread_self(), j->type, (void*)j, (char*)j->key->ptr);
b9bc0eef 10200
10201 /* Process the Job */
10202 if (j->type == REDIS_IOJOB_LOAD) {
560db612 10203 vmpointer *vp = (vmpointer*)j->id;
10204 j->val = vmReadObjectFromSwap(j->page,vp->vtype);
b9bc0eef 10205 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
10206 FILE *fp = fopen("/dev/null","w+");
10207 j->pages = rdbSavedObjectPages(j->val,fp);
10208 fclose(fp);
10209 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
a5819310 10210 if (vmWriteObjectOnSwap(j->val,j->page) == REDIS_ERR)
10211 j->canceled = 1;
b9bc0eef 10212 }
10213
10214 /* Done: insert the job into the processed queue */
9ebed7cf 10215 redisLog(REDIS_DEBUG,"Thread %ld completed the job: %p (key %s)",
10216 (long) pthread_self(), (void*)j, (char*)j->key->ptr);
b9bc0eef 10217 lockThreadedIO();
10218 listDelNode(server.io_processing,ln);
10219 listAddNodeTail(server.io_processed,j);
10220 unlockThreadedIO();
e0a62c7f 10221
b9bc0eef 10222 /* Signal the main thread there is new stuff to process */
10223 assert(write(server.io_ready_pipe_write,"x",1) == 1);
10224 }
10225 return NULL; /* never reached */
10226}
10227
10228static void spawnIOThread(void) {
10229 pthread_t thread;
478c2c6f 10230 sigset_t mask, omask;
a97b9060 10231 int err;
b9bc0eef 10232
478c2c6f 10233 sigemptyset(&mask);
10234 sigaddset(&mask,SIGCHLD);
10235 sigaddset(&mask,SIGHUP);
10236 sigaddset(&mask,SIGPIPE);
10237 pthread_sigmask(SIG_SETMASK, &mask, &omask);
a97b9060 10238 while ((err = pthread_create(&thread,&server.io_threads_attr,IOThreadEntryPoint,NULL)) != 0) {
10239 redisLog(REDIS_WARNING,"Unable to spawn an I/O thread: %s",
10240 strerror(err));
10241 usleep(1000000);
10242 }
478c2c6f 10243 pthread_sigmask(SIG_SETMASK, &omask, NULL);
b9bc0eef 10244 server.io_active_threads++;
10245}
10246
4ee9488d 10247/* We need to wait for the last thread to exit before we are able to
10248 * fork() in order to BGSAVE or BGREWRITEAOF. */
054e426d 10249static void waitEmptyIOJobsQueue(void) {
4ee9488d 10250 while(1) {
76b7233a 10251 int io_processed_len;
10252
4ee9488d 10253 lockThreadedIO();
054e426d 10254 if (listLength(server.io_newjobs) == 0 &&
10255 listLength(server.io_processing) == 0 &&
10256 server.io_active_threads == 0)
10257 {
4ee9488d 10258 unlockThreadedIO();
10259 return;
10260 }
76b7233a 10261 /* While waiting for empty jobs queue condition we post-process some
10262 * finshed job, as I/O threads may be hanging trying to write against
10263 * the io_ready_pipe_write FD but there are so much pending jobs that
10264 * it's blocking. */
10265 io_processed_len = listLength(server.io_processed);
4ee9488d 10266 unlockThreadedIO();
76b7233a 10267 if (io_processed_len) {
10268 vmThreadedIOCompletedJob(NULL,server.io_ready_pipe_read,NULL,0);
10269 usleep(1000); /* 1 millisecond */
10270 } else {
10271 usleep(10000); /* 10 milliseconds */
10272 }
4ee9488d 10273 }
10274}
10275
054e426d 10276static void vmReopenSwapFile(void) {
478c2c6f 10277 /* Note: we don't close the old one as we are in the child process
10278 * and don't want to mess at all with the original file object. */
054e426d 10279 server.vm_fp = fopen(server.vm_swap_file,"r+b");
10280 if (server.vm_fp == NULL) {
10281 redisLog(REDIS_WARNING,"Can't re-open the VM swap file: %s. Exiting.",
10282 server.vm_swap_file);
478c2c6f 10283 _exit(1);
054e426d 10284 }
10285 server.vm_fd = fileno(server.vm_fp);
10286}
10287
b9bc0eef 10288/* This function must be called while with threaded IO locked */
10289static void queueIOJob(iojob *j) {
6c96ba7d 10290 redisLog(REDIS_DEBUG,"Queued IO Job %p type %d about key '%s'\n",
10291 (void*)j, j->type, (char*)j->key->ptr);
b9bc0eef 10292 listAddNodeTail(server.io_newjobs,j);
10293 if (server.io_active_threads < server.vm_max_threads)
10294 spawnIOThread();
10295}
10296
10297static int vmSwapObjectThreaded(robj *key, robj *val, redisDb *db) {
10298 iojob *j;
e0a62c7f 10299
b9bc0eef 10300 j = zmalloc(sizeof(*j));
10301 j->type = REDIS_IOJOB_PREPARE_SWAP;
10302 j->db = db;
78ebe4c8 10303 j->key = key;
7dd8e7cf 10304 incrRefCount(key);
560db612 10305 j->id = j->val = val;
b9bc0eef 10306 incrRefCount(val);
10307 j->canceled = 0;
10308 j->thread = (pthread_t) -1;
560db612 10309 val->storage = REDIS_VM_SWAPPING;
b9bc0eef 10310
10311 lockThreadedIO();
10312 queueIOJob(j);
10313 unlockThreadedIO();
10314 return REDIS_OK;
10315}
10316
b0d8747d 10317/* ============ Virtual Memory - Blocking clients on missing keys =========== */
10318
d5d55fc3 10319/* This function makes the clinet 'c' waiting for the key 'key' to be loaded.
10320 * If there is not already a job loading the key, it is craeted.
10321 * The key is added to the io_keys list in the client structure, and also
10322 * in the hash table mapping swapped keys to waiting clients, that is,
10323 * server.io_waited_keys. */
10324static int waitForSwappedKey(redisClient *c, robj *key) {
10325 struct dictEntry *de;
10326 robj *o;
10327 list *l;
10328
10329 /* If the key does not exist or is already in RAM we don't need to
10330 * block the client at all. */
09241813 10331 de = dictFind(c->db->dict,key->ptr);
d5d55fc3 10332 if (de == NULL) return 0;
560db612 10333 o = dictGetEntryVal(de);
d5d55fc3 10334 if (o->storage == REDIS_VM_MEMORY) {
10335 return 0;
10336 } else if (o->storage == REDIS_VM_SWAPPING) {
10337 /* We were swapping the key, undo it! */
10338 vmCancelThreadedIOJob(o);
10339 return 0;
10340 }
e0a62c7f 10341
d5d55fc3 10342 /* OK: the key is either swapped, or being loaded just now. */
10343
10344 /* Add the key to the list of keys this client is waiting for.
10345 * This maps clients to keys they are waiting for. */
10346 listAddNodeTail(c->io_keys,key);
10347 incrRefCount(key);
10348
10349 /* Add the client to the swapped keys => clients waiting map. */
10350 de = dictFind(c->db->io_keys,key);
10351 if (de == NULL) {
10352 int retval;
10353
10354 /* For every key we take a list of clients blocked for it */
10355 l = listCreate();
10356 retval = dictAdd(c->db->io_keys,key,l);
10357 incrRefCount(key);
10358 assert(retval == DICT_OK);
10359 } else {
10360 l = dictGetEntryVal(de);
10361 }
10362 listAddNodeTail(l,c);
10363
10364 /* Are we already loading the key from disk? If not create a job */
10365 if (o->storage == REDIS_VM_SWAPPED) {
10366 iojob *j;
560db612 10367 vmpointer *vp = (vmpointer*)o;
d5d55fc3 10368
10369 o->storage = REDIS_VM_LOADING;
10370 j = zmalloc(sizeof(*j));
10371 j->type = REDIS_IOJOB_LOAD;
10372 j->db = c->db;
560db612 10373 j->id = (robj*)vp;
10374 j->key = key;
10375 incrRefCount(key);
10376 j->page = vp->page;
d5d55fc3 10377 j->val = NULL;
10378 j->canceled = 0;
10379 j->thread = (pthread_t) -1;
10380 lockThreadedIO();
10381 queueIOJob(j);
10382 unlockThreadedIO();
10383 }
10384 return 1;
10385}
10386
6f078746
PN
10387/* Preload keys for any command with first, last and step values for
10388 * the command keys prototype, as defined in the command table. */
10389static void waitForMultipleSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv) {
10390 int j, last;
10391 if (cmd->vm_firstkey == 0) return;
10392 last = cmd->vm_lastkey;
10393 if (last < 0) last = argc+last;
10394 for (j = cmd->vm_firstkey; j <= last; j += cmd->vm_keystep) {
10395 redisAssert(j < argc);
10396 waitForSwappedKey(c,argv[j]);
10397 }
10398}
10399
5d373da9 10400/* Preload keys needed for the ZUNIONSTORE and ZINTERSTORE commands.
739ba0d2
PN
10401 * Note that the number of keys to preload is user-defined, so we need to
10402 * apply a sanity check against argc. */
ca1788b5 10403static void zunionInterBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv) {
76583ea4 10404 int i, num;
ca1788b5 10405 REDIS_NOTUSED(cmd);
ca1788b5
PN
10406
10407 num = atoi(argv[2]->ptr);
739ba0d2 10408 if (num > (argc-3)) return;
76583ea4 10409 for (i = 0; i < num; i++) {
ca1788b5 10410 waitForSwappedKey(c,argv[3+i]);
76583ea4
PN
10411 }
10412}
10413
3805e04f
PN
10414/* Preload keys needed to execute the entire MULTI/EXEC block.
10415 *
10416 * This function is called by blockClientOnSwappedKeys when EXEC is issued,
10417 * and will block the client when any command requires a swapped out value. */
10418static void execBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv) {
10419 int i, margc;
10420 struct redisCommand *mcmd;
10421 robj **margv;
10422 REDIS_NOTUSED(cmd);
10423 REDIS_NOTUSED(argc);
10424 REDIS_NOTUSED(argv);
10425
10426 if (!(c->flags & REDIS_MULTI)) return;
10427 for (i = 0; i < c->mstate.count; i++) {
10428 mcmd = c->mstate.commands[i].cmd;
10429 margc = c->mstate.commands[i].argc;
10430 margv = c->mstate.commands[i].argv;
10431
10432 if (mcmd->vm_preload_proc != NULL) {
10433 mcmd->vm_preload_proc(c,mcmd,margc,margv);
10434 } else {
10435 waitForMultipleSwappedKeys(c,mcmd,margc,margv);
10436 }
76583ea4
PN
10437 }
10438}
10439
b0d8747d 10440/* Is this client attempting to run a command against swapped keys?
d5d55fc3 10441 * If so, block it ASAP, load the keys in background, then resume it.
b0d8747d 10442 *
d5d55fc3 10443 * The important idea about this function is that it can fail! If keys will
10444 * still be swapped when the client is resumed, this key lookups will
10445 * just block loading keys from disk. In practical terms this should only
10446 * happen with SORT BY command or if there is a bug in this function.
10447 *
10448 * Return 1 if the client is marked as blocked, 0 if the client can
10449 * continue as the keys it is going to access appear to be in memory. */
0a6f3f0f 10450static int blockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd) {
76583ea4 10451 if (cmd->vm_preload_proc != NULL) {
ca1788b5 10452 cmd->vm_preload_proc(c,cmd,c->argc,c->argv);
76583ea4 10453 } else {
6f078746 10454 waitForMultipleSwappedKeys(c,cmd,c->argc,c->argv);
76583ea4
PN
10455 }
10456
d5d55fc3 10457 /* If the client was blocked for at least one key, mark it as blocked. */
10458 if (listLength(c->io_keys)) {
10459 c->flags |= REDIS_IO_WAIT;
10460 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
10461 server.vm_blocked_clients++;
10462 return 1;
10463 } else {
10464 return 0;
10465 }
10466}
10467
10468/* Remove the 'key' from the list of blocked keys for a given client.
10469 *
10470 * The function returns 1 when there are no longer blocking keys after
10471 * the current one was removed (and the client can be unblocked). */
10472static int dontWaitForSwappedKey(redisClient *c, robj *key) {
10473 list *l;
10474 listNode *ln;
10475 listIter li;
10476 struct dictEntry *de;
10477
10478 /* Remove the key from the list of keys this client is waiting for. */
10479 listRewind(c->io_keys,&li);
10480 while ((ln = listNext(&li)) != NULL) {
bf028098 10481 if (equalStringObjects(ln->value,key)) {
d5d55fc3 10482 listDelNode(c->io_keys,ln);
10483 break;
10484 }
10485 }
10486 assert(ln != NULL);
10487
10488 /* Remove the client form the key => waiting clients map. */
10489 de = dictFind(c->db->io_keys,key);
10490 assert(de != NULL);
10491 l = dictGetEntryVal(de);
10492 ln = listSearchKey(l,c);
10493 assert(ln != NULL);
10494 listDelNode(l,ln);
10495 if (listLength(l) == 0)
10496 dictDelete(c->db->io_keys,key);
10497
10498 return listLength(c->io_keys) == 0;
10499}
10500
560db612 10501/* Every time we now a key was loaded back in memory, we handle clients
10502 * waiting for this key if any. */
d5d55fc3 10503static void handleClientsBlockedOnSwappedKey(redisDb *db, robj *key) {
10504 struct dictEntry *de;
10505 list *l;
10506 listNode *ln;
10507 int len;
10508
10509 de = dictFind(db->io_keys,key);
10510 if (!de) return;
10511
10512 l = dictGetEntryVal(de);
10513 len = listLength(l);
10514 /* Note: we can't use something like while(listLength(l)) as the list
10515 * can be freed by the calling function when we remove the last element. */
10516 while (len--) {
10517 ln = listFirst(l);
10518 redisClient *c = ln->value;
10519
10520 if (dontWaitForSwappedKey(c,key)) {
10521 /* Put the client in the list of clients ready to go as we
10522 * loaded all the keys about it. */
10523 listAddNodeTail(server.io_ready_clients,c);
10524 }
10525 }
b0d8747d 10526}
b0d8747d 10527
500ece7c 10528/* =========================== Remote Configuration ========================= */
10529
10530static void configSetCommand(redisClient *c) {
10531 robj *o = getDecodedObject(c->argv[3]);
2e5eb04e 10532 long long ll;
10533
500ece7c 10534 if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) {
10535 zfree(server.dbfilename);
10536 server.dbfilename = zstrdup(o->ptr);
10537 } else if (!strcasecmp(c->argv[2]->ptr,"requirepass")) {
10538 zfree(server.requirepass);
10539 server.requirepass = zstrdup(o->ptr);
10540 } else if (!strcasecmp(c->argv[2]->ptr,"masterauth")) {
10541 zfree(server.masterauth);
10542 server.masterauth = zstrdup(o->ptr);
10543 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory")) {
2e5eb04e 10544 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
10545 ll < 0) goto badfmt;
10546 server.maxmemory = ll;
10547 } else if (!strcasecmp(c->argv[2]->ptr,"timeout")) {
10548 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
10549 ll < 0 || ll > LONG_MAX) goto badfmt;
10550 server.maxidletime = ll;
1b677732 10551 } else if (!strcasecmp(c->argv[2]->ptr,"appendfsync")) {
10552 if (!strcasecmp(o->ptr,"no")) {
10553 server.appendfsync = APPENDFSYNC_NO;
10554 } else if (!strcasecmp(o->ptr,"everysec")) {
10555 server.appendfsync = APPENDFSYNC_EVERYSEC;
10556 } else if (!strcasecmp(o->ptr,"always")) {
10557 server.appendfsync = APPENDFSYNC_ALWAYS;
10558 } else {
10559 goto badfmt;
10560 }
38db9171 10561 } else if (!strcasecmp(c->argv[2]->ptr,"no-appendfsync-on-rewrite")) {
10562 int yn = yesnotoi(o->ptr);
10563
10564 if (yn == -1) goto badfmt;
10565 server.no_appendfsync_on_rewrite = yn;
2e5eb04e 10566 } else if (!strcasecmp(c->argv[2]->ptr,"appendonly")) {
10567 int old = server.appendonly;
10568 int new = yesnotoi(o->ptr);
10569
10570 if (new == -1) goto badfmt;
10571 if (old != new) {
10572 if (new == 0) {
10573 stopAppendOnly();
10574 } else {
10575 if (startAppendOnly() == REDIS_ERR) {
10576 addReplySds(c,sdscatprintf(sdsempty(),
10577 "-ERR Unable to turn on AOF. Check server logs.\r\n"));
10578 decrRefCount(o);
10579 return;
10580 }
10581 }
10582 }
a34e0a25 10583 } else if (!strcasecmp(c->argv[2]->ptr,"save")) {
10584 int vlen, j;
10585 sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen);
10586
10587 /* Perform sanity check before setting the new config:
10588 * - Even number of args
10589 * - Seconds >= 1, changes >= 0 */
10590 if (vlen & 1) {
10591 sdsfreesplitres(v,vlen);
10592 goto badfmt;
10593 }
10594 for (j = 0; j < vlen; j++) {
10595 char *eptr;
10596 long val;
10597
10598 val = strtoll(v[j], &eptr, 10);
10599 if (eptr[0] != '\0' ||
10600 ((j & 1) == 0 && val < 1) ||
10601 ((j & 1) == 1 && val < 0)) {
10602 sdsfreesplitres(v,vlen);
10603 goto badfmt;
10604 }
10605 }
10606 /* Finally set the new config */
10607 resetServerSaveParams();
10608 for (j = 0; j < vlen; j += 2) {
10609 time_t seconds;
10610 int changes;
10611
10612 seconds = strtoll(v[j],NULL,10);
10613 changes = strtoll(v[j+1],NULL,10);
10614 appendServerSaveParams(seconds, changes);
10615 }
10616 sdsfreesplitres(v,vlen);
500ece7c 10617 } else {
10618 addReplySds(c,sdscatprintf(sdsempty(),
10619 "-ERR not supported CONFIG parameter %s\r\n",
10620 (char*)c->argv[2]->ptr));
10621 decrRefCount(o);
10622 return;
10623 }
10624 decrRefCount(o);
10625 addReply(c,shared.ok);
a34e0a25 10626 return;
10627
10628badfmt: /* Bad format errors */
10629 addReplySds(c,sdscatprintf(sdsempty(),
10630 "-ERR invalid argument '%s' for CONFIG SET '%s'\r\n",
10631 (char*)o->ptr,
10632 (char*)c->argv[2]->ptr));
10633 decrRefCount(o);
500ece7c 10634}
10635
10636static void configGetCommand(redisClient *c) {
10637 robj *o = getDecodedObject(c->argv[2]);
10638 robj *lenobj = createObject(REDIS_STRING,NULL);
10639 char *pattern = o->ptr;
10640 int matches = 0;
10641
10642 addReply(c,lenobj);
10643 decrRefCount(lenobj);
10644
10645 if (stringmatch(pattern,"dbfilename",0)) {
10646 addReplyBulkCString(c,"dbfilename");
10647 addReplyBulkCString(c,server.dbfilename);
10648 matches++;
10649 }
10650 if (stringmatch(pattern,"requirepass",0)) {
10651 addReplyBulkCString(c,"requirepass");
10652 addReplyBulkCString(c,server.requirepass);
10653 matches++;
10654 }
10655 if (stringmatch(pattern,"masterauth",0)) {
10656 addReplyBulkCString(c,"masterauth");
10657 addReplyBulkCString(c,server.masterauth);
10658 matches++;
10659 }
10660 if (stringmatch(pattern,"maxmemory",0)) {
10661 char buf[128];
10662
2e5eb04e 10663 ll2string(buf,128,server.maxmemory);
500ece7c 10664 addReplyBulkCString(c,"maxmemory");
10665 addReplyBulkCString(c,buf);
10666 matches++;
10667 }
2e5eb04e 10668 if (stringmatch(pattern,"timeout",0)) {
10669 char buf[128];
10670
10671 ll2string(buf,128,server.maxidletime);
10672 addReplyBulkCString(c,"timeout");
10673 addReplyBulkCString(c,buf);
10674 matches++;
10675 }
10676 if (stringmatch(pattern,"appendonly",0)) {
10677 addReplyBulkCString(c,"appendonly");
10678 addReplyBulkCString(c,server.appendonly ? "yes" : "no");
10679 matches++;
10680 }
38db9171 10681 if (stringmatch(pattern,"no-appendfsync-on-rewrite",0)) {
10682 addReplyBulkCString(c,"no-appendfsync-on-rewrite");
10683 addReplyBulkCString(c,server.no_appendfsync_on_rewrite ? "yes" : "no");
10684 matches++;
10685 }
1b677732 10686 if (stringmatch(pattern,"appendfsync",0)) {
10687 char *policy;
10688
10689 switch(server.appendfsync) {
10690 case APPENDFSYNC_NO: policy = "no"; break;
10691 case APPENDFSYNC_EVERYSEC: policy = "everysec"; break;
10692 case APPENDFSYNC_ALWAYS: policy = "always"; break;
10693 default: policy = "unknown"; break; /* too harmless to panic */
10694 }
10695 addReplyBulkCString(c,"appendfsync");
10696 addReplyBulkCString(c,policy);
10697 matches++;
10698 }
a34e0a25 10699 if (stringmatch(pattern,"save",0)) {
10700 sds buf = sdsempty();
10701 int j;
10702
10703 for (j = 0; j < server.saveparamslen; j++) {
10704 buf = sdscatprintf(buf,"%ld %d",
10705 server.saveparams[j].seconds,
10706 server.saveparams[j].changes);
10707 if (j != server.saveparamslen-1)
10708 buf = sdscatlen(buf," ",1);
10709 }
10710 addReplyBulkCString(c,"save");
10711 addReplyBulkCString(c,buf);
10712 sdsfree(buf);
10713 matches++;
10714 }
500ece7c 10715 decrRefCount(o);
10716 lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",matches*2);
10717}
10718
10719static void configCommand(redisClient *c) {
10720 if (!strcasecmp(c->argv[1]->ptr,"set")) {
10721 if (c->argc != 4) goto badarity;
10722 configSetCommand(c);
10723 } else if (!strcasecmp(c->argv[1]->ptr,"get")) {
10724 if (c->argc != 3) goto badarity;
10725 configGetCommand(c);
10726 } else if (!strcasecmp(c->argv[1]->ptr,"resetstat")) {
10727 if (c->argc != 2) goto badarity;
10728 server.stat_numcommands = 0;
10729 server.stat_numconnections = 0;
10730 server.stat_expiredkeys = 0;
10731 server.stat_starttime = time(NULL);
10732 addReply(c,shared.ok);
10733 } else {
10734 addReplySds(c,sdscatprintf(sdsempty(),
10735 "-ERR CONFIG subcommand must be one of GET, SET, RESETSTAT\r\n"));
10736 }
10737 return;
10738
10739badarity:
10740 addReplySds(c,sdscatprintf(sdsempty(),
10741 "-ERR Wrong number of arguments for CONFIG %s\r\n",
10742 (char*) c->argv[1]->ptr));
10743}
10744
befec3cd 10745/* =========================== Pubsub implementation ======================== */
10746
ffc6b7f8 10747static void freePubsubPattern(void *p) {
10748 pubsubPattern *pat = p;
10749
10750 decrRefCount(pat->pattern);
10751 zfree(pat);
10752}
10753
10754static int listMatchPubsubPattern(void *a, void *b) {
10755 pubsubPattern *pa = a, *pb = b;
10756
10757 return (pa->client == pb->client) &&
bf028098 10758 (equalStringObjects(pa->pattern,pb->pattern));
ffc6b7f8 10759}
10760
10761/* Subscribe a client to a channel. Returns 1 if the operation succeeded, or
10762 * 0 if the client was already subscribed to that channel. */
10763static int pubsubSubscribeChannel(redisClient *c, robj *channel) {
befec3cd 10764 struct dictEntry *de;
10765 list *clients = NULL;
10766 int retval = 0;
10767
ffc6b7f8 10768 /* Add the channel to the client -> channels hash table */
10769 if (dictAdd(c->pubsub_channels,channel,NULL) == DICT_OK) {
befec3cd 10770 retval = 1;
ffc6b7f8 10771 incrRefCount(channel);
10772 /* Add the client to the channel -> list of clients hash table */
10773 de = dictFind(server.pubsub_channels,channel);
befec3cd 10774 if (de == NULL) {
10775 clients = listCreate();
ffc6b7f8 10776 dictAdd(server.pubsub_channels,channel,clients);
10777 incrRefCount(channel);
befec3cd 10778 } else {
10779 clients = dictGetEntryVal(de);
10780 }
10781 listAddNodeTail(clients,c);
10782 }
10783 /* Notify the client */
10784 addReply(c,shared.mbulk3);
10785 addReply(c,shared.subscribebulk);
ffc6b7f8 10786 addReplyBulk(c,channel);
482b672d 10787 addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns));
befec3cd 10788 return retval;
10789}
10790
ffc6b7f8 10791/* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
10792 * 0 if the client was not subscribed to the specified channel. */
10793static int pubsubUnsubscribeChannel(redisClient *c, robj *channel, int notify) {
befec3cd 10794 struct dictEntry *de;
10795 list *clients;
10796 listNode *ln;
10797 int retval = 0;
10798
ffc6b7f8 10799 /* Remove the channel from the client -> channels hash table */
10800 incrRefCount(channel); /* channel may be just a pointer to the same object
201037f5 10801 we have in the hash tables. Protect it... */
ffc6b7f8 10802 if (dictDelete(c->pubsub_channels,channel) == DICT_OK) {
befec3cd 10803 retval = 1;
ffc6b7f8 10804 /* Remove the client from the channel -> clients list hash table */
10805 de = dictFind(server.pubsub_channels,channel);
befec3cd 10806 assert(de != NULL);
10807 clients = dictGetEntryVal(de);
10808 ln = listSearchKey(clients,c);
10809 assert(ln != NULL);
10810 listDelNode(clients,ln);
ff767a75 10811 if (listLength(clients) == 0) {
10812 /* Free the list and associated hash entry at all if this was
10813 * the latest client, so that it will be possible to abuse
ffc6b7f8 10814 * Redis PUBSUB creating millions of channels. */
10815 dictDelete(server.pubsub_channels,channel);
ff767a75 10816 }
befec3cd 10817 }
10818 /* Notify the client */
10819 if (notify) {
10820 addReply(c,shared.mbulk3);
10821 addReply(c,shared.unsubscribebulk);
ffc6b7f8 10822 addReplyBulk(c,channel);
482b672d 10823 addReplyLongLong(c,dictSize(c->pubsub_channels)+
ffc6b7f8 10824 listLength(c->pubsub_patterns));
10825
10826 }
10827 decrRefCount(channel); /* it is finally safe to release it */
10828 return retval;
10829}
10830
10831/* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the clinet was already subscribed to that pattern. */
10832static int pubsubSubscribePattern(redisClient *c, robj *pattern) {
10833 int retval = 0;
10834
10835 if (listSearchKey(c->pubsub_patterns,pattern) == NULL) {
10836 retval = 1;
10837 pubsubPattern *pat;
10838 listAddNodeTail(c->pubsub_patterns,pattern);
10839 incrRefCount(pattern);
10840 pat = zmalloc(sizeof(*pat));
10841 pat->pattern = getDecodedObject(pattern);
10842 pat->client = c;
10843 listAddNodeTail(server.pubsub_patterns,pat);
10844 }
10845 /* Notify the client */
10846 addReply(c,shared.mbulk3);
10847 addReply(c,shared.psubscribebulk);
10848 addReplyBulk(c,pattern);
482b672d 10849 addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns));
ffc6b7f8 10850 return retval;
10851}
10852
10853/* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
10854 * 0 if the client was not subscribed to the specified channel. */
10855static int pubsubUnsubscribePattern(redisClient *c, robj *pattern, int notify) {
10856 listNode *ln;
10857 pubsubPattern pat;
10858 int retval = 0;
10859
10860 incrRefCount(pattern); /* Protect the object. May be the same we remove */
10861 if ((ln = listSearchKey(c->pubsub_patterns,pattern)) != NULL) {
10862 retval = 1;
10863 listDelNode(c->pubsub_patterns,ln);
10864 pat.client = c;
10865 pat.pattern = pattern;
10866 ln = listSearchKey(server.pubsub_patterns,&pat);
10867 listDelNode(server.pubsub_patterns,ln);
10868 }
10869 /* Notify the client */
10870 if (notify) {
10871 addReply(c,shared.mbulk3);
10872 addReply(c,shared.punsubscribebulk);
10873 addReplyBulk(c,pattern);
482b672d 10874 addReplyLongLong(c,dictSize(c->pubsub_channels)+
ffc6b7f8 10875 listLength(c->pubsub_patterns));
befec3cd 10876 }
ffc6b7f8 10877 decrRefCount(pattern);
befec3cd 10878 return retval;
10879}
10880
ffc6b7f8 10881/* Unsubscribe from all the channels. Return the number of channels the
10882 * client was subscribed from. */
10883static int pubsubUnsubscribeAllChannels(redisClient *c, int notify) {
10884 dictIterator *di = dictGetIterator(c->pubsub_channels);
befec3cd 10885 dictEntry *de;
10886 int count = 0;
10887
10888 while((de = dictNext(di)) != NULL) {
ffc6b7f8 10889 robj *channel = dictGetEntryKey(de);
befec3cd 10890
ffc6b7f8 10891 count += pubsubUnsubscribeChannel(c,channel,notify);
befec3cd 10892 }
10893 dictReleaseIterator(di);
10894 return count;
10895}
10896
ffc6b7f8 10897/* Unsubscribe from all the patterns. Return the number of patterns the
10898 * client was subscribed from. */
10899static int pubsubUnsubscribeAllPatterns(redisClient *c, int notify) {
10900 listNode *ln;
10901 listIter li;
10902 int count = 0;
10903
10904 listRewind(c->pubsub_patterns,&li);
10905 while ((ln = listNext(&li)) != NULL) {
10906 robj *pattern = ln->value;
10907
10908 count += pubsubUnsubscribePattern(c,pattern,notify);
10909 }
10910 return count;
10911}
10912
befec3cd 10913/* Publish a message */
ffc6b7f8 10914static int pubsubPublishMessage(robj *channel, robj *message) {
befec3cd 10915 int receivers = 0;
10916 struct dictEntry *de;
ffc6b7f8 10917 listNode *ln;
10918 listIter li;
befec3cd 10919
ffc6b7f8 10920 /* Send to clients listening for that channel */
10921 de = dictFind(server.pubsub_channels,channel);
befec3cd 10922 if (de) {
10923 list *list = dictGetEntryVal(de);
10924 listNode *ln;
10925 listIter li;
10926
10927 listRewind(list,&li);
10928 while ((ln = listNext(&li)) != NULL) {
10929 redisClient *c = ln->value;
10930
10931 addReply(c,shared.mbulk3);
10932 addReply(c,shared.messagebulk);
ffc6b7f8 10933 addReplyBulk(c,channel);
befec3cd 10934 addReplyBulk(c,message);
10935 receivers++;
10936 }
10937 }
ffc6b7f8 10938 /* Send to clients listening to matching channels */
10939 if (listLength(server.pubsub_patterns)) {
10940 listRewind(server.pubsub_patterns,&li);
10941 channel = getDecodedObject(channel);
10942 while ((ln = listNext(&li)) != NULL) {
10943 pubsubPattern *pat = ln->value;
10944
10945 if (stringmatchlen((char*)pat->pattern->ptr,
10946 sdslen(pat->pattern->ptr),
10947 (char*)channel->ptr,
10948 sdslen(channel->ptr),0)) {
c8d0ea0e 10949 addReply(pat->client,shared.mbulk4);
10950 addReply(pat->client,shared.pmessagebulk);
10951 addReplyBulk(pat->client,pat->pattern);
ffc6b7f8 10952 addReplyBulk(pat->client,channel);
10953 addReplyBulk(pat->client,message);
10954 receivers++;
10955 }
10956 }
10957 decrRefCount(channel);
10958 }
befec3cd 10959 return receivers;
10960}
10961
10962static void subscribeCommand(redisClient *c) {
10963 int j;
10964
10965 for (j = 1; j < c->argc; j++)
ffc6b7f8 10966 pubsubSubscribeChannel(c,c->argv[j]);
befec3cd 10967}
10968
10969static void unsubscribeCommand(redisClient *c) {
10970 if (c->argc == 1) {
ffc6b7f8 10971 pubsubUnsubscribeAllChannels(c,1);
10972 return;
10973 } else {
10974 int j;
10975
10976 for (j = 1; j < c->argc; j++)
10977 pubsubUnsubscribeChannel(c,c->argv[j],1);
10978 }
10979}
10980
10981static void psubscribeCommand(redisClient *c) {
10982 int j;
10983
10984 for (j = 1; j < c->argc; j++)
10985 pubsubSubscribePattern(c,c->argv[j]);
10986}
10987
10988static void punsubscribeCommand(redisClient *c) {
10989 if (c->argc == 1) {
10990 pubsubUnsubscribeAllPatterns(c,1);
befec3cd 10991 return;
10992 } else {
10993 int j;
10994
10995 for (j = 1; j < c->argc; j++)
ffc6b7f8 10996 pubsubUnsubscribePattern(c,c->argv[j],1);
befec3cd 10997 }
10998}
10999
11000static void publishCommand(redisClient *c) {
11001 int receivers = pubsubPublishMessage(c->argv[1],c->argv[2]);
482b672d 11002 addReplyLongLong(c,receivers);
befec3cd 11003}
11004
37ab76c9 11005/* ===================== WATCH (CAS alike for MULTI/EXEC) ===================
11006 *
11007 * The implementation uses a per-DB hash table mapping keys to list of clients
11008 * WATCHing those keys, so that given a key that is going to be modified
11009 * we can mark all the associated clients as dirty.
11010 *
11011 * Also every client contains a list of WATCHed keys so that's possible to
11012 * un-watch such keys when the client is freed or when UNWATCH is called. */
11013
11014/* In the client->watched_keys list we need to use watchedKey structures
11015 * as in order to identify a key in Redis we need both the key name and the
11016 * DB */
11017typedef struct watchedKey {
11018 robj *key;
11019 redisDb *db;
11020} watchedKey;
11021
11022/* Watch for the specified key */
11023static void watchForKey(redisClient *c, robj *key) {
11024 list *clients = NULL;
11025 listIter li;
11026 listNode *ln;
11027 watchedKey *wk;
11028
11029 /* Check if we are already watching for this key */
11030 listRewind(c->watched_keys,&li);
11031 while((ln = listNext(&li))) {
11032 wk = listNodeValue(ln);
11033 if (wk->db == c->db && equalStringObjects(key,wk->key))
11034 return; /* Key already watched */
11035 }
11036 /* This key is not already watched in this DB. Let's add it */
11037 clients = dictFetchValue(c->db->watched_keys,key);
11038 if (!clients) {
11039 clients = listCreate();
11040 dictAdd(c->db->watched_keys,key,clients);
11041 incrRefCount(key);
11042 }
11043 listAddNodeTail(clients,c);
11044 /* Add the new key to the lits of keys watched by this client */
11045 wk = zmalloc(sizeof(*wk));
11046 wk->key = key;
11047 wk->db = c->db;
11048 incrRefCount(key);
11049 listAddNodeTail(c->watched_keys,wk);
11050}
11051
11052/* Unwatch all the keys watched by this client. To clean the EXEC dirty
11053 * flag is up to the caller. */
11054static void unwatchAllKeys(redisClient *c) {
11055 listIter li;
11056 listNode *ln;
11057
11058 if (listLength(c->watched_keys) == 0) return;
11059 listRewind(c->watched_keys,&li);
11060 while((ln = listNext(&li))) {
11061 list *clients;
11062 watchedKey *wk;
11063
11064 /* Lookup the watched key -> clients list and remove the client
11065 * from the list */
11066 wk = listNodeValue(ln);
11067 clients = dictFetchValue(wk->db->watched_keys, wk->key);
11068 assert(clients != NULL);
11069 listDelNode(clients,listSearchKey(clients,c));
11070 /* Kill the entry at all if this was the only client */
11071 if (listLength(clients) == 0)
11072 dictDelete(wk->db->watched_keys, wk->key);
11073 /* Remove this watched key from the client->watched list */
11074 listDelNode(c->watched_keys,ln);
11075 decrRefCount(wk->key);
11076 zfree(wk);
11077 }
11078}
11079
ca3f830b 11080/* "Touch" a key, so that if this key is being WATCHed by some client the
37ab76c9 11081 * next EXEC will fail. */
11082static void touchWatchedKey(redisDb *db, robj *key) {
11083 list *clients;
11084 listIter li;
11085 listNode *ln;
11086
11087 if (dictSize(db->watched_keys) == 0) return;
11088 clients = dictFetchValue(db->watched_keys, key);
11089 if (!clients) return;
11090
11091 /* Mark all the clients watching this key as REDIS_DIRTY_CAS */
11092 /* Check if we are already watching for this key */
11093 listRewind(clients,&li);
11094 while((ln = listNext(&li))) {
11095 redisClient *c = listNodeValue(ln);
11096
11097 c->flags |= REDIS_DIRTY_CAS;
11098 }
11099}
11100
9b30e1a2 11101/* On FLUSHDB or FLUSHALL all the watched keys that are present before the
11102 * flush but will be deleted as effect of the flushing operation should
11103 * be touched. "dbid" is the DB that's getting the flush. -1 if it is
11104 * a FLUSHALL operation (all the DBs flushed). */
11105static void touchWatchedKeysOnFlush(int dbid) {
11106 listIter li1, li2;
11107 listNode *ln;
11108
11109 /* For every client, check all the waited keys */
11110 listRewind(server.clients,&li1);
11111 while((ln = listNext(&li1))) {
11112 redisClient *c = listNodeValue(ln);
11113 listRewind(c->watched_keys,&li2);
11114 while((ln = listNext(&li2))) {
11115 watchedKey *wk = listNodeValue(ln);
11116
11117 /* For every watched key matching the specified DB, if the
11118 * key exists, mark the client as dirty, as the key will be
11119 * removed. */
11120 if (dbid == -1 || wk->db->id == dbid) {
09241813 11121 if (dictFind(wk->db->dict, wk->key->ptr) != NULL)
9b30e1a2 11122 c->flags |= REDIS_DIRTY_CAS;
11123 }
11124 }
11125 }
11126}
11127
37ab76c9 11128static void watchCommand(redisClient *c) {
11129 int j;
11130
6531c94d 11131 if (c->flags & REDIS_MULTI) {
11132 addReplySds(c,sdsnew("-ERR WATCH inside MULTI is not allowed\r\n"));
11133 return;
11134 }
37ab76c9 11135 for (j = 1; j < c->argc; j++)
11136 watchForKey(c,c->argv[j]);
11137 addReply(c,shared.ok);
11138}
11139
11140static void unwatchCommand(redisClient *c) {
11141 unwatchAllKeys(c);
11142 c->flags &= (~REDIS_DIRTY_CAS);
11143 addReply(c,shared.ok);
11144}
11145
7f957c92 11146/* ================================= Debugging ============================== */
11147
ba798261 11148/* Compute the sha1 of string at 's' with 'len' bytes long.
11149 * The SHA1 is then xored againt the string pointed by digest.
11150 * Since xor is commutative, this operation is used in order to
11151 * "add" digests relative to unordered elements.
11152 *
11153 * So digest(a,b,c,d) will be the same of digest(b,a,c,d) */
11154static void xorDigest(unsigned char *digest, void *ptr, size_t len) {
11155 SHA1_CTX ctx;
11156 unsigned char hash[20], *s = ptr;
11157 int j;
11158
11159 SHA1Init(&ctx);
11160 SHA1Update(&ctx,s,len);
11161 SHA1Final(hash,&ctx);
11162
11163 for (j = 0; j < 20; j++)
11164 digest[j] ^= hash[j];
11165}
11166
11167static void xorObjectDigest(unsigned char *digest, robj *o) {
11168 o = getDecodedObject(o);
11169 xorDigest(digest,o->ptr,sdslen(o->ptr));
11170 decrRefCount(o);
11171}
11172
11173/* This function instead of just computing the SHA1 and xoring it
11174 * against diget, also perform the digest of "digest" itself and
11175 * replace the old value with the new one.
11176 *
11177 * So the final digest will be:
11178 *
11179 * digest = SHA1(digest xor SHA1(data))
11180 *
11181 * This function is used every time we want to preserve the order so
11182 * that digest(a,b,c,d) will be different than digest(b,c,d,a)
11183 *
11184 * Also note that mixdigest("foo") followed by mixdigest("bar")
11185 * will lead to a different digest compared to "fo", "obar".
11186 */
11187static void mixDigest(unsigned char *digest, void *ptr, size_t len) {
11188 SHA1_CTX ctx;
11189 char *s = ptr;
11190
11191 xorDigest(digest,s,len);
11192 SHA1Init(&ctx);
11193 SHA1Update(&ctx,digest,20);
11194 SHA1Final(digest,&ctx);
11195}
11196
11197static void mixObjectDigest(unsigned char *digest, robj *o) {
11198 o = getDecodedObject(o);
11199 mixDigest(digest,o->ptr,sdslen(o->ptr));
11200 decrRefCount(o);
11201}
11202
11203/* Compute the dataset digest. Since keys, sets elements, hashes elements
11204 * are not ordered, we use a trick: every aggregate digest is the xor
11205 * of the digests of their elements. This way the order will not change
11206 * the result. For list instead we use a feedback entering the output digest
11207 * as input in order to ensure that a different ordered list will result in
11208 * a different digest. */
11209static void computeDatasetDigest(unsigned char *final) {
11210 unsigned char digest[20];
11211 char buf[128];
11212 dictIterator *di = NULL;
11213 dictEntry *de;
11214 int j;
11215 uint32_t aux;
11216
11217 memset(final,0,20); /* Start with a clean result */
11218
11219 for (j = 0; j < server.dbnum; j++) {
11220 redisDb *db = server.db+j;
11221
11222 if (dictSize(db->dict) == 0) continue;
11223 di = dictGetIterator(db->dict);
11224
11225 /* hash the DB id, so the same dataset moved in a different
11226 * DB will lead to a different digest */
11227 aux = htonl(j);
11228 mixDigest(final,&aux,sizeof(aux));
11229
11230 /* Iterate this DB writing every entry */
11231 while((de = dictNext(di)) != NULL) {
09241813 11232 sds key;
11233 robj *keyobj, *o;
ba798261 11234 time_t expiretime;
11235
11236 memset(digest,0,20); /* This key-val digest */
11237 key = dictGetEntryKey(de);
09241813 11238 keyobj = createStringObject(key,sdslen(key));
11239
11240 mixDigest(digest,key,sdslen(key));
11241
11242 /* Make sure the key is loaded if VM is active */
11243 o = lookupKeyRead(db,keyobj);
cbae1d34 11244
ba798261 11245 aux = htonl(o->type);
11246 mixDigest(digest,&aux,sizeof(aux));
09241813 11247 expiretime = getExpire(db,keyobj);
ba798261 11248
11249 /* Save the key and associated value */
11250 if (o->type == REDIS_STRING) {
11251 mixObjectDigest(digest,o);
11252 } else if (o->type == REDIS_LIST) {
003f0840
PN
11253 listTypeIterator *li = listTypeInitIterator(o,0,REDIS_TAIL);
11254 listTypeEntry entry;
11255 while(listTypeNext(li,&entry)) {
11256 robj *eleobj = listTypeGet(&entry);
ba798261 11257 mixObjectDigest(digest,eleobj);
dc845730 11258 decrRefCount(eleobj);
ba798261 11259 }
003f0840 11260 listTypeReleaseIterator(li);
ba798261 11261 } else if (o->type == REDIS_SET) {
11262 dict *set = o->ptr;
11263 dictIterator *di = dictGetIterator(set);
11264 dictEntry *de;
11265
11266 while((de = dictNext(di)) != NULL) {
11267 robj *eleobj = dictGetEntryKey(de);
11268
11269 xorObjectDigest(digest,eleobj);
11270 }
11271 dictReleaseIterator(di);
11272 } else if (o->type == REDIS_ZSET) {
11273 zset *zs = o->ptr;
11274 dictIterator *di = dictGetIterator(zs->dict);
11275 dictEntry *de;
11276
11277 while((de = dictNext(di)) != NULL) {
11278 robj *eleobj = dictGetEntryKey(de);
11279 double *score = dictGetEntryVal(de);
11280 unsigned char eledigest[20];
11281
11282 snprintf(buf,sizeof(buf),"%.17g",*score);
11283 memset(eledigest,0,20);
11284 mixObjectDigest(eledigest,eleobj);
11285 mixDigest(eledigest,buf,strlen(buf));
11286 xorDigest(digest,eledigest,20);
11287 }
11288 dictReleaseIterator(di);
11289 } else if (o->type == REDIS_HASH) {
d1578a33 11290 hashTypeIterator *hi;
ba798261 11291 robj *obj;
11292
d1578a33
PN
11293 hi = hashTypeInitIterator(o);
11294 while (hashTypeNext(hi) != REDIS_ERR) {
ba798261 11295 unsigned char eledigest[20];
11296
11297 memset(eledigest,0,20);
d1578a33 11298 obj = hashTypeCurrent(hi,REDIS_HASH_KEY);
ba798261 11299 mixObjectDigest(eledigest,obj);
11300 decrRefCount(obj);
d1578a33 11301 obj = hashTypeCurrent(hi,REDIS_HASH_VALUE);
ba798261 11302 mixObjectDigest(eledigest,obj);
11303 decrRefCount(obj);
11304 xorDigest(digest,eledigest,20);
11305 }
d1578a33 11306 hashTypeReleaseIterator(hi);
ba798261 11307 } else {
11308 redisPanic("Unknown object type");
11309 }
ba798261 11310 /* If the key has an expire, add it to the mix */
11311 if (expiretime != -1) xorDigest(digest,"!!expire!!",10);
11312 /* We can finally xor the key-val digest to the final digest */
11313 xorDigest(final,digest,20);
09241813 11314 decrRefCount(keyobj);
ba798261 11315 }
11316 dictReleaseIterator(di);
11317 }
11318}
11319
7f957c92 11320static void debugCommand(redisClient *c) {
11321 if (!strcasecmp(c->argv[1]->ptr,"segfault")) {
11322 *((char*)-1) = 'x';
210e29f7 11323 } else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
11324 if (rdbSave(server.dbfilename) != REDIS_OK) {
11325 addReply(c,shared.err);
11326 return;
11327 }
11328 emptyDb();
11329 if (rdbLoad(server.dbfilename) != REDIS_OK) {
11330 addReply(c,shared.err);
11331 return;
11332 }
11333 redisLog(REDIS_WARNING,"DB reloaded by DEBUG RELOAD");
11334 addReply(c,shared.ok);
71c2b467 11335 } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) {
11336 emptyDb();
11337 if (loadAppendOnlyFile(server.appendfilename) != REDIS_OK) {
11338 addReply(c,shared.err);
11339 return;
11340 }
11341 redisLog(REDIS_WARNING,"Append Only File loaded by DEBUG LOADAOF");
11342 addReply(c,shared.ok);
333298da 11343 } else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
09241813 11344 dictEntry *de = dictFind(c->db->dict,c->argv[2]->ptr);
11345 robj *val;
333298da 11346
11347 if (!de) {
11348 addReply(c,shared.nokeyerr);
11349 return;
11350 }
333298da 11351 val = dictGetEntryVal(de);
560db612 11352 if (!server.vm_enabled || (val->storage == REDIS_VM_MEMORY ||
11353 val->storage == REDIS_VM_SWAPPING)) {
07efaf74 11354 char *strenc;
11355 char buf[128];
11356
11357 if (val->encoding < (sizeof(strencoding)/sizeof(char*))) {
11358 strenc = strencoding[val->encoding];
11359 } else {
11360 snprintf(buf,64,"unknown encoding %d\n", val->encoding);
11361 strenc = buf;
11362 }
ace06542 11363 addReplySds(c,sdscatprintf(sdsempty(),
09241813 11364 "+Value at:%p refcount:%d "
07efaf74 11365 "encoding:%s serializedlength:%lld\r\n",
09241813 11366 (void*)val, val->refcount,
07efaf74 11367 strenc, (long long) rdbSavedObjectLen(val,NULL)));
ace06542 11368 } else {
560db612 11369 vmpointer *vp = (vmpointer*) val;
ace06542 11370 addReplySds(c,sdscatprintf(sdsempty(),
09241813 11371 "+Value swapped at: page %llu "
ace06542 11372 "using %llu pages\r\n",
09241813 11373 (unsigned long long) vp->page,
560db612 11374 (unsigned long long) vp->usedpages));
ace06542 11375 }
78ebe4c8 11376 } else if (!strcasecmp(c->argv[1]->ptr,"swapin") && c->argc == 3) {
11377 lookupKeyRead(c->db,c->argv[2]);
11378 addReply(c,shared.ok);
7d30035d 11379 } else if (!strcasecmp(c->argv[1]->ptr,"swapout") && c->argc == 3) {
09241813 11380 dictEntry *de = dictFind(c->db->dict,c->argv[2]->ptr);
11381 robj *val;
560db612 11382 vmpointer *vp;
7d30035d 11383
11384 if (!server.vm_enabled) {
11385 addReplySds(c,sdsnew("-ERR Virtual Memory is disabled\r\n"));
11386 return;
11387 }
11388 if (!de) {
11389 addReply(c,shared.nokeyerr);
11390 return;
11391 }
7d30035d 11392 val = dictGetEntryVal(de);
4ef8de8a 11393 /* Swap it */
560db612 11394 if (val->storage != REDIS_VM_MEMORY) {
7d30035d 11395 addReplySds(c,sdsnew("-ERR This key is not in memory\r\n"));
560db612 11396 } else if (val->refcount != 1) {
11397 addReplySds(c,sdsnew("-ERR Object is shared\r\n"));
11398 } else if ((vp = vmSwapObjectBlocking(val)) != NULL) {
11399 dictGetEntryVal(de) = vp;
7d30035d 11400 addReply(c,shared.ok);
11401 } else {
11402 addReply(c,shared.err);
11403 }
59305dc7 11404 } else if (!strcasecmp(c->argv[1]->ptr,"populate") && c->argc == 3) {
11405 long keys, j;
11406 robj *key, *val;
11407 char buf[128];
11408
11409 if (getLongFromObjectOrReply(c, c->argv[2], &keys, NULL) != REDIS_OK)
11410 return;
11411 for (j = 0; j < keys; j++) {
11412 snprintf(buf,sizeof(buf),"key:%lu",j);
11413 key = createStringObject(buf,strlen(buf));
11414 if (lookupKeyRead(c->db,key) != NULL) {
11415 decrRefCount(key);
11416 continue;
11417 }
11418 snprintf(buf,sizeof(buf),"value:%lu",j);
11419 val = createStringObject(buf,strlen(buf));
09241813 11420 dbAdd(c->db,key,val);
11421 decrRefCount(key);
59305dc7 11422 }
11423 addReply(c,shared.ok);
ba798261 11424 } else if (!strcasecmp(c->argv[1]->ptr,"digest") && c->argc == 2) {
11425 unsigned char digest[20];
11426 sds d = sdsnew("+");
11427 int j;
11428
11429 computeDatasetDigest(digest);
11430 for (j = 0; j < 20; j++)
11431 d = sdscatprintf(d, "%02x",digest[j]);
11432
11433 d = sdscatlen(d,"\r\n",2);
11434 addReplySds(c,d);
7f957c92 11435 } else {
333298da 11436 addReplySds(c,sdsnew(
bdcb92f2 11437 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPIN <key>|SWAPOUT <key>|RELOAD]\r\n"));
7f957c92 11438 }
11439}
56906eef 11440
6c96ba7d 11441static void _redisAssert(char *estr, char *file, int line) {
dfc5e96c 11442 redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
fdfb02e7 11443 redisLog(REDIS_WARNING,"==> %s:%d '%s' is not true",file,line,estr);
dfc5e96c 11444#ifdef HAVE_BACKTRACE
11445 redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
11446 *((char*)-1) = 'x';
11447#endif
11448}
11449
c651fd9e 11450static void _redisPanic(char *msg, char *file, int line) {
11451 redisLog(REDIS_WARNING,"!!! Software Failure. Press left mouse button to continue");
17772754 11452 redisLog(REDIS_WARNING,"Guru Meditation: %s #%s:%d",msg,file,line);
c651fd9e 11453#ifdef HAVE_BACKTRACE
11454 redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
11455 *((char*)-1) = 'x';
11456#endif
11457}
11458
bcfc686d 11459/* =================================== Main! ================================ */
56906eef 11460
bcfc686d 11461#ifdef __linux__
11462int linuxOvercommitMemoryValue(void) {
11463 FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
11464 char buf[64];
56906eef 11465
bcfc686d 11466 if (!fp) return -1;
11467 if (fgets(buf,64,fp) == NULL) {
11468 fclose(fp);
11469 return -1;
11470 }
11471 fclose(fp);
56906eef 11472
bcfc686d 11473 return atoi(buf);
11474}
11475
11476void linuxOvercommitMemoryWarning(void) {
11477 if (linuxOvercommitMemoryValue() == 0) {
7ccd2d0a 11478 redisLog(REDIS_WARNING,"WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. 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.");
bcfc686d 11479 }
11480}
11481#endif /* __linux__ */
11482
11483static void daemonize(void) {
11484 int fd;
11485 FILE *fp;
11486
11487 if (fork() != 0) exit(0); /* parent exits */
11488 setsid(); /* create a new session */
11489
11490 /* Every output goes to /dev/null. If Redis is daemonized but
11491 * the 'logfile' is set to 'stdout' in the configuration file
11492 * it will not log at all. */
11493 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
11494 dup2(fd, STDIN_FILENO);
11495 dup2(fd, STDOUT_FILENO);
11496 dup2(fd, STDERR_FILENO);
11497 if (fd > STDERR_FILENO) close(fd);
11498 }
11499 /* Try to write the pid file */
11500 fp = fopen(server.pidfile,"w");
11501 if (fp) {
11502 fprintf(fp,"%d\n",getpid());
11503 fclose(fp);
56906eef 11504 }
56906eef 11505}
11506
42ab0172 11507static void version() {
8a3b0d2d 11508 printf("Redis server version %s (%s:%d)\n", REDIS_VERSION,
11509 REDIS_GIT_SHA1, atoi(REDIS_GIT_DIRTY) > 0);
42ab0172
AO
11510 exit(0);
11511}
11512
723fb69b
AO
11513static void usage() {
11514 fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
e9409273 11515 fprintf(stderr," ./redis-server - (read config from stdin)\n");
723fb69b
AO
11516 exit(1);
11517}
11518
bcfc686d 11519int main(int argc, char **argv) {
9651a787 11520 time_t start;
11521
bcfc686d 11522 initServerConfig();
1a132bbc 11523 sortCommandTable();
bcfc686d 11524 if (argc == 2) {
44efe66e 11525 if (strcmp(argv[1], "-v") == 0 ||
11526 strcmp(argv[1], "--version") == 0) version();
11527 if (strcmp(argv[1], "--help") == 0) usage();
bcfc686d 11528 resetServerSaveParams();
11529 loadServerConfig(argv[1]);
723fb69b
AO
11530 } else if ((argc > 2)) {
11531 usage();
bcfc686d 11532 } else {
11533 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'");
11534 }
bcfc686d 11535 if (server.daemonize) daemonize();
71c54b21 11536 initServer();
bcfc686d 11537 redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
11538#ifdef __linux__
11539 linuxOvercommitMemoryWarning();
11540#endif
9651a787 11541 start = time(NULL);
bcfc686d 11542 if (server.appendonly) {
11543 if (loadAppendOnlyFile(server.appendfilename) == REDIS_OK)
9651a787 11544 redisLog(REDIS_NOTICE,"DB loaded from append only file: %ld seconds",time(NULL)-start);
bcfc686d 11545 } else {
11546 if (rdbLoad(server.dbfilename) == REDIS_OK)
9651a787 11547 redisLog(REDIS_NOTICE,"DB loaded from disk: %ld seconds",time(NULL)-start);
bcfc686d 11548 }
bcfc686d 11549 redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
d5d55fc3 11550 aeSetBeforeSleepProc(server.el,beforeSleep);
bcfc686d 11551 aeMain(server.el);
11552 aeDeleteEventLoop(server.el);
11553 return 0;
11554}
11555
11556/* ============================= Backtrace support ========================= */
11557
11558#ifdef HAVE_BACKTRACE
11559static char *findFuncName(void *pointer, unsigned long *offset);
11560
56906eef 11561static void *getMcontextEip(ucontext_t *uc) {
11562#if defined(__FreeBSD__)
11563 return (void*) uc->uc_mcontext.mc_eip;
11564#elif defined(__dietlibc__)
11565 return (void*) uc->uc_mcontext.eip;
06db1f50 11566#elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
da0a1620 11567 #if __x86_64__
11568 return (void*) uc->uc_mcontext->__ss.__rip;
11569 #else
56906eef 11570 return (void*) uc->uc_mcontext->__ss.__eip;
da0a1620 11571 #endif
06db1f50 11572#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
cb7e07cc 11573 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
06db1f50 11574 return (void*) uc->uc_mcontext->__ss.__rip;
cbc59b38 11575 #else
11576 return (void*) uc->uc_mcontext->__ss.__eip;
e0a62c7f 11577 #endif
54bac49d 11578#elif defined(__i386__) || defined(__X86_64__) || defined(__x86_64__)
c04c9ac9 11579 return (void*) uc->uc_mcontext.gregs[REG_EIP]; /* Linux 32/64 bit */
b91cf5ef 11580#elif defined(__ia64__) /* Linux IA64 */
11581 return (void*) uc->uc_mcontext.sc_ip;
11582#else
11583 return NULL;
56906eef 11584#endif
11585}
11586
11587static void segvHandler(int sig, siginfo_t *info, void *secret) {
11588 void *trace[100];
11589 char **messages = NULL;
11590 int i, trace_size = 0;
11591 unsigned long offset=0;
56906eef 11592 ucontext_t *uc = (ucontext_t*) secret;
1c85b79f 11593 sds infostring;
56906eef 11594 REDIS_NOTUSED(info);
11595
11596 redisLog(REDIS_WARNING,
11597 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION, sig);
1c85b79f 11598 infostring = genRedisInfoString();
11599 redisLog(REDIS_WARNING, "%s",infostring);
11600 /* It's not safe to sdsfree() the returned string under memory
11601 * corruption conditions. Let it leak as we are going to abort */
e0a62c7f 11602
56906eef 11603 trace_size = backtrace(trace, 100);
de96dbfe 11604 /* overwrite sigaction with caller's address */
b91cf5ef 11605 if (getMcontextEip(uc) != NULL) {
11606 trace[1] = getMcontextEip(uc);
11607 }
56906eef 11608 messages = backtrace_symbols(trace, trace_size);
fe3bbfbe 11609
d76412d1 11610 for (i=1; i<trace_size; ++i) {
56906eef 11611 char *fn = findFuncName(trace[i], &offset), *p;
11612
11613 p = strchr(messages[i],'+');
11614 if (!fn || (p && ((unsigned long)strtol(p+1,NULL,10)) < offset)) {
11615 redisLog(REDIS_WARNING,"%s", messages[i]);
11616 } else {
11617 redisLog(REDIS_WARNING,"%d redis-server %p %s + %d", i, trace[i], fn, (unsigned int)offset);
11618 }
11619 }
b177fd30 11620 /* free(messages); Don't call free() with possibly corrupted memory. */
478c2c6f 11621 _exit(0);
fe3bbfbe 11622}
56906eef 11623
fab43727 11624static void sigtermHandler(int sig) {
11625 REDIS_NOTUSED(sig);
b58ba105 11626
fab43727 11627 redisLog(REDIS_WARNING,"SIGTERM received, scheduling shutting down...");
11628 server.shutdown_asap = 1;
b58ba105
AM
11629}
11630
56906eef 11631static void setupSigSegvAction(void) {
11632 struct sigaction act;
11633
11634 sigemptyset (&act.sa_mask);
11635 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
11636 * is used. Otherwise, sa_handler is used */
11637 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
11638 act.sa_sigaction = segvHandler;
11639 sigaction (SIGSEGV, &act, NULL);
11640 sigaction (SIGBUS, &act, NULL);
12fea928 11641 sigaction (SIGFPE, &act, NULL);
11642 sigaction (SIGILL, &act, NULL);
11643 sigaction (SIGBUS, &act, NULL);
b58ba105
AM
11644
11645 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
fab43727 11646 act.sa_handler = sigtermHandler;
b58ba105 11647 sigaction (SIGTERM, &act, NULL);
e65fdc78 11648 return;
56906eef 11649}
e65fdc78 11650
bcfc686d 11651#include "staticsymbols.h"
11652/* This function try to convert a pointer into a function name. It's used in
11653 * oreder to provide a backtrace under segmentation fault that's able to
11654 * display functions declared as static (otherwise the backtrace is useless). */
11655static char *findFuncName(void *pointer, unsigned long *offset){
11656 int i, ret = -1;
11657 unsigned long off, minoff = 0;
ed9b544e 11658
bcfc686d 11659 /* Try to match against the Symbol with the smallest offset */
11660 for (i=0; symsTable[i].pointer; i++) {
11661 unsigned long lp = (unsigned long) pointer;
0bc03378 11662
bcfc686d 11663 if (lp != (unsigned long)-1 && lp >= symsTable[i].pointer) {
11664 off=lp-symsTable[i].pointer;
11665 if (ret < 0 || off < minoff) {
11666 minoff=off;
11667 ret=i;
11668 }
11669 }
0bc03378 11670 }
bcfc686d 11671 if (ret == -1) return NULL;
11672 *offset = minoff;
11673 return symsTable[ret].name;
0bc03378 11674}
bcfc686d 11675#else /* HAVE_BACKTRACE */
11676static void setupSigSegvAction(void) {
0bc03378 11677}
bcfc686d 11678#endif /* HAVE_BACKTRACE */
0bc03378 11679
ed9b544e 11680
ed9b544e 11681
bcfc686d 11682/* The End */
11683
11684
ed9b544e 11685