]> git.saurik.com Git - redis.git/blame - redis.c
small refactor of SMOVE and tests for SMOVE on sets with different encoding
[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) {
b978abbf 5697 robj *srcset, *dstset, *ele;
a4460ef4 5698 srcset = lookupKeyWrite(c->db,c->argv[1]);
5699 dstset = lookupKeyWrite(c->db,c->argv[2]);
b978abbf 5700 ele = c->argv[3];
a4460ef4 5701
b978abbf
PN
5702 /* If the source key does not exist return 0 */
5703 if (srcset == NULL) {
5704 addReply(c,shared.czero);
a4460ef4 5705 return;
5706 }
b978abbf
PN
5707
5708 /* If the source key has the wrong type, or the destination key
5709 * is set and has the wrong type, return with an error. */
5710 if (checkType(c,srcset,REDIS_SET) ||
5711 (dstset && checkType(c,dstset,REDIS_SET))) return;
5712
5713 /* If srcset and dstset are equal, SMOVE is a no-op */
5714 if (srcset == dstset) {
5715 addReply(c,shared.cone);
a4460ef4 5716 return;
5717 }
b978abbf
PN
5718
5719 /* If the element cannot be removed from the src set, return 0. */
5720 if (!setTypeRemove(srcset,ele)) {
a4460ef4 5721 addReply(c,shared.czero);
5722 return;
5723 }
b978abbf
PN
5724
5725 /* Remove the src set from the database when empty */
5726 if (setTypeSize(srcset) == 0) dbDelete(c->db,c->argv[1]);
a4460ef4 5727 server.dirty++;
b978abbf
PN
5728
5729 /* Create the destination set when it doesn't exist */
a4460ef4 5730 if (!dstset) {
b978abbf 5731 dstset = setTypeCreate(ele);
09241813 5732 dbAdd(c->db,c->argv[2],dstset);
a4460ef4 5733 }
b978abbf
PN
5734
5735 /* An extra key has changed when ele was successfully added to dstset */
5736 if (setTypeAdd(dstset,ele)) server.dirty++;
a4460ef4 5737 addReply(c,shared.cone);
5738}
5739
ed9b544e 5740static void sismemberCommand(redisClient *c) {
3305306f 5741 robj *set;
ed9b544e 5742
dd88747b 5743 if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
5744 checkType(c,set,REDIS_SET)) return;
5745
35cabcb5 5746 if (setTypeIsMember(set,c->argv[2]))
dd88747b 5747 addReply(c,shared.cone);
5748 else
c937aa89 5749 addReply(c,shared.czero);
ed9b544e 5750}
5751
5752static void scardCommand(redisClient *c) {
3305306f 5753 robj *o;
dd88747b 5754
5755 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
5756 checkType(c,o,REDIS_SET)) return;
e0a62c7f 5757
35cabcb5 5758 addReplyUlong(c,setTypeSize(o));
ed9b544e 5759}
5760
12fea928 5761static void spopCommand(redisClient *c) {
35cabcb5 5762 robj *set, *ele;
12fea928 5763
dd88747b 5764 if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
5765 checkType(c,set,REDIS_SET)) return;
5766
35cabcb5
PN
5767 ele = setTypeRandomElement(set);
5768 if (ele == NULL) {
12fea928 5769 addReply(c,shared.nullbulk);
5770 } else {
35cabcb5 5771 setTypeRemove(set,ele);
dd88747b 5772 addReplyBulk(c,ele);
35cabcb5
PN
5773 decrRefCount(ele);
5774 if (setTypeSize(set) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5775 server.dirty++;
12fea928 5776 }
5777}
5778
2abb95a9 5779static void srandmemberCommand(redisClient *c) {
35cabcb5 5780 robj *set, *ele;
2abb95a9 5781
dd88747b 5782 if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
5783 checkType(c,set,REDIS_SET)) return;
5784
35cabcb5
PN
5785 ele = setTypeRandomElement(set);
5786 if (ele == NULL) {
2abb95a9 5787 addReply(c,shared.nullbulk);
5788 } else {
dd88747b 5789 addReplyBulk(c,ele);
35cabcb5 5790 decrRefCount(ele);
2abb95a9 5791 }
5792}
5793
ed9b544e 5794static int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
35cabcb5 5795 return setTypeSize(*(robj**)s1)-setTypeSize(*(robj**)s2);
ed9b544e 5796}
5797
35cabcb5
PN
5798static void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum, robj *dstkey) {
5799 robj **sets = zmalloc(sizeof(robj*)*setnum);
5800 setIterator *si;
5801 robj *ele, *lenobj = NULL, *dstset = NULL;
682ac724 5802 unsigned long j, cardinality = 0;
ed9b544e 5803
35cabcb5
PN
5804 for (j = 0; j < setnum; j++) {
5805 robj *setobj = dstkey ?
5806 lookupKeyWrite(c->db,setkeys[j]) :
5807 lookupKeyRead(c->db,setkeys[j]);
3305306f 5808 if (!setobj) {
35cabcb5 5809 zfree(sets);
5faa6025 5810 if (dstkey) {
09241813 5811 if (dbDelete(c->db,dstkey))
fdcaae84 5812 server.dirty++;
0d36ded0 5813 addReply(c,shared.czero);
5faa6025 5814 } else {
4e27f268 5815 addReply(c,shared.emptymultibulk);
5faa6025 5816 }
ed9b544e 5817 return;
5818 }
35cabcb5
PN
5819 if (checkType(c,setobj,REDIS_SET)) {
5820 zfree(sets);
ed9b544e 5821 return;
5822 }
35cabcb5 5823 sets[j] = setobj;
ed9b544e 5824 }
5825 /* Sort sets from the smallest to largest, this will improve our
5826 * algorithm's performace */
35cabcb5 5827 qsort(sets,setnum,sizeof(robj*),qsortCompareSetsByCardinality);
ed9b544e 5828
5829 /* The first thing we should output is the total number of elements...
5830 * since this is a multi-bulk write, but at this stage we don't know
5831 * the intersection set size, so we use a trick, append an empty object
5832 * to the output list and save the pointer to later modify it with the
5833 * right length */
5834 if (!dstkey) {
5835 lenobj = createObject(REDIS_STRING,NULL);
5836 addReply(c,lenobj);
5837 decrRefCount(lenobj);
5838 } else {
5839 /* If we have a target key where to store the resulting set
5840 * create this key with an empty set inside */
d0b58d53 5841 dstset = createIntsetObject();
ed9b544e 5842 }
5843
5844 /* Iterate all the elements of the first (smallest) set, and test
5845 * the element against all the other sets, if at least one set does
5846 * not include the element it is discarded */
35cabcb5
PN
5847 si = setTypeInitIterator(sets[0]);
5848 while((ele = setTypeNext(si)) != NULL) {
5849 for (j = 1; j < setnum; j++)
5850 if (!setTypeIsMember(sets[j],ele)) break;
5851
5852 /* Only take action when all sets contain the member */
5853 if (j == setnum) {
5854 if (!dstkey) {
5855 addReplyBulk(c,ele);
5856 cardinality++;
5857 } else {
5858 setTypeAdd(dstset,ele);
5859 }
ed9b544e 5860 }
35cabcb5 5861 decrRefCount(ele);
ed9b544e 5862 }
35cabcb5 5863 setTypeReleaseIterator(si);
ed9b544e 5864
83cdfe18 5865 if (dstkey) {
3ea27d37 5866 /* Store the resulting set into the target, if the intersection
5867 * is not an empty set. */
09241813 5868 dbDelete(c->db,dstkey);
35cabcb5 5869 if (setTypeSize(dstset) > 0) {
09241813 5870 dbAdd(c->db,dstkey,dstset);
35cabcb5 5871 addReplyLongLong(c,setTypeSize(dstset));
3ea27d37 5872 } else {
5873 decrRefCount(dstset);
d36c4e97 5874 addReply(c,shared.czero);
3ea27d37 5875 }
40d224a9 5876 server.dirty++;
d36c4e97 5877 } else {
5878 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",cardinality);
40d224a9 5879 }
35cabcb5 5880 zfree(sets);
ed9b544e 5881}
5882
5883static void sinterCommand(redisClient *c) {
5884 sinterGenericCommand(c,c->argv+1,c->argc-1,NULL);
5885}
5886
5887static void sinterstoreCommand(redisClient *c) {
5888 sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
5889}
5890
f4f56e1d 5891#define REDIS_OP_UNION 0
5892#define REDIS_OP_DIFF 1
2830ca53 5893#define REDIS_OP_INTER 2
f4f56e1d 5894
35cabcb5
PN
5895static void sunionDiffGenericCommand(redisClient *c, robj **setkeys, int setnum, robj *dstkey, int op) {
5896 robj **sets = zmalloc(sizeof(robj*)*setnum);
5897 setIterator *si;
5898 robj *ele, *dstset = NULL;
40d224a9 5899 int j, cardinality = 0;
5900
35cabcb5
PN
5901 for (j = 0; j < setnum; j++) {
5902 robj *setobj = dstkey ?
5903 lookupKeyWrite(c->db,setkeys[j]) :
5904 lookupKeyRead(c->db,setkeys[j]);
40d224a9 5905 if (!setobj) {
35cabcb5 5906 sets[j] = NULL;
40d224a9 5907 continue;
5908 }
35cabcb5
PN
5909 if (checkType(c,setobj,REDIS_SET)) {
5910 zfree(sets);
40d224a9 5911 return;
5912 }
35cabcb5 5913 sets[j] = setobj;
40d224a9 5914 }
5915
5916 /* We need a temp set object to store our union. If the dstkey
5917 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
5918 * this set object will be the resulting object to set into the target key*/
d0b58d53 5919 dstset = createIntsetObject();
40d224a9 5920
40d224a9 5921 /* Iterate all the elements of all the sets, add every element a single
5922 * time to the result set */
35cabcb5
PN
5923 for (j = 0; j < setnum; j++) {
5924 if (op == REDIS_OP_DIFF && j == 0 && !sets[j]) break; /* result set is empty */
5925 if (!sets[j]) continue; /* non existing keys are like empty sets */
40d224a9 5926
35cabcb5
PN
5927 si = setTypeInitIterator(sets[j]);
5928 while((ele = setTypeNext(si)) != NULL) {
f4f56e1d 5929 if (op == REDIS_OP_UNION || j == 0) {
35cabcb5 5930 if (setTypeAdd(dstset,ele)) {
40d224a9 5931 cardinality++;
5932 }
f4f56e1d 5933 } else if (op == REDIS_OP_DIFF) {
35cabcb5 5934 if (setTypeRemove(dstset,ele)) {
f4f56e1d 5935 cardinality--;
5936 }
40d224a9 5937 }
35cabcb5 5938 decrRefCount(ele);
40d224a9 5939 }
35cabcb5 5940 setTypeReleaseIterator(si);
51829ed3 5941
35cabcb5 5942 /* Exit when result set is empty. */
d36c4e97 5943 if (op == REDIS_OP_DIFF && cardinality == 0) break;
40d224a9 5944 }
5945
f4f56e1d 5946 /* Output the content of the resulting set, if not in STORE mode */
5947 if (!dstkey) {
5948 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",cardinality));
35cabcb5
PN
5949 si = setTypeInitIterator(dstset);
5950 while((ele = setTypeNext(si)) != NULL) {
dd88747b 5951 addReplyBulk(c,ele);
35cabcb5 5952 decrRefCount(ele);
f4f56e1d 5953 }
35cabcb5 5954 setTypeReleaseIterator(si);
d36c4e97 5955 decrRefCount(dstset);
83cdfe18
AG
5956 } else {
5957 /* If we have a target key where to store the resulting set
5958 * create this key with the result set inside */
09241813 5959 dbDelete(c->db,dstkey);
35cabcb5 5960 if (setTypeSize(dstset) > 0) {
09241813 5961 dbAdd(c->db,dstkey,dstset);
35cabcb5 5962 addReplyLongLong(c,setTypeSize(dstset));
3ea27d37 5963 } else {
5964 decrRefCount(dstset);
d36c4e97 5965 addReply(c,shared.czero);
3ea27d37 5966 }
40d224a9 5967 server.dirty++;
5968 }
35cabcb5 5969 zfree(sets);
40d224a9 5970}
5971
5972static void sunionCommand(redisClient *c) {
f4f56e1d 5973 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_UNION);
40d224a9 5974}
5975
5976static void sunionstoreCommand(redisClient *c) {
f4f56e1d 5977 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_UNION);
5978}
5979
5980static void sdiffCommand(redisClient *c) {
5981 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_DIFF);
5982}
5983
5984static void sdiffstoreCommand(redisClient *c) {
5985 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_DIFF);
40d224a9 5986}
5987
6b47e12e 5988/* ==================================== ZSets =============================== */
5989
5990/* ZSETs are ordered sets using two data structures to hold the same elements
5991 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
5992 * data structure.
5993 *
5994 * The elements are added to an hash table mapping Redis objects to scores.
5995 * At the same time the elements are added to a skip list mapping scores
5996 * to Redis objects (so objects are sorted by scores in this "view"). */
5997
5998/* This skiplist implementation is almost a C translation of the original
5999 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
6000 * Alternative to Balanced Trees", modified in three ways:
6001 * a) this implementation allows for repeated values.
6002 * b) the comparison is not just by key (our 'score') but by satellite data.
6003 * c) there is a back pointer, so it's a doubly linked list with the back
6004 * pointers being only at "level 1". This allows to traverse the list
6005 * from tail to head, useful for ZREVRANGE. */
6006
6007static zskiplistNode *zslCreateNode(int level, double score, robj *obj) {
6008 zskiplistNode *zn = zmalloc(sizeof(*zn));
6009
6010 zn->forward = zmalloc(sizeof(zskiplistNode*) * level);
2f4dd7e0 6011 if (level > 1)
2b37892e 6012 zn->span = zmalloc(sizeof(unsigned int) * (level - 1));
2f4dd7e0 6013 else
6014 zn->span = NULL;
6b47e12e 6015 zn->score = score;
6016 zn->obj = obj;
6017 return zn;
6018}
6019
6020static zskiplist *zslCreate(void) {
6021 int j;
6022 zskiplist *zsl;
e0a62c7f 6023
6b47e12e 6024 zsl = zmalloc(sizeof(*zsl));
6025 zsl->level = 1;
cc812361 6026 zsl->length = 0;
6b47e12e 6027 zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
69d95c3e 6028 for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
6b47e12e 6029 zsl->header->forward[j] = NULL;
94e543b5 6030
6031 /* span has space for ZSKIPLIST_MAXLEVEL-1 elements */
6032 if (j < ZSKIPLIST_MAXLEVEL-1)
6033 zsl->header->span[j] = 0;
69d95c3e 6034 }
e3870fab 6035 zsl->header->backward = NULL;
6036 zsl->tail = NULL;
6b47e12e 6037 return zsl;
6038}
6039
fd8ccf44 6040static void zslFreeNode(zskiplistNode *node) {
6041 decrRefCount(node->obj);
ad807e6f 6042 zfree(node->forward);
69d95c3e 6043 zfree(node->span);
fd8ccf44 6044 zfree(node);
6045}
6046
6047static void zslFree(zskiplist *zsl) {
ad807e6f 6048 zskiplistNode *node = zsl->header->forward[0], *next;
fd8ccf44 6049
ad807e6f 6050 zfree(zsl->header->forward);
69d95c3e 6051 zfree(zsl->header->span);
ad807e6f 6052 zfree(zsl->header);
fd8ccf44 6053 while(node) {
599379dd 6054 next = node->forward[0];
fd8ccf44 6055 zslFreeNode(node);
6056 node = next;
6057 }
ad807e6f 6058 zfree(zsl);
fd8ccf44 6059}
6060
6b47e12e 6061static int zslRandomLevel(void) {
6062 int level = 1;
6063 while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
6064 level += 1;
10c2baa5 6065 return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
6b47e12e 6066}
6067
6068static void zslInsert(zskiplist *zsl, double score, robj *obj) {
6069 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
2b37892e 6070 unsigned int rank[ZSKIPLIST_MAXLEVEL];
6b47e12e 6071 int i, level;
6072
6073 x = zsl->header;
6074 for (i = zsl->level-1; i >= 0; i--) {
2b37892e
PN
6075 /* store rank that is crossed to reach the insert position */
6076 rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
69d95c3e 6077
9d60e6e4 6078 while (x->forward[i] &&
6079 (x->forward[i]->score < score ||
6080 (x->forward[i]->score == score &&
69d95c3e 6081 compareStringObjects(x->forward[i]->obj,obj) < 0))) {
a50ea45c 6082 rank[i] += i > 0 ? x->span[i-1] : 1;
6b47e12e 6083 x = x->forward[i];
69d95c3e 6084 }
6b47e12e 6085 update[i] = x;
6086 }
6b47e12e 6087 /* we assume the key is not already inside, since we allow duplicated
6088 * scores, and the re-insertion of score and redis object should never
6089 * happpen since the caller of zslInsert() should test in the hash table
6090 * if the element is already inside or not. */
6091 level = zslRandomLevel();
6092 if (level > zsl->level) {
69d95c3e 6093 for (i = zsl->level; i < level; i++) {
2b37892e 6094 rank[i] = 0;
6b47e12e 6095 update[i] = zsl->header;
2b37892e 6096 update[i]->span[i-1] = zsl->length;
69d95c3e 6097 }
6b47e12e 6098 zsl->level = level;
6099 }
6100 x = zslCreateNode(level,score,obj);
6101 for (i = 0; i < level; i++) {
6102 x->forward[i] = update[i]->forward[i];
6103 update[i]->forward[i] = x;
69d95c3e
PN
6104
6105 /* update span covered by update[i] as x is inserted here */
2b37892e
PN
6106 if (i > 0) {
6107 x->span[i-1] = update[i]->span[i-1] - (rank[0] - rank[i]);
6108 update[i]->span[i-1] = (rank[0] - rank[i]) + 1;
6109 }
6b47e12e 6110 }
69d95c3e
PN
6111
6112 /* increment span for untouched levels */
6113 for (i = level; i < zsl->level; i++) {
2b37892e 6114 update[i]->span[i-1]++;
69d95c3e
PN
6115 }
6116
bb975144 6117 x->backward = (update[0] == zsl->header) ? NULL : update[0];
e3870fab 6118 if (x->forward[0])
6119 x->forward[0]->backward = x;
6120 else
6121 zsl->tail = x;
cc812361 6122 zsl->length++;
6b47e12e 6123}
6124
84105336
PN
6125/* Internal function used by zslDelete, zslDeleteByScore and zslDeleteByRank */
6126void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) {
6127 int i;
6128 for (i = 0; i < zsl->level; i++) {
6129 if (update[i]->forward[i] == x) {
6130 if (i > 0) {
6131 update[i]->span[i-1] += x->span[i-1] - 1;
6132 }
6133 update[i]->forward[i] = x->forward[i];
6134 } else {
6135 /* invariant: i > 0, because update[0]->forward[0]
6136 * is always equal to x */
6137 update[i]->span[i-1] -= 1;
6138 }
6139 }
6140 if (x->forward[0]) {
6141 x->forward[0]->backward = x->backward;
6142 } else {
6143 zsl->tail = x->backward;
6144 }
6145 while(zsl->level > 1 && zsl->header->forward[zsl->level-1] == NULL)
6146 zsl->level--;
6147 zsl->length--;
6148}
6149
50c55df5 6150/* Delete an element with matching score/object from the skiplist. */
fd8ccf44 6151static int zslDelete(zskiplist *zsl, double score, robj *obj) {
e197b441 6152 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
6153 int i;
6154
6155 x = zsl->header;
6156 for (i = zsl->level-1; i >= 0; i--) {
9d60e6e4 6157 while (x->forward[i] &&
6158 (x->forward[i]->score < score ||
6159 (x->forward[i]->score == score &&
6160 compareStringObjects(x->forward[i]->obj,obj) < 0)))
e197b441 6161 x = x->forward[i];
6162 update[i] = x;
6163 }
6164 /* We may have multiple elements with the same score, what we need
6165 * is to find the element with both the right score and object. */
6166 x = x->forward[0];
bf028098 6167 if (x && score == x->score && equalStringObjects(x->obj,obj)) {
84105336 6168 zslDeleteNode(zsl, x, update);
9d60e6e4 6169 zslFreeNode(x);
9d60e6e4 6170 return 1;
6171 } else {
6172 return 0; /* not found */
e197b441 6173 }
6174 return 0; /* not found */
fd8ccf44 6175}
6176
1807985b 6177/* Delete all the elements with score between min and max from the skiplist.
6178 * Min and mx are inclusive, so a score >= min || score <= max is deleted.
6179 * Note that this function takes the reference to the hash table view of the
6180 * sorted set, in order to remove the elements from the hash table too. */
f84d3933 6181static unsigned long zslDeleteRangeByScore(zskiplist *zsl, double min, double max, dict *dict) {
1807985b 6182 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
6183 unsigned long removed = 0;
6184 int i;
6185
6186 x = zsl->header;
6187 for (i = zsl->level-1; i >= 0; i--) {
6188 while (x->forward[i] && x->forward[i]->score < min)
6189 x = x->forward[i];
6190 update[i] = x;
6191 }
6192 /* We may have multiple elements with the same score, what we need
6193 * is to find the element with both the right score and object. */
6194 x = x->forward[0];
6195 while (x && x->score <= max) {
84105336
PN
6196 zskiplistNode *next = x->forward[0];
6197 zslDeleteNode(zsl, x, update);
1807985b 6198 dictDelete(dict,x->obj);
6199 zslFreeNode(x);
1807985b 6200 removed++;
6201 x = next;
6202 }
6203 return removed; /* not found */
6204}
1807985b 6205
9212eafd 6206/* Delete all the elements with rank between start and end from the skiplist.
2424490f 6207 * Start and end are inclusive. Note that start and end need to be 1-based */
9212eafd
PN
6208static unsigned long zslDeleteRangeByRank(zskiplist *zsl, unsigned int start, unsigned int end, dict *dict) {
6209 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
6210 unsigned long traversed = 0, removed = 0;
6211 int i;
6212
9212eafd
PN
6213 x = zsl->header;
6214 for (i = zsl->level-1; i >= 0; i--) {
6215 while (x->forward[i] && (traversed + (i > 0 ? x->span[i-1] : 1)) < start) {
6216 traversed += i > 0 ? x->span[i-1] : 1;
6217 x = x->forward[i];
1807985b 6218 }
9212eafd
PN
6219 update[i] = x;
6220 }
6221
6222 traversed++;
6223 x = x->forward[0];
6224 while (x && traversed <= end) {
84105336
PN
6225 zskiplistNode *next = x->forward[0];
6226 zslDeleteNode(zsl, x, update);
1807985b 6227 dictDelete(dict,x->obj);
6228 zslFreeNode(x);
1807985b 6229 removed++;
9212eafd 6230 traversed++;
1807985b 6231 x = next;
6232 }
9212eafd 6233 return removed;
1807985b 6234}
6235
50c55df5 6236/* Find the first node having a score equal or greater than the specified one.
6237 * Returns NULL if there is no match. */
6238static zskiplistNode *zslFirstWithScore(zskiplist *zsl, double score) {
6239 zskiplistNode *x;
6240 int i;
6241
6242 x = zsl->header;
6243 for (i = zsl->level-1; i >= 0; i--) {
6244 while (x->forward[i] && x->forward[i]->score < score)
6245 x = x->forward[i];
6246 }
6247 /* We may have multiple elements with the same score, what we need
6248 * is to find the element with both the right score and object. */
6249 return x->forward[0];
6250}
6251
27b0ccca
PN
6252/* Find the rank for an element by both score and key.
6253 * Returns 0 when the element cannot be found, rank otherwise.
6254 * Note that the rank is 1-based due to the span of zsl->header to the
6255 * first element. */
003f0840 6256static unsigned long zslistTypeGetRank(zskiplist *zsl, double score, robj *o) {
27b0ccca
PN
6257 zskiplistNode *x;
6258 unsigned long rank = 0;
6259 int i;
6260
6261 x = zsl->header;
6262 for (i = zsl->level-1; i >= 0; i--) {
6263 while (x->forward[i] &&
6264 (x->forward[i]->score < score ||
6265 (x->forward[i]->score == score &&
6266 compareStringObjects(x->forward[i]->obj,o) <= 0))) {
a50ea45c 6267 rank += i > 0 ? x->span[i-1] : 1;
27b0ccca
PN
6268 x = x->forward[i];
6269 }
6270
6271 /* x might be equal to zsl->header, so test if obj is non-NULL */
bf028098 6272 if (x->obj && equalStringObjects(x->obj,o)) {
27b0ccca
PN
6273 return rank;
6274 }
6275 }
6276 return 0;
6277}
6278
e74825c2 6279/* Finds an element by its rank. The rank argument needs to be 1-based. */
003f0840 6280zskiplistNode* zslistTypeGetElementByRank(zskiplist *zsl, unsigned long rank) {
e74825c2
PN
6281 zskiplistNode *x;
6282 unsigned long traversed = 0;
6283 int i;
6284
6285 x = zsl->header;
6286 for (i = zsl->level-1; i >= 0; i--) {
dd88747b 6287 while (x->forward[i] && (traversed + (i>0 ? x->span[i-1] : 1)) <= rank)
6288 {
a50ea45c 6289 traversed += i > 0 ? x->span[i-1] : 1;
e74825c2
PN
6290 x = x->forward[i];
6291 }
e74825c2
PN
6292 if (traversed == rank) {
6293 return x;
6294 }
6295 }
6296 return NULL;
6297}
6298
fd8ccf44 6299/* The actual Z-commands implementations */
6300
7db723ad 6301/* This generic command implements both ZADD and ZINCRBY.
e2665397 6302 * scoreval is the score if the operation is a ZADD (doincrement == 0) or
7db723ad 6303 * the increment if the operation is a ZINCRBY (doincrement == 1). */
e2665397 6304static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, int doincrement) {
fd8ccf44 6305 robj *zsetobj;
6306 zset *zs;
6307 double *score;
6308
5fc9229c 6309 if (isnan(scoreval)) {
6310 addReplySds(c,sdsnew("-ERR provide score is Not A Number (nan)\r\n"));
6311 return;
6312 }
6313
e2665397 6314 zsetobj = lookupKeyWrite(c->db,key);
fd8ccf44 6315 if (zsetobj == NULL) {
6316 zsetobj = createZsetObject();
09241813 6317 dbAdd(c->db,key,zsetobj);
fd8ccf44 6318 } else {
6319 if (zsetobj->type != REDIS_ZSET) {
6320 addReply(c,shared.wrongtypeerr);
6321 return;
6322 }
6323 }
fd8ccf44 6324 zs = zsetobj->ptr;
e2665397 6325
7db723ad 6326 /* Ok now since we implement both ZADD and ZINCRBY here the code
e2665397 6327 * needs to handle the two different conditions. It's all about setting
6328 * '*score', that is, the new score to set, to the right value. */
6329 score = zmalloc(sizeof(double));
6330 if (doincrement) {
6331 dictEntry *de;
6332
6333 /* Read the old score. If the element was not present starts from 0 */
6334 de = dictFind(zs->dict,ele);
6335 if (de) {
6336 double *oldscore = dictGetEntryVal(de);
6337 *score = *oldscore + scoreval;
6338 } else {
6339 *score = scoreval;
6340 }
5fc9229c 6341 if (isnan(*score)) {
6342 addReplySds(c,
6343 sdsnew("-ERR resulting score is Not A Number (nan)\r\n"));
6344 zfree(score);
6345 /* Note that we don't need to check if the zset may be empty and
6346 * should be removed here, as we can only obtain Nan as score if
6347 * there was already an element in the sorted set. */
6348 return;
6349 }
e2665397 6350 } else {
6351 *score = scoreval;
6352 }
6353
6354 /* What follows is a simple remove and re-insert operation that is common
7db723ad 6355 * to both ZADD and ZINCRBY... */
e2665397 6356 if (dictAdd(zs->dict,ele,score) == DICT_OK) {
fd8ccf44 6357 /* case 1: New element */
e2665397 6358 incrRefCount(ele); /* added to hash */
6359 zslInsert(zs->zsl,*score,ele);
6360 incrRefCount(ele); /* added to skiplist */
fd8ccf44 6361 server.dirty++;
e2665397 6362 if (doincrement)
e2665397 6363 addReplyDouble(c,*score);
91d71bfc 6364 else
6365 addReply(c,shared.cone);
fd8ccf44 6366 } else {
6367 dictEntry *de;
6368 double *oldscore;
e0a62c7f 6369
fd8ccf44 6370 /* case 2: Score update operation */
e2665397 6371 de = dictFind(zs->dict,ele);
dfc5e96c 6372 redisAssert(de != NULL);
fd8ccf44 6373 oldscore = dictGetEntryVal(de);
6374 if (*score != *oldscore) {
6375 int deleted;
6376
e2665397 6377 /* Remove and insert the element in the skip list with new score */
6378 deleted = zslDelete(zs->zsl,*oldscore,ele);
dfc5e96c 6379 redisAssert(deleted != 0);
e2665397 6380 zslInsert(zs->zsl,*score,ele);
6381 incrRefCount(ele);
6382 /* Update the score in the hash table */
6383 dictReplace(zs->dict,ele,score);
fd8ccf44 6384 server.dirty++;
2161a965 6385 } else {
6386 zfree(score);
fd8ccf44 6387 }
e2665397 6388 if (doincrement)
6389 addReplyDouble(c,*score);
6390 else
6391 addReply(c,shared.czero);
fd8ccf44 6392 }
6393}
6394
e2665397 6395static void zaddCommand(redisClient *c) {
6396 double scoreval;
6397
bd79a6bd 6398 if (getDoubleFromObjectOrReply(c, c->argv[2], &scoreval, NULL) != REDIS_OK) return;
e2665397 6399 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,0);
6400}
6401
7db723ad 6402static void zincrbyCommand(redisClient *c) {
e2665397 6403 double scoreval;
6404
bd79a6bd 6405 if (getDoubleFromObjectOrReply(c, c->argv[2], &scoreval, NULL) != REDIS_OK) return;
e2665397 6406 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1);
6407}
6408
1b7106e7 6409static void zremCommand(redisClient *c) {
6410 robj *zsetobj;
6411 zset *zs;
dd88747b 6412 dictEntry *de;
6413 double *oldscore;
6414 int deleted;
1b7106e7 6415
dd88747b 6416 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
6417 checkType(c,zsetobj,REDIS_ZSET)) return;
1b7106e7 6418
dd88747b 6419 zs = zsetobj->ptr;
6420 de = dictFind(zs->dict,c->argv[2]);
6421 if (de == NULL) {
6422 addReply(c,shared.czero);
6423 return;
1b7106e7 6424 }
dd88747b 6425 /* Delete from the skiplist */
6426 oldscore = dictGetEntryVal(de);
6427 deleted = zslDelete(zs->zsl,*oldscore,c->argv[2]);
6428 redisAssert(deleted != 0);
6429
6430 /* Delete from the hash table */
6431 dictDelete(zs->dict,c->argv[2]);
6432 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
09241813 6433 if (dictSize(zs->dict) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 6434 server.dirty++;
6435 addReply(c,shared.cone);
1b7106e7 6436}
6437
1807985b 6438static void zremrangebyscoreCommand(redisClient *c) {
bbe025e0
AM
6439 double min;
6440 double max;
dd88747b 6441 long deleted;
1807985b 6442 robj *zsetobj;
6443 zset *zs;
6444
bd79a6bd
PN
6445 if ((getDoubleFromObjectOrReply(c, c->argv[2], &min, NULL) != REDIS_OK) ||
6446 (getDoubleFromObjectOrReply(c, c->argv[3], &max, NULL) != REDIS_OK)) return;
bbe025e0 6447
dd88747b 6448 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
6449 checkType(c,zsetobj,REDIS_ZSET)) return;
1807985b 6450
dd88747b 6451 zs = zsetobj->ptr;
6452 deleted = zslDeleteRangeByScore(zs->zsl,min,max,zs->dict);
6453 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
09241813 6454 if (dictSize(zs->dict) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 6455 server.dirty += deleted;
482b672d 6456 addReplyLongLong(c,deleted);
1807985b 6457}
6458
9212eafd 6459static void zremrangebyrankCommand(redisClient *c) {
bbe025e0
AM
6460 long start;
6461 long end;
dd88747b 6462 int llen;
6463 long deleted;
9212eafd
PN
6464 robj *zsetobj;
6465 zset *zs;
6466
bd79a6bd
PN
6467 if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
6468 (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
bbe025e0 6469
dd88747b 6470 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
6471 checkType(c,zsetobj,REDIS_ZSET)) return;
6472 zs = zsetobj->ptr;
6473 llen = zs->zsl->length;
9212eafd 6474
dd88747b 6475 /* convert negative indexes */
6476 if (start < 0) start = llen+start;
6477 if (end < 0) end = llen+end;
6478 if (start < 0) start = 0;
6479 if (end < 0) end = 0;
9212eafd 6480
dd88747b 6481 /* indexes sanity checks */
6482 if (start > end || start >= llen) {
6483 addReply(c,shared.czero);
6484 return;
9212eafd 6485 }
dd88747b 6486 if (end >= llen) end = llen-1;
6487
6488 /* increment start and end because zsl*Rank functions
6489 * use 1-based rank */
6490 deleted = zslDeleteRangeByRank(zs->zsl,start+1,end+1,zs->dict);
6491 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
09241813 6492 if (dictSize(zs->dict) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 6493 server.dirty += deleted;
482b672d 6494 addReplyLongLong(c, deleted);
9212eafd
PN
6495}
6496
8f92e768
PN
6497typedef struct {
6498 dict *dict;
6499 double weight;
6500} zsetopsrc;
6501
6502static int qsortCompareZsetopsrcByCardinality(const void *s1, const void *s2) {
6503 zsetopsrc *d1 = (void*) s1, *d2 = (void*) s2;
6504 unsigned long size1, size2;
6505 size1 = d1->dict ? dictSize(d1->dict) : 0;
6506 size2 = d2->dict ? dictSize(d2->dict) : 0;
6507 return size1 - size2;
6508}
6509
d2764cd6
PN
6510#define REDIS_AGGR_SUM 1
6511#define REDIS_AGGR_MIN 2
6512#define REDIS_AGGR_MAX 3
bc000c1d 6513#define zunionInterDictValue(_e) (dictGetEntryVal(_e) == NULL ? 1.0 : *(double*)dictGetEntryVal(_e))
d2764cd6
PN
6514
6515inline static void zunionInterAggregate(double *target, double val, int aggregate) {
6516 if (aggregate == REDIS_AGGR_SUM) {
6517 *target = *target + val;
6518 } else if (aggregate == REDIS_AGGR_MIN) {
6519 *target = val < *target ? val : *target;
6520 } else if (aggregate == REDIS_AGGR_MAX) {
6521 *target = val > *target ? val : *target;
6522 } else {
6523 /* safety net */
f83c6cb5 6524 redisPanic("Unknown ZUNION/INTER aggregate type");
d2764cd6
PN
6525 }
6526}
6527
2830ca53 6528static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
bc000c1d 6529 int i, j, setnum;
d2764cd6 6530 int aggregate = REDIS_AGGR_SUM;
8f92e768 6531 zsetopsrc *src;
2830ca53
PN
6532 robj *dstobj;
6533 zset *dstzset;
b287c9bb
PN
6534 dictIterator *di;
6535 dictEntry *de;
6536
bc000c1d
JC
6537 /* expect setnum input keys to be given */
6538 setnum = atoi(c->argv[2]->ptr);
6539 if (setnum < 1) {
5d373da9 6540 addReplySds(c,sdsnew("-ERR at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE\r\n"));
2830ca53 6541 return;
b287c9bb 6542 }
2830ca53
PN
6543
6544 /* test if the expected number of keys would overflow */
bc000c1d 6545 if (3+setnum > c->argc) {
b287c9bb
PN
6546 addReply(c,shared.syntaxerr);
6547 return;
6548 }
6549
2830ca53 6550 /* read keys to be used for input */
bc000c1d
JC
6551 src = zmalloc(sizeof(zsetopsrc) * setnum);
6552 for (i = 0, j = 3; i < setnum; i++, j++) {
6553 robj *obj = lookupKeyWrite(c->db,c->argv[j]);
6554 if (!obj) {
8f92e768 6555 src[i].dict = NULL;
b287c9bb 6556 } else {
bc000c1d
JC
6557 if (obj->type == REDIS_ZSET) {
6558 src[i].dict = ((zset*)obj->ptr)->dict;
6559 } else if (obj->type == REDIS_SET) {
6560 src[i].dict = (obj->ptr);
6561 } else {
8f92e768 6562 zfree(src);
b287c9bb
PN
6563 addReply(c,shared.wrongtypeerr);
6564 return;
6565 }
b287c9bb 6566 }
2830ca53
PN
6567
6568 /* default all weights to 1 */
8f92e768 6569 src[i].weight = 1.0;
b287c9bb
PN
6570 }
6571
2830ca53
PN
6572 /* parse optional extra arguments */
6573 if (j < c->argc) {
d2764cd6 6574 int remaining = c->argc - j;
b287c9bb 6575
2830ca53 6576 while (remaining) {
bc000c1d 6577 if (remaining >= (setnum + 1) && !strcasecmp(c->argv[j]->ptr,"weights")) {
2830ca53 6578 j++; remaining--;
bc000c1d 6579 for (i = 0; i < setnum; i++, j++, remaining--) {
bd79a6bd 6580 if (getDoubleFromObjectOrReply(c, c->argv[j], &src[i].weight, NULL) != REDIS_OK)
bbe025e0 6581 return;
2830ca53 6582 }
d2764cd6
PN
6583 } else if (remaining >= 2 && !strcasecmp(c->argv[j]->ptr,"aggregate")) {
6584 j++; remaining--;
6585 if (!strcasecmp(c->argv[j]->ptr,"sum")) {
6586 aggregate = REDIS_AGGR_SUM;
6587 } else if (!strcasecmp(c->argv[j]->ptr,"min")) {
6588 aggregate = REDIS_AGGR_MIN;
6589 } else if (!strcasecmp(c->argv[j]->ptr,"max")) {
6590 aggregate = REDIS_AGGR_MAX;
6591 } else {
6592 zfree(src);
6593 addReply(c,shared.syntaxerr);
6594 return;
6595 }
6596 j++; remaining--;
2830ca53 6597 } else {
8f92e768 6598 zfree(src);
2830ca53
PN
6599 addReply(c,shared.syntaxerr);
6600 return;
6601 }
6602 }
6603 }
b287c9bb 6604
d2764cd6
PN
6605 /* sort sets from the smallest to largest, this will improve our
6606 * algorithm's performance */
bc000c1d 6607 qsort(src,setnum,sizeof(zsetopsrc),qsortCompareZsetopsrcByCardinality);
d2764cd6 6608
2830ca53
PN
6609 dstobj = createZsetObject();
6610 dstzset = dstobj->ptr;
6611
6612 if (op == REDIS_OP_INTER) {
8f92e768
PN
6613 /* skip going over all entries if the smallest zset is NULL or empty */
6614 if (src[0].dict && dictSize(src[0].dict) > 0) {
6615 /* precondition: as src[0].dict is non-empty and the zsets are ordered
6616 * from small to large, all src[i > 0].dict are non-empty too */
6617 di = dictGetIterator(src[0].dict);
2830ca53 6618 while((de = dictNext(di)) != NULL) {
d2764cd6 6619 double *score = zmalloc(sizeof(double)), value;
bc000c1d 6620 *score = src[0].weight * zunionInterDictValue(de);
2830ca53 6621
bc000c1d 6622 for (j = 1; j < setnum; j++) {
d2764cd6 6623 dictEntry *other = dictFind(src[j].dict,dictGetEntryKey(de));
2830ca53 6624 if (other) {
bc000c1d 6625 value = src[j].weight * zunionInterDictValue(other);
d2764cd6 6626 zunionInterAggregate(score, value, aggregate);
2830ca53
PN
6627 } else {
6628 break;
6629 }
6630 }
b287c9bb 6631
2830ca53 6632 /* skip entry when not present in every source dict */
bc000c1d 6633 if (j != setnum) {
2830ca53
PN
6634 zfree(score);
6635 } else {
6636 robj *o = dictGetEntryKey(de);
6637 dictAdd(dstzset->dict,o,score);
6638 incrRefCount(o); /* added to dictionary */
6639 zslInsert(dstzset->zsl,*score,o);
6640 incrRefCount(o); /* added to skiplist */
b287c9bb
PN
6641 }
6642 }
2830ca53
PN
6643 dictReleaseIterator(di);
6644 }
6645 } else if (op == REDIS_OP_UNION) {
bc000c1d 6646 for (i = 0; i < setnum; i++) {
8f92e768 6647 if (!src[i].dict) continue;
2830ca53 6648
8f92e768 6649 di = dictGetIterator(src[i].dict);
2830ca53
PN
6650 while((de = dictNext(di)) != NULL) {
6651 /* skip key when already processed */
6652 if (dictFind(dstzset->dict,dictGetEntryKey(de)) != NULL) continue;
6653
d2764cd6 6654 double *score = zmalloc(sizeof(double)), value;
bc000c1d 6655 *score = src[i].weight * zunionInterDictValue(de);
2830ca53 6656
d2764cd6
PN
6657 /* because the zsets are sorted by size, its only possible
6658 * for sets at larger indices to hold this entry */
bc000c1d 6659 for (j = (i+1); j < setnum; j++) {
d2764cd6 6660 dictEntry *other = dictFind(src[j].dict,dictGetEntryKey(de));
2830ca53 6661 if (other) {
bc000c1d 6662 value = src[j].weight * zunionInterDictValue(other);
d2764cd6 6663 zunionInterAggregate(score, value, aggregate);
2830ca53
PN
6664 }
6665 }
b287c9bb 6666
2830ca53
PN
6667 robj *o = dictGetEntryKey(de);
6668 dictAdd(dstzset->dict,o,score);
6669 incrRefCount(o); /* added to dictionary */
6670 zslInsert(dstzset->zsl,*score,o);
6671 incrRefCount(o); /* added to skiplist */
6672 }
6673 dictReleaseIterator(di);
b287c9bb 6674 }
2830ca53
PN
6675 } else {
6676 /* unknown operator */
6677 redisAssert(op == REDIS_OP_INTER || op == REDIS_OP_UNION);
b287c9bb
PN
6678 }
6679
09241813 6680 dbDelete(c->db,dstkey);
3ea27d37 6681 if (dstzset->zsl->length) {
09241813 6682 dbAdd(c->db,dstkey,dstobj);
482b672d 6683 addReplyLongLong(c, dstzset->zsl->length);
3ea27d37 6684 server.dirty++;
6685 } else {
8bca8773 6686 decrRefCount(dstobj);
3ea27d37 6687 addReply(c, shared.czero);
6688 }
8f92e768 6689 zfree(src);
b287c9bb
PN
6690}
6691
5d373da9 6692static void zunionstoreCommand(redisClient *c) {
2830ca53 6693 zunionInterGenericCommand(c,c->argv[1], REDIS_OP_UNION);
b287c9bb
PN
6694}
6695
5d373da9 6696static void zinterstoreCommand(redisClient *c) {
2830ca53 6697 zunionInterGenericCommand(c,c->argv[1], REDIS_OP_INTER);
b287c9bb
PN
6698}
6699
e3870fab 6700static void zrangeGenericCommand(redisClient *c, int reverse) {
cc812361 6701 robj *o;
bbe025e0
AM
6702 long start;
6703 long end;
752da584 6704 int withscores = 0;
dd88747b 6705 int llen;
6706 int rangelen, j;
6707 zset *zsetobj;
6708 zskiplist *zsl;
6709 zskiplistNode *ln;
6710 robj *ele;
752da584 6711
bd79a6bd
PN
6712 if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
6713 (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
bbe025e0 6714
752da584 6715 if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) {
6716 withscores = 1;
6717 } else if (c->argc >= 5) {
6718 addReply(c,shared.syntaxerr);
6719 return;
6720 }
cc812361 6721
4e27f268 6722 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
6723 || checkType(c,o,REDIS_ZSET)) return;
dd88747b 6724 zsetobj = o->ptr;
6725 zsl = zsetobj->zsl;
6726 llen = zsl->length;
cc812361 6727
dd88747b 6728 /* convert negative indexes */
6729 if (start < 0) start = llen+start;
6730 if (end < 0) end = llen+end;
6731 if (start < 0) start = 0;
6732 if (end < 0) end = 0;
cc812361 6733
dd88747b 6734 /* indexes sanity checks */
6735 if (start > end || start >= llen) {
6736 /* Out of range start or start > end result in empty list */
6737 addReply(c,shared.emptymultibulk);
6738 return;
6739 }
6740 if (end >= llen) end = llen-1;
6741 rangelen = (end-start)+1;
cc812361 6742
dd88747b 6743 /* check if starting point is trivial, before searching
6744 * the element in log(N) time */
6745 if (reverse) {
003f0840 6746 ln = start == 0 ? zsl->tail : zslistTypeGetElementByRank(zsl, llen-start);
dd88747b 6747 } else {
6748 ln = start == 0 ?
003f0840 6749 zsl->header->forward[0] : zslistTypeGetElementByRank(zsl, start+1);
dd88747b 6750 }
cc812361 6751
dd88747b 6752 /* Return the result in form of a multi-bulk reply */
6753 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",
6754 withscores ? (rangelen*2) : rangelen));
6755 for (j = 0; j < rangelen; j++) {
6756 ele = ln->obj;
6757 addReplyBulk(c,ele);
6758 if (withscores)
6759 addReplyDouble(c,ln->score);
6760 ln = reverse ? ln->backward : ln->forward[0];
cc812361 6761 }
6762}
6763
e3870fab 6764static void zrangeCommand(redisClient *c) {
6765 zrangeGenericCommand(c,0);
6766}
6767
6768static void zrevrangeCommand(redisClient *c) {
6769 zrangeGenericCommand(c,1);
6770}
6771
f44dd428 6772/* This command implements both ZRANGEBYSCORE and ZCOUNT.
6773 * If justcount is non-zero, just the count is returned. */
6774static void genericZrangebyscoreCommand(redisClient *c, int justcount) {
50c55df5 6775 robj *o;
f44dd428 6776 double min, max;
6777 int minex = 0, maxex = 0; /* are min or max exclusive? */
80181f78 6778 int offset = 0, limit = -1;
0500ef27
SH
6779 int withscores = 0;
6780 int badsyntax = 0;
6781
f44dd428 6782 /* Parse the min-max interval. If one of the values is prefixed
6783 * by the "(" character, it's considered "open". For instance
6784 * ZRANGEBYSCORE zset (1.5 (2.5 will match min < x < max
6785 * ZRANGEBYSCORE zset 1.5 2.5 will instead match min <= x <= max */
6786 if (((char*)c->argv[2]->ptr)[0] == '(') {
6787 min = strtod((char*)c->argv[2]->ptr+1,NULL);
6788 minex = 1;
6789 } else {
6790 min = strtod(c->argv[2]->ptr,NULL);
6791 }
6792 if (((char*)c->argv[3]->ptr)[0] == '(') {
6793 max = strtod((char*)c->argv[3]->ptr+1,NULL);
6794 maxex = 1;
6795 } else {
6796 max = strtod(c->argv[3]->ptr,NULL);
6797 }
6798
6799 /* Parse "WITHSCORES": note that if the command was called with
6800 * the name ZCOUNT then we are sure that c->argc == 4, so we'll never
6801 * enter the following paths to parse WITHSCORES and LIMIT. */
0500ef27 6802 if (c->argc == 5 || c->argc == 8) {
3a3978b1 6803 if (strcasecmp(c->argv[c->argc-1]->ptr,"withscores") == 0)
6804 withscores = 1;
6805 else
6806 badsyntax = 1;
0500ef27 6807 }
3a3978b1 6808 if (c->argc != (4 + withscores) && c->argc != (7 + withscores))
0500ef27 6809 badsyntax = 1;
0500ef27 6810 if (badsyntax) {
454d4e43 6811 addReplySds(c,
6812 sdsnew("-ERR wrong number of arguments for ZRANGEBYSCORE\r\n"));
80181f78 6813 return;
0500ef27
SH
6814 }
6815
f44dd428 6816 /* Parse "LIMIT" */
0500ef27 6817 if (c->argc == (7 + withscores) && strcasecmp(c->argv[4]->ptr,"limit")) {
80181f78 6818 addReply(c,shared.syntaxerr);
6819 return;
0500ef27 6820 } else if (c->argc == (7 + withscores)) {
80181f78 6821 offset = atoi(c->argv[5]->ptr);
6822 limit = atoi(c->argv[6]->ptr);
0b13687c 6823 if (offset < 0) offset = 0;
80181f78 6824 }
50c55df5 6825
f44dd428 6826 /* Ok, lookup the key and get the range */
50c55df5 6827 o = lookupKeyRead(c->db,c->argv[1]);
6828 if (o == NULL) {
4e27f268 6829 addReply(c,justcount ? shared.czero : shared.emptymultibulk);
50c55df5 6830 } else {
6831 if (o->type != REDIS_ZSET) {
6832 addReply(c,shared.wrongtypeerr);
6833 } else {
6834 zset *zsetobj = o->ptr;
6835 zskiplist *zsl = zsetobj->zsl;
6836 zskiplistNode *ln;
f44dd428 6837 robj *ele, *lenobj = NULL;
6838 unsigned long rangelen = 0;
50c55df5 6839
f44dd428 6840 /* Get the first node with the score >= min, or with
6841 * score > min if 'minex' is true. */
50c55df5 6842 ln = zslFirstWithScore(zsl,min);
f44dd428 6843 while (minex && ln && ln->score == min) ln = ln->forward[0];
6844
50c55df5 6845 if (ln == NULL) {
6846 /* No element matching the speciifed interval */
f44dd428 6847 addReply(c,justcount ? shared.czero : shared.emptymultibulk);
50c55df5 6848 return;
6849 }
6850
6851 /* We don't know in advance how many matching elements there
6852 * are in the list, so we push this object that will represent
6853 * the multi-bulk length in the output buffer, and will "fix"
6854 * it later */
f44dd428 6855 if (!justcount) {
6856 lenobj = createObject(REDIS_STRING,NULL);
6857 addReply(c,lenobj);
6858 decrRefCount(lenobj);
6859 }
50c55df5 6860
f44dd428 6861 while(ln && (maxex ? (ln->score < max) : (ln->score <= max))) {
80181f78 6862 if (offset) {
6863 offset--;
6864 ln = ln->forward[0];
6865 continue;
6866 }
6867 if (limit == 0) break;
f44dd428 6868 if (!justcount) {
6869 ele = ln->obj;
dd88747b 6870 addReplyBulk(c,ele);
f44dd428 6871 if (withscores)
6872 addReplyDouble(c,ln->score);
6873 }
50c55df5 6874 ln = ln->forward[0];
6875 rangelen++;
80181f78 6876 if (limit > 0) limit--;
50c55df5 6877 }
f44dd428 6878 if (justcount) {
482b672d 6879 addReplyLongLong(c,(long)rangelen);
f44dd428 6880 } else {
6881 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",
6882 withscores ? (rangelen*2) : rangelen);
6883 }
50c55df5 6884 }
6885 }
6886}
6887
f44dd428 6888static void zrangebyscoreCommand(redisClient *c) {
6889 genericZrangebyscoreCommand(c,0);
6890}
6891
6892static void zcountCommand(redisClient *c) {
6893 genericZrangebyscoreCommand(c,1);
6894}
6895
3c41331e 6896static void zcardCommand(redisClient *c) {
e197b441 6897 robj *o;
6898 zset *zs;
dd88747b 6899
6900 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
6901 checkType(c,o,REDIS_ZSET)) return;
6902
6903 zs = o->ptr;
6904 addReplyUlong(c,zs->zsl->length);
e197b441 6905}
6906
6e333bbe 6907static void zscoreCommand(redisClient *c) {
6908 robj *o;
6909 zset *zs;
dd88747b 6910 dictEntry *de;
6911
6912 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
6913 checkType(c,o,REDIS_ZSET)) return;
6914
6915 zs = o->ptr;
6916 de = dictFind(zs->dict,c->argv[2]);
6917 if (!de) {
96d8b4ee 6918 addReply(c,shared.nullbulk);
6e333bbe 6919 } else {
dd88747b 6920 double *score = dictGetEntryVal(de);
6e333bbe 6921
dd88747b 6922 addReplyDouble(c,*score);
6e333bbe 6923 }
6924}
6925
798d9e55 6926static void zrankGenericCommand(redisClient *c, int reverse) {
69d95c3e 6927 robj *o;
dd88747b 6928 zset *zs;
6929 zskiplist *zsl;
6930 dictEntry *de;
6931 unsigned long rank;
6932 double *score;
6933
6934 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
6935 checkType(c,o,REDIS_ZSET)) return;
6936
6937 zs = o->ptr;
6938 zsl = zs->zsl;
6939 de = dictFind(zs->dict,c->argv[2]);
6940 if (!de) {
69d95c3e
PN
6941 addReply(c,shared.nullbulk);
6942 return;
6943 }
69d95c3e 6944
dd88747b 6945 score = dictGetEntryVal(de);
003f0840 6946 rank = zslistTypeGetRank(zsl, *score, c->argv[2]);
dd88747b 6947 if (rank) {
6948 if (reverse) {
482b672d 6949 addReplyLongLong(c, zsl->length - rank);
27b0ccca 6950 } else {
482b672d 6951 addReplyLongLong(c, rank-1);
69d95c3e 6952 }
dd88747b 6953 } else {
6954 addReply(c,shared.nullbulk);
978c2c94 6955 }
6956}
6957
798d9e55
PN
6958static void zrankCommand(redisClient *c) {
6959 zrankGenericCommand(c, 0);
6960}
6961
6962static void zrevrankCommand(redisClient *c) {
6963 zrankGenericCommand(c, 1);
6964}
6965
7fb16bac
PN
6966/* ========================= Hashes utility functions ======================= */
6967#define REDIS_HASH_KEY 1
6968#define REDIS_HASH_VALUE 2
978c2c94 6969
7fb16bac
PN
6970/* Check the length of a number of objects to see if we need to convert a
6971 * zipmap to a real hash. Note that we only check string encoded objects
6972 * as their string length can be queried in constant time. */
d1578a33 6973static void hashTypeTryConversion(robj *subject, robj **argv, int start, int end) {
7fb16bac
PN
6974 int i;
6975 if (subject->encoding != REDIS_ENCODING_ZIPMAP) return;
978c2c94 6976
7fb16bac
PN
6977 for (i = start; i <= end; i++) {
6978 if (argv[i]->encoding == REDIS_ENCODING_RAW &&
6979 sdslen(argv[i]->ptr) > server.hash_max_zipmap_value)
6980 {
6981 convertToRealHash(subject);
978c2c94 6982 return;
6983 }
6984 }
7fb16bac 6985}
bae2c7ec 6986
97224de7 6987/* Encode given objects in-place when the hash uses a dict. */
d1578a33 6988static void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2) {
97224de7 6989 if (subject->encoding == REDIS_ENCODING_HT) {
3f973463
PN
6990 if (o1) *o1 = tryObjectEncoding(*o1);
6991 if (o2) *o2 = tryObjectEncoding(*o2);
97224de7
PN
6992 }
6993}
6994
7fb16bac 6995/* Get the value from a hash identified by key. Returns either a string
a3f3af86
PN
6996 * object or NULL if the value cannot be found. The refcount of the object
6997 * is always increased by 1 when the value was found. */
d1578a33 6998static robj *hashTypeGet(robj *o, robj *key) {
7fb16bac 6999 robj *value = NULL;
978c2c94 7000 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
7fb16bac
PN
7001 unsigned char *v;
7002 unsigned int vlen;
7003 key = getDecodedObject(key);
7004 if (zipmapGet(o->ptr,key->ptr,sdslen(key->ptr),&v,&vlen)) {
7005 value = createStringObject((char*)v,vlen);
7006 }
7007 decrRefCount(key);
7008 } else {
7009 dictEntry *de = dictFind(o->ptr,key);
7010 if (de != NULL) {
7011 value = dictGetEntryVal(de);
a3f3af86 7012 incrRefCount(value);
7fb16bac
PN
7013 }
7014 }
7015 return value;
7016}
978c2c94 7017
7fb16bac
PN
7018/* Test if the key exists in the given hash. Returns 1 if the key
7019 * exists and 0 when it doesn't. */
d1578a33 7020static int hashTypeExists(robj *o, robj *key) {
7fb16bac
PN
7021 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
7022 key = getDecodedObject(key);
7023 if (zipmapExists(o->ptr,key->ptr,sdslen(key->ptr))) {
7024 decrRefCount(key);
7025 return 1;
7026 }
7027 decrRefCount(key);
7028 } else {
7029 if (dictFind(o->ptr,key) != NULL) {
7030 return 1;
7031 }
7032 }
7033 return 0;
7034}
bae2c7ec 7035
7fb16bac
PN
7036/* Add an element, discard the old if the key already exists.
7037 * Return 0 on insert and 1 on update. */
d1578a33 7038static int hashTypeSet(robj *o, robj *key, robj *value) {
7fb16bac
PN
7039 int update = 0;
7040 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
7041 key = getDecodedObject(key);
7042 value = getDecodedObject(value);
7043 o->ptr = zipmapSet(o->ptr,
7044 key->ptr,sdslen(key->ptr),
7045 value->ptr,sdslen(value->ptr), &update);
7046 decrRefCount(key);
7047 decrRefCount(value);
7048
7049 /* Check if the zipmap needs to be upgraded to a real hash table */
7050 if (zipmapLen(o->ptr) > server.hash_max_zipmap_entries)
bae2c7ec 7051 convertToRealHash(o);
978c2c94 7052 } else {
7fb16bac
PN
7053 if (dictReplace(o->ptr,key,value)) {
7054 /* Insert */
7055 incrRefCount(key);
978c2c94 7056 } else {
7fb16bac 7057 /* Update */
978c2c94 7058 update = 1;
7059 }
7fb16bac 7060 incrRefCount(value);
978c2c94 7061 }
7fb16bac 7062 return update;
978c2c94 7063}
7064
7fb16bac
PN
7065/* Delete an element from a hash.
7066 * Return 1 on deleted and 0 on not found. */
d1578a33 7067static int hashTypeDelete(robj *o, robj *key) {
7fb16bac
PN
7068 int deleted = 0;
7069 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
7070 key = getDecodedObject(key);
7071 o->ptr = zipmapDel(o->ptr,key->ptr,sdslen(key->ptr), &deleted);
7072 decrRefCount(key);
7073 } else {
7074 deleted = dictDelete((dict*)o->ptr,key) == DICT_OK;
7075 /* Always check if the dictionary needs a resize after a delete. */
7076 if (deleted && htNeedsResize(o->ptr)) dictResize(o->ptr);
d33278d1 7077 }
7fb16bac
PN
7078 return deleted;
7079}
d33278d1 7080
7fb16bac 7081/* Return the number of elements in a hash. */
d1578a33 7082static unsigned long hashTypeLength(robj *o) {
7fb16bac
PN
7083 return (o->encoding == REDIS_ENCODING_ZIPMAP) ?
7084 zipmapLen((unsigned char*)o->ptr) : dictSize((dict*)o->ptr);
7085}
7086
7087/* Structure to hold hash iteration abstration. Note that iteration over
7088 * hashes involves both fields and values. Because it is possible that
7089 * not both are required, store pointers in the iterator to avoid
7090 * unnecessary memory allocation for fields/values. */
7091typedef struct {
7092 int encoding;
7093 unsigned char *zi;
7094 unsigned char *zk, *zv;
7095 unsigned int zklen, zvlen;
7096
7097 dictIterator *di;
7098 dictEntry *de;
d1578a33 7099} hashTypeIterator;
7fb16bac 7100
d1578a33
PN
7101static hashTypeIterator *hashTypeInitIterator(robj *subject) {
7102 hashTypeIterator *hi = zmalloc(sizeof(hashTypeIterator));
7fb16bac
PN
7103 hi->encoding = subject->encoding;
7104 if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
7105 hi->zi = zipmapRewind(subject->ptr);
7106 } else if (hi->encoding == REDIS_ENCODING_HT) {
7107 hi->di = dictGetIterator(subject->ptr);
d33278d1 7108 } else {
7fb16bac 7109 redisAssert(NULL);
d33278d1 7110 }
c44d3b56 7111 return hi;
7fb16bac 7112}
d33278d1 7113
d1578a33 7114static void hashTypeReleaseIterator(hashTypeIterator *hi) {
7fb16bac
PN
7115 if (hi->encoding == REDIS_ENCODING_HT) {
7116 dictReleaseIterator(hi->di);
d33278d1 7117 }
c44d3b56 7118 zfree(hi);
7fb16bac 7119}
d33278d1 7120
7fb16bac
PN
7121/* Move to the next entry in the hash. Return REDIS_OK when the next entry
7122 * could be found and REDIS_ERR when the iterator reaches the end. */
d1578a33 7123static int hashTypeNext(hashTypeIterator *hi) {
7fb16bac
PN
7124 if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
7125 if ((hi->zi = zipmapNext(hi->zi, &hi->zk, &hi->zklen,
7126 &hi->zv, &hi->zvlen)) == NULL) return REDIS_ERR;
7127 } else {
7128 if ((hi->de = dictNext(hi->di)) == NULL) return REDIS_ERR;
7129 }
7130 return REDIS_OK;
7131}
d33278d1 7132
0c390abc 7133/* Get key or value object at current iteration position.
a3f3af86 7134 * This increases the refcount of the field object by 1. */
d1578a33 7135static robj *hashTypeCurrent(hashTypeIterator *hi, int what) {
7fb16bac
PN
7136 robj *o;
7137 if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
7138 if (what & REDIS_HASH_KEY) {
7139 o = createStringObject((char*)hi->zk,hi->zklen);
7140 } else {
7141 o = createStringObject((char*)hi->zv,hi->zvlen);
d33278d1 7142 }
d33278d1 7143 } else {
7fb16bac
PN
7144 if (what & REDIS_HASH_KEY) {
7145 o = dictGetEntryKey(hi->de);
7146 } else {
7147 o = dictGetEntryVal(hi->de);
d33278d1 7148 }
a3f3af86 7149 incrRefCount(o);
d33278d1 7150 }
7fb16bac 7151 return o;
d33278d1
PN
7152}
7153
d1578a33 7154static robj *hashTypeLookupWriteOrCreate(redisClient *c, robj *key) {
7fb16bac 7155 robj *o = lookupKeyWrite(c->db,key);
01426b05
PN
7156 if (o == NULL) {
7157 o = createHashObject();
09241813 7158 dbAdd(c->db,key,o);
01426b05
PN
7159 } else {
7160 if (o->type != REDIS_HASH) {
7161 addReply(c,shared.wrongtypeerr);
7fb16bac 7162 return NULL;
01426b05
PN
7163 }
7164 }
7fb16bac
PN
7165 return o;
7166}
01426b05 7167
7fb16bac
PN
7168/* ============================= Hash commands ============================== */
7169static void hsetCommand(redisClient *c) {
6e9e463f 7170 int update;
7fb16bac 7171 robj *o;
bbe025e0 7172
d1578a33
PN
7173 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7174 hashTypeTryConversion(o,c->argv,2,3);
7175 hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);
7176 update = hashTypeSet(o,c->argv[2],c->argv[3]);
6e9e463f 7177 addReply(c, update ? shared.czero : shared.cone);
7fb16bac
PN
7178 server.dirty++;
7179}
01426b05 7180
1f1c7695
PN
7181static void hsetnxCommand(redisClient *c) {
7182 robj *o;
d1578a33
PN
7183 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7184 hashTypeTryConversion(o,c->argv,2,3);
1f1c7695 7185
d1578a33 7186 if (hashTypeExists(o, c->argv[2])) {
1f1c7695 7187 addReply(c, shared.czero);
01426b05 7188 } else {
d1578a33
PN
7189 hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);
7190 hashTypeSet(o,c->argv[2],c->argv[3]);
1f1c7695
PN
7191 addReply(c, shared.cone);
7192 server.dirty++;
7193 }
7194}
01426b05 7195
7fb16bac
PN
7196static void hmsetCommand(redisClient *c) {
7197 int i;
7198 robj *o;
01426b05 7199
7fb16bac
PN
7200 if ((c->argc % 2) == 1) {
7201 addReplySds(c,sdsnew("-ERR wrong number of arguments for HMSET\r\n"));
7202 return;
7203 }
01426b05 7204
d1578a33
PN
7205 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7206 hashTypeTryConversion(o,c->argv,2,c->argc-1);
7fb16bac 7207 for (i = 2; i < c->argc; i += 2) {
d1578a33
PN
7208 hashTypeTryObjectEncoding(o,&c->argv[i], &c->argv[i+1]);
7209 hashTypeSet(o,c->argv[i],c->argv[i+1]);
7fb16bac
PN
7210 }
7211 addReply(c, shared.ok);
edc2f63a 7212 server.dirty++;
7fb16bac
PN
7213}
7214
7215static void hincrbyCommand(redisClient *c) {
7216 long long value, incr;
7217 robj *o, *current, *new;
7218
bd79a6bd 7219 if (getLongLongFromObjectOrReply(c,c->argv[3],&incr,NULL) != REDIS_OK) return;
d1578a33
PN
7220 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7221 if ((current = hashTypeGet(o,c->argv[2])) != NULL) {
946342c1
PN
7222 if (getLongLongFromObjectOrReply(c,current,&value,
7223 "hash value is not an integer") != REDIS_OK) {
7224 decrRefCount(current);
7225 return;
7226 }
a3f3af86 7227 decrRefCount(current);
7fb16bac
PN
7228 } else {
7229 value = 0;
01426b05
PN
7230 }
7231
7fb16bac 7232 value += incr;
3f973463 7233 new = createStringObjectFromLongLong(value);
d1578a33
PN
7234 hashTypeTryObjectEncoding(o,&c->argv[2],NULL);
7235 hashTypeSet(o,c->argv[2],new);
7fb16bac
PN
7236 decrRefCount(new);
7237 addReplyLongLong(c,value);
01426b05 7238 server.dirty++;
01426b05
PN
7239}
7240
978c2c94 7241static void hgetCommand(redisClient *c) {
7fb16bac 7242 robj *o, *value;
dd88747b 7243 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
7244 checkType(c,o,REDIS_HASH)) return;
7245
d1578a33 7246 if ((value = hashTypeGet(o,c->argv[2])) != NULL) {
7fb16bac 7247 addReplyBulk(c,value);
a3f3af86 7248 decrRefCount(value);
dd88747b 7249 } else {
7fb16bac 7250 addReply(c,shared.nullbulk);
69d95c3e 7251 }
69d95c3e
PN
7252}
7253
09aeb579
PN
7254static void hmgetCommand(redisClient *c) {
7255 int i;
7fb16bac
PN
7256 robj *o, *value;
7257 o = lookupKeyRead(c->db,c->argv[1]);
7258 if (o != NULL && o->type != REDIS_HASH) {
7259 addReply(c,shared.wrongtypeerr);
09aeb579
PN
7260 }
7261
7fb16bac
PN
7262 /* Note the check for o != NULL happens inside the loop. This is
7263 * done because objects that cannot be found are considered to be
7264 * an empty hash. The reply should then be a series of NULLs. */
09aeb579 7265 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-2));
7fb16bac 7266 for (i = 2; i < c->argc; i++) {
d1578a33 7267 if (o != NULL && (value = hashTypeGet(o,c->argv[i])) != NULL) {
7fb16bac 7268 addReplyBulk(c,value);
a3f3af86 7269 decrRefCount(value);
7fb16bac
PN
7270 } else {
7271 addReply(c,shared.nullbulk);
09aeb579
PN
7272 }
7273 }
7274}
7275
07efaf74 7276static void hdelCommand(redisClient *c) {
dd88747b 7277 robj *o;
dd88747b 7278 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
7279 checkType(c,o,REDIS_HASH)) return;
07efaf74 7280
d1578a33
PN
7281 if (hashTypeDelete(o,c->argv[2])) {
7282 if (hashTypeLength(o) == 0) dbDelete(c->db,c->argv[1]);
7fb16bac
PN
7283 addReply(c,shared.cone);
7284 server.dirty++;
dd88747b 7285 } else {
7fb16bac 7286 addReply(c,shared.czero);
07efaf74 7287 }
7288}
7289
92b27fe9 7290static void hlenCommand(redisClient *c) {
7291 robj *o;
dd88747b 7292 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
92b27fe9 7293 checkType(c,o,REDIS_HASH)) return;
7294
d1578a33 7295 addReplyUlong(c,hashTypeLength(o));
92b27fe9 7296}
7297
78409a0f 7298static void genericHgetallCommand(redisClient *c, int flags) {
7fb16bac 7299 robj *o, *lenobj, *obj;
78409a0f 7300 unsigned long count = 0;
d1578a33 7301 hashTypeIterator *hi;
78409a0f 7302
4e27f268 7303 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
78409a0f 7304 || checkType(c,o,REDIS_HASH)) return;
7305
7306 lenobj = createObject(REDIS_STRING,NULL);
7307 addReply(c,lenobj);
7308 decrRefCount(lenobj);
7309
d1578a33
PN
7310 hi = hashTypeInitIterator(o);
7311 while (hashTypeNext(hi) != REDIS_ERR) {
7fb16bac 7312 if (flags & REDIS_HASH_KEY) {
d1578a33 7313 obj = hashTypeCurrent(hi,REDIS_HASH_KEY);
7fb16bac 7314 addReplyBulk(c,obj);
a3f3af86 7315 decrRefCount(obj);
7fb16bac 7316 count++;
78409a0f 7317 }
7fb16bac 7318 if (flags & REDIS_HASH_VALUE) {
d1578a33 7319 obj = hashTypeCurrent(hi,REDIS_HASH_VALUE);
7fb16bac 7320 addReplyBulk(c,obj);
a3f3af86 7321 decrRefCount(obj);
7fb16bac 7322 count++;
78409a0f 7323 }
78409a0f 7324 }
d1578a33 7325 hashTypeReleaseIterator(hi);
7fb16bac 7326
78409a0f 7327 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",count);
7328}
7329
7330static void hkeysCommand(redisClient *c) {
7fb16bac 7331 genericHgetallCommand(c,REDIS_HASH_KEY);
78409a0f 7332}
7333
7334static void hvalsCommand(redisClient *c) {
7fb16bac 7335 genericHgetallCommand(c,REDIS_HASH_VALUE);
78409a0f 7336}
7337
7338static void hgetallCommand(redisClient *c) {
7fb16bac 7339 genericHgetallCommand(c,REDIS_HASH_KEY|REDIS_HASH_VALUE);
78409a0f 7340}
7341
a86f14b1 7342static void hexistsCommand(redisClient *c) {
7343 robj *o;
a86f14b1 7344 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
7345 checkType(c,o,REDIS_HASH)) return;
7346
d1578a33 7347 addReply(c, hashTypeExists(o,c->argv[2]) ? shared.cone : shared.czero);
a86f14b1 7348}
7349
ada386b2 7350static void convertToRealHash(robj *o) {
7351 unsigned char *key, *val, *p, *zm = o->ptr;
7352 unsigned int klen, vlen;
7353 dict *dict = dictCreate(&hashDictType,NULL);
7354
7355 assert(o->type == REDIS_HASH && o->encoding != REDIS_ENCODING_HT);
7356 p = zipmapRewind(zm);
7357 while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
7358 robj *keyobj, *valobj;
7359
7360 keyobj = createStringObject((char*)key,klen);
7361 valobj = createStringObject((char*)val,vlen);
05df7621 7362 keyobj = tryObjectEncoding(keyobj);
7363 valobj = tryObjectEncoding(valobj);
ada386b2 7364 dictAdd(dict,keyobj,valobj);
7365 }
7366 o->encoding = REDIS_ENCODING_HT;
7367 o->ptr = dict;
7368 zfree(zm);
7369}
7370
6b47e12e 7371/* ========================= Non type-specific commands ==================== */
7372
ed9b544e 7373static void flushdbCommand(redisClient *c) {
ca37e9cd 7374 server.dirty += dictSize(c->db->dict);
9b30e1a2 7375 touchWatchedKeysOnFlush(c->db->id);
3305306f 7376 dictEmpty(c->db->dict);
7377 dictEmpty(c->db->expires);
ed9b544e 7378 addReply(c,shared.ok);
ed9b544e 7379}
7380
7381static void flushallCommand(redisClient *c) {
9b30e1a2 7382 touchWatchedKeysOnFlush(-1);
ca37e9cd 7383 server.dirty += emptyDb();
ed9b544e 7384 addReply(c,shared.ok);
500ece7c 7385 if (server.bgsavechildpid != -1) {
7386 kill(server.bgsavechildpid,SIGKILL);
7387 rdbRemoveTempFile(server.bgsavechildpid);
7388 }
f78fd11b 7389 rdbSave(server.dbfilename);
ca37e9cd 7390 server.dirty++;
ed9b544e 7391}
7392
56906eef 7393static redisSortOperation *createSortOperation(int type, robj *pattern) {
ed9b544e 7394 redisSortOperation *so = zmalloc(sizeof(*so));
ed9b544e 7395 so->type = type;
7396 so->pattern = pattern;
7397 return so;
7398}
7399
7400/* Return the value associated to the key with a name obtained
55017f9d
PN
7401 * substituting the first occurence of '*' in 'pattern' with 'subst'.
7402 * The returned object will always have its refcount increased by 1
7403 * when it is non-NULL. */
56906eef 7404static robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
6d7d1370 7405 char *p, *f;
ed9b544e 7406 sds spat, ssub;
6d7d1370
PN
7407 robj keyobj, fieldobj, *o;
7408 int prefixlen, sublen, postfixlen, fieldlen;
ed9b544e 7409 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
7410 struct {
f1017b3f 7411 long len;
7412 long free;
ed9b544e 7413 char buf[REDIS_SORTKEY_MAX+1];
6d7d1370 7414 } keyname, fieldname;
ed9b544e 7415
28173a49 7416 /* If the pattern is "#" return the substitution object itself in order
7417 * to implement the "SORT ... GET #" feature. */
7418 spat = pattern->ptr;
7419 if (spat[0] == '#' && spat[1] == '\0') {
55017f9d 7420 incrRefCount(subst);
28173a49 7421 return subst;
7422 }
7423
7424 /* The substitution object may be specially encoded. If so we create
9d65a1bb 7425 * a decoded object on the fly. Otherwise getDecodedObject will just
7426 * increment the ref count, that we'll decrement later. */
7427 subst = getDecodedObject(subst);
942a3961 7428
ed9b544e 7429 ssub = subst->ptr;
7430 if (sdslen(spat)+sdslen(ssub)-1 > REDIS_SORTKEY_MAX) return NULL;
7431 p = strchr(spat,'*');
ed5a857a 7432 if (!p) {
7433 decrRefCount(subst);
7434 return NULL;
7435 }
ed9b544e 7436
6d7d1370
PN
7437 /* Find out if we're dealing with a hash dereference. */
7438 if ((f = strstr(p+1, "->")) != NULL) {
7439 fieldlen = sdslen(spat)-(f-spat);
7440 /* this also copies \0 character */
7441 memcpy(fieldname.buf,f+2,fieldlen-1);
7442 fieldname.len = fieldlen-2;
7443 } else {
7444 fieldlen = 0;
7445 }
7446
ed9b544e 7447 prefixlen = p-spat;
7448 sublen = sdslen(ssub);
6d7d1370 7449 postfixlen = sdslen(spat)-(prefixlen+1)-fieldlen;
ed9b544e 7450 memcpy(keyname.buf,spat,prefixlen);
7451 memcpy(keyname.buf+prefixlen,ssub,sublen);
7452 memcpy(keyname.buf+prefixlen+sublen,p+1,postfixlen);
7453 keyname.buf[prefixlen+sublen+postfixlen] = '\0';
7454 keyname.len = prefixlen+sublen+postfixlen;
942a3961 7455 decrRefCount(subst);
7456
6d7d1370
PN
7457 /* Lookup substituted key */
7458 initStaticStringObject(keyobj,((char*)&keyname)+(sizeof(long)*2));
7459 o = lookupKeyRead(db,&keyobj);
55017f9d
PN
7460 if (o == NULL) return NULL;
7461
7462 if (fieldlen > 0) {
7463 if (o->type != REDIS_HASH || fieldname.len < 1) return NULL;
6d7d1370 7464
705dad38
PN
7465 /* Retrieve value from hash by the field name. This operation
7466 * already increases the refcount of the returned object. */
6d7d1370 7467 initStaticStringObject(fieldobj,((char*)&fieldname)+(sizeof(long)*2));
d1578a33 7468 o = hashTypeGet(o, &fieldobj);
705dad38 7469 } else {
55017f9d 7470 if (o->type != REDIS_STRING) return NULL;
b6f07345 7471
705dad38
PN
7472 /* Every object that this function returns needs to have its refcount
7473 * increased. sortCommand decreases it again. */
7474 incrRefCount(o);
6d7d1370
PN
7475 }
7476
7477 return o;
ed9b544e 7478}
7479
7480/* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
7481 * the additional parameter is not standard but a BSD-specific we have to
7482 * pass sorting parameters via the global 'server' structure */
7483static int sortCompare(const void *s1, const void *s2) {
7484 const redisSortObject *so1 = s1, *so2 = s2;
7485 int cmp;
7486
7487 if (!server.sort_alpha) {
7488 /* Numeric sorting. Here it's trivial as we precomputed scores */
7489 if (so1->u.score > so2->u.score) {
7490 cmp = 1;
7491 } else if (so1->u.score < so2->u.score) {
7492 cmp = -1;
7493 } else {
7494 cmp = 0;
7495 }
7496 } else {
7497 /* Alphanumeric sorting */
7498 if (server.sort_bypattern) {
7499 if (!so1->u.cmpobj || !so2->u.cmpobj) {
7500 /* At least one compare object is NULL */
7501 if (so1->u.cmpobj == so2->u.cmpobj)
7502 cmp = 0;
7503 else if (so1->u.cmpobj == NULL)
7504 cmp = -1;
7505 else
7506 cmp = 1;
7507 } else {
7508 /* We have both the objects, use strcoll */
7509 cmp = strcoll(so1->u.cmpobj->ptr,so2->u.cmpobj->ptr);
7510 }
7511 } else {
08ee9b57 7512 /* Compare elements directly. */
7513 cmp = compareStringObjects(so1->obj,so2->obj);
ed9b544e 7514 }
7515 }
7516 return server.sort_desc ? -cmp : cmp;
7517}
7518
7519/* The SORT command is the most complex command in Redis. Warning: this code
7520 * is optimized for speed and a bit less for readability */
7521static void sortCommand(redisClient *c) {
ed9b544e 7522 list *operations;
a03611e1 7523 unsigned int outputlen = 0;
ed9b544e 7524 int desc = 0, alpha = 0;
7525 int limit_start = 0, limit_count = -1, start, end;
7526 int j, dontsort = 0, vectorlen;
7527 int getop = 0; /* GET operation counter */
443c6409 7528 robj *sortval, *sortby = NULL, *storekey = NULL;
ed9b544e 7529 redisSortObject *vector; /* Resulting vector to sort */
7530
7531 /* Lookup the key to sort. It must be of the right types */
3305306f 7532 sortval = lookupKeyRead(c->db,c->argv[1]);
7533 if (sortval == NULL) {
4e27f268 7534 addReply(c,shared.emptymultibulk);
ed9b544e 7535 return;
7536 }
a5eb649b 7537 if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST &&
7538 sortval->type != REDIS_ZSET)
7539 {
c937aa89 7540 addReply(c,shared.wrongtypeerr);
ed9b544e 7541 return;
7542 }
7543
7544 /* Create a list of operations to perform for every sorted element.
7545 * Operations can be GET/DEL/INCR/DECR */
7546 operations = listCreate();
092dac2a 7547 listSetFreeMethod(operations,zfree);
ed9b544e 7548 j = 2;
7549
7550 /* Now we need to protect sortval incrementing its count, in the future
7551 * SORT may have options able to overwrite/delete keys during the sorting
7552 * and the sorted key itself may get destroied */
7553 incrRefCount(sortval);
7554
7555 /* The SORT command has an SQL-alike syntax, parse it */
7556 while(j < c->argc) {
7557 int leftargs = c->argc-j-1;
7558 if (!strcasecmp(c->argv[j]->ptr,"asc")) {
7559 desc = 0;
7560 } else if (!strcasecmp(c->argv[j]->ptr,"desc")) {
7561 desc = 1;
7562 } else if (!strcasecmp(c->argv[j]->ptr,"alpha")) {
7563 alpha = 1;
7564 } else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) {
7565 limit_start = atoi(c->argv[j+1]->ptr);
7566 limit_count = atoi(c->argv[j+2]->ptr);
7567 j+=2;
443c6409 7568 } else if (!strcasecmp(c->argv[j]->ptr,"store") && leftargs >= 1) {
7569 storekey = c->argv[j+1];
7570 j++;
ed9b544e 7571 } else if (!strcasecmp(c->argv[j]->ptr,"by") && leftargs >= 1) {
7572 sortby = c->argv[j+1];
7573 /* If the BY pattern does not contain '*', i.e. it is constant,
7574 * we don't need to sort nor to lookup the weight keys. */
7575 if (strchr(c->argv[j+1]->ptr,'*') == NULL) dontsort = 1;
7576 j++;
7577 } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
7578 listAddNodeTail(operations,createSortOperation(
7579 REDIS_SORT_GET,c->argv[j+1]));
7580 getop++;
7581 j++;
ed9b544e 7582 } else {
7583 decrRefCount(sortval);
7584 listRelease(operations);
c937aa89 7585 addReply(c,shared.syntaxerr);
ed9b544e 7586 return;
7587 }
7588 j++;
7589 }
7590
7591 /* Load the sorting vector with all the objects to sort */
a5eb649b 7592 switch(sortval->type) {
003f0840 7593 case REDIS_LIST: vectorlen = listTypeLength(sortval); break;
a5eb649b 7594 case REDIS_SET: vectorlen = dictSize((dict*)sortval->ptr); break;
7595 case REDIS_ZSET: vectorlen = dictSize(((zset*)sortval->ptr)->dict); break;
f83c6cb5 7596 default: vectorlen = 0; redisPanic("Bad SORT type"); /* Avoid GCC warning */
a5eb649b 7597 }
ed9b544e 7598 vector = zmalloc(sizeof(redisSortObject)*vectorlen);
ed9b544e 7599 j = 0;
a5eb649b 7600
ed9b544e 7601 if (sortval->type == REDIS_LIST) {
003f0840
PN
7602 listTypeIterator *li = listTypeInitIterator(sortval,0,REDIS_TAIL);
7603 listTypeEntry entry;
7604 while(listTypeNext(li,&entry)) {
7605 vector[j].obj = listTypeGet(&entry);
ed9b544e 7606 vector[j].u.score = 0;
7607 vector[j].u.cmpobj = NULL;
ed9b544e 7608 j++;
7609 }
003f0840 7610 listTypeReleaseIterator(li);
ed9b544e 7611 } else {
a5eb649b 7612 dict *set;
ed9b544e 7613 dictIterator *di;
7614 dictEntry *setele;
7615
a5eb649b 7616 if (sortval->type == REDIS_SET) {
7617 set = sortval->ptr;
7618 } else {
7619 zset *zs = sortval->ptr;
7620 set = zs->dict;
7621 }
7622
ed9b544e 7623 di = dictGetIterator(set);
ed9b544e 7624 while((setele = dictNext(di)) != NULL) {
7625 vector[j].obj = dictGetEntryKey(setele);
7626 vector[j].u.score = 0;
7627 vector[j].u.cmpobj = NULL;
7628 j++;
7629 }
7630 dictReleaseIterator(di);
7631 }
dfc5e96c 7632 redisAssert(j == vectorlen);
ed9b544e 7633
7634 /* Now it's time to load the right scores in the sorting vector */
7635 if (dontsort == 0) {
7636 for (j = 0; j < vectorlen; j++) {
6d7d1370 7637 robj *byval;
ed9b544e 7638 if (sortby) {
6d7d1370 7639 /* lookup value to sort by */
3305306f 7640 byval = lookupKeyByPattern(c->db,sortby,vector[j].obj);
705dad38 7641 if (!byval) continue;
ed9b544e 7642 } else {
6d7d1370
PN
7643 /* use object itself to sort by */
7644 byval = vector[j].obj;
7645 }
7646
7647 if (alpha) {
08ee9b57 7648 if (sortby) vector[j].u.cmpobj = getDecodedObject(byval);
6d7d1370
PN
7649 } else {
7650 if (byval->encoding == REDIS_ENCODING_RAW) {
7651 vector[j].u.score = strtod(byval->ptr,NULL);
16fa22f1 7652 } else if (byval->encoding == REDIS_ENCODING_INT) {
6d7d1370
PN
7653 /* Don't need to decode the object if it's
7654 * integer-encoded (the only encoding supported) so
7655 * far. We can just cast it */
16fa22f1
PN
7656 vector[j].u.score = (long)byval->ptr;
7657 } else {
7658 redisAssert(1 != 1);
942a3961 7659 }
ed9b544e 7660 }
6d7d1370 7661
705dad38
PN
7662 /* when the object was retrieved using lookupKeyByPattern,
7663 * its refcount needs to be decreased. */
7664 if (sortby) {
7665 decrRefCount(byval);
ed9b544e 7666 }
7667 }
7668 }
7669
7670 /* We are ready to sort the vector... perform a bit of sanity check
7671 * on the LIMIT option too. We'll use a partial version of quicksort. */
7672 start = (limit_start < 0) ? 0 : limit_start;
7673 end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1;
7674 if (start >= vectorlen) {
7675 start = vectorlen-1;
7676 end = vectorlen-2;
7677 }
7678 if (end >= vectorlen) end = vectorlen-1;
7679
7680 if (dontsort == 0) {
7681 server.sort_desc = desc;
7682 server.sort_alpha = alpha;
7683 server.sort_bypattern = sortby ? 1 : 0;
5f5b9840 7684 if (sortby && (start != 0 || end != vectorlen-1))
7685 pqsort(vector,vectorlen,sizeof(redisSortObject),sortCompare, start,end);
7686 else
7687 qsort(vector,vectorlen,sizeof(redisSortObject),sortCompare);
ed9b544e 7688 }
7689
7690 /* Send command output to the output buffer, performing the specified
7691 * GET/DEL/INCR/DECR operations if any. */
7692 outputlen = getop ? getop*(end-start+1) : end-start+1;
443c6409 7693 if (storekey == NULL) {
7694 /* STORE option not specified, sent the sorting result to client */
7695 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",outputlen));
7696 for (j = start; j <= end; j++) {
7697 listNode *ln;
c7df85a4 7698 listIter li;
7699
dd88747b 7700 if (!getop) addReplyBulk(c,vector[j].obj);
c7df85a4 7701 listRewind(operations,&li);
7702 while((ln = listNext(&li))) {
443c6409 7703 redisSortOperation *sop = ln->value;
7704 robj *val = lookupKeyByPattern(c->db,sop->pattern,
7705 vector[j].obj);
7706
7707 if (sop->type == REDIS_SORT_GET) {
55017f9d 7708 if (!val) {
443c6409 7709 addReply(c,shared.nullbulk);
7710 } else {
dd88747b 7711 addReplyBulk(c,val);
55017f9d 7712 decrRefCount(val);
443c6409 7713 }
7714 } else {
dfc5e96c 7715 redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
443c6409 7716 }
7717 }
ed9b544e 7718 }
443c6409 7719 } else {
74e0f445 7720 robj *sobj = createZiplistObject();
443c6409 7721
7722 /* STORE option specified, set the sorting result as a List object */
7723 for (j = start; j <= end; j++) {
7724 listNode *ln;
c7df85a4 7725 listIter li;
7726
443c6409 7727 if (!getop) {
003f0840 7728 listTypePush(sobj,vector[j].obj,REDIS_TAIL);
a03611e1
PN
7729 } else {
7730 listRewind(operations,&li);
7731 while((ln = listNext(&li))) {
7732 redisSortOperation *sop = ln->value;
7733 robj *val = lookupKeyByPattern(c->db,sop->pattern,
7734 vector[j].obj);
7735
7736 if (sop->type == REDIS_SORT_GET) {
7737 if (!val) val = createStringObject("",0);
7738
003f0840 7739 /* listTypePush does an incrRefCount, so we should take care
a03611e1
PN
7740 * care of the incremented refcount caused by either
7741 * lookupKeyByPattern or createStringObject("",0) */
003f0840 7742 listTypePush(sobj,val,REDIS_TAIL);
a03611e1 7743 decrRefCount(val);
443c6409 7744 } else {
a03611e1
PN
7745 /* always fails */
7746 redisAssert(sop->type == REDIS_SORT_GET);
443c6409 7747 }
ed9b544e 7748 }
ed9b544e 7749 }
ed9b544e 7750 }
846d8b3e 7751 dbReplace(c->db,storekey,sobj);
443c6409 7752 /* Note: we add 1 because the DB is dirty anyway since even if the
7753 * SORT result is empty a new key is set and maybe the old content
7754 * replaced. */
7755 server.dirty += 1+outputlen;
7756 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",outputlen));
ed9b544e 7757 }
7758
7759 /* Cleanup */
a03611e1
PN
7760 if (sortval->type == REDIS_LIST)
7761 for (j = 0; j < vectorlen; j++)
7762 decrRefCount(vector[j].obj);
ed9b544e 7763 decrRefCount(sortval);
7764 listRelease(operations);
7765 for (j = 0; j < vectorlen; j++) {
16fa22f1 7766 if (alpha && vector[j].u.cmpobj)
ed9b544e 7767 decrRefCount(vector[j].u.cmpobj);
7768 }
7769 zfree(vector);
7770}
7771
ec6c7a1d 7772/* Convert an amount of bytes into a human readable string in the form
7773 * of 100B, 2G, 100M, 4K, and so forth. */
7774static void bytesToHuman(char *s, unsigned long long n) {
7775 double d;
7776
7777 if (n < 1024) {
7778 /* Bytes */
7779 sprintf(s,"%lluB",n);
7780 return;
7781 } else if (n < (1024*1024)) {
7782 d = (double)n/(1024);
7783 sprintf(s,"%.2fK",d);
7784 } else if (n < (1024LL*1024*1024)) {
7785 d = (double)n/(1024*1024);
7786 sprintf(s,"%.2fM",d);
7787 } else if (n < (1024LL*1024*1024*1024)) {
7788 d = (double)n/(1024LL*1024*1024);
b72f6a4b 7789 sprintf(s,"%.2fG",d);
ec6c7a1d 7790 }
7791}
7792
1c85b79f 7793/* Create the string returned by the INFO command. This is decoupled
7794 * by the INFO command itself as we need to report the same information
7795 * on memory corruption problems. */
7796static sds genRedisInfoString(void) {
ed9b544e 7797 sds info;
7798 time_t uptime = time(NULL)-server.stat_starttime;
c3cb078d 7799 int j;
ec6c7a1d 7800 char hmem[64];
55a8298f 7801
b72f6a4b 7802 bytesToHuman(hmem,zmalloc_used_memory());
ed9b544e 7803 info = sdscatprintf(sdsempty(),
7804 "redis_version:%s\r\n"
5436146c
PN
7805 "redis_git_sha1:%s\r\n"
7806 "redis_git_dirty:%d\r\n"
f1017b3f 7807 "arch_bits:%s\r\n"
7a932b74 7808 "multiplexing_api:%s\r\n"
0d7170a4 7809 "process_id:%ld\r\n"
682ac724 7810 "uptime_in_seconds:%ld\r\n"
7811 "uptime_in_days:%ld\r\n"
ed9b544e 7812 "connected_clients:%d\r\n"
7813 "connected_slaves:%d\r\n"
f86a74e9 7814 "blocked_clients:%d\r\n"
5fba9f71 7815 "used_memory:%zu\r\n"
ec6c7a1d 7816 "used_memory_human:%s\r\n"
ed9b544e 7817 "changes_since_last_save:%lld\r\n"
be2bb6b0 7818 "bgsave_in_progress:%d\r\n"
682ac724 7819 "last_save_time:%ld\r\n"
b3fad521 7820 "bgrewriteaof_in_progress:%d\r\n"
ed9b544e 7821 "total_connections_received:%lld\r\n"
7822 "total_commands_processed:%lld\r\n"
2a6a2ed1 7823 "expired_keys:%lld\r\n"
3be2c9d7 7824 "hash_max_zipmap_entries:%zu\r\n"
7825 "hash_max_zipmap_value:%zu\r\n"
ffc6b7f8 7826 "pubsub_channels:%ld\r\n"
7827 "pubsub_patterns:%u\r\n"
7d98e08c 7828 "vm_enabled:%d\r\n"
a0f643ea 7829 "role:%s\r\n"
ed9b544e 7830 ,REDIS_VERSION,
5436146c 7831 REDIS_GIT_SHA1,
274e45e3 7832 strtol(REDIS_GIT_DIRTY,NULL,10) > 0,
f1017b3f 7833 (sizeof(long) == 8) ? "64" : "32",
7a932b74 7834 aeGetApiName(),
0d7170a4 7835 (long) getpid(),
a0f643ea 7836 uptime,
7837 uptime/(3600*24),
ed9b544e 7838 listLength(server.clients)-listLength(server.slaves),
7839 listLength(server.slaves),
d5d55fc3 7840 server.blpop_blocked_clients,
b72f6a4b 7841 zmalloc_used_memory(),
ec6c7a1d 7842 hmem,
ed9b544e 7843 server.dirty,
9d65a1bb 7844 server.bgsavechildpid != -1,
ed9b544e 7845 server.lastsave,
b3fad521 7846 server.bgrewritechildpid != -1,
ed9b544e 7847 server.stat_numconnections,
7848 server.stat_numcommands,
2a6a2ed1 7849 server.stat_expiredkeys,
55a8298f 7850 server.hash_max_zipmap_entries,
7851 server.hash_max_zipmap_value,
ffc6b7f8 7852 dictSize(server.pubsub_channels),
7853 listLength(server.pubsub_patterns),
7d98e08c 7854 server.vm_enabled != 0,
a0f643ea 7855 server.masterhost == NULL ? "master" : "slave"
ed9b544e 7856 );
a0f643ea 7857 if (server.masterhost) {
7858 info = sdscatprintf(info,
7859 "master_host:%s\r\n"
7860 "master_port:%d\r\n"
7861 "master_link_status:%s\r\n"
7862 "master_last_io_seconds_ago:%d\r\n"
7863 ,server.masterhost,
7864 server.masterport,
7865 (server.replstate == REDIS_REPL_CONNECTED) ?
7866 "up" : "down",
f72b934d 7867 server.master ? ((int)(time(NULL)-server.master->lastinteraction)) : -1
a0f643ea 7868 );
7869 }
7d98e08c 7870 if (server.vm_enabled) {
1064ef87 7871 lockThreadedIO();
7d98e08c 7872 info = sdscatprintf(info,
7873 "vm_conf_max_memory:%llu\r\n"
7874 "vm_conf_page_size:%llu\r\n"
7875 "vm_conf_pages:%llu\r\n"
7876 "vm_stats_used_pages:%llu\r\n"
7877 "vm_stats_swapped_objects:%llu\r\n"
7878 "vm_stats_swappin_count:%llu\r\n"
7879 "vm_stats_swappout_count:%llu\r\n"
b9bc0eef 7880 "vm_stats_io_newjobs_len:%lu\r\n"
7881 "vm_stats_io_processing_len:%lu\r\n"
7882 "vm_stats_io_processed_len:%lu\r\n"
25fd2cb2 7883 "vm_stats_io_active_threads:%lu\r\n"
d5d55fc3 7884 "vm_stats_blocked_clients:%lu\r\n"
7d98e08c 7885 ,(unsigned long long) server.vm_max_memory,
7886 (unsigned long long) server.vm_page_size,
7887 (unsigned long long) server.vm_pages,
7888 (unsigned long long) server.vm_stats_used_pages,
7889 (unsigned long long) server.vm_stats_swapped_objects,
7890 (unsigned long long) server.vm_stats_swapins,
b9bc0eef 7891 (unsigned long long) server.vm_stats_swapouts,
7892 (unsigned long) listLength(server.io_newjobs),
7893 (unsigned long) listLength(server.io_processing),
7894 (unsigned long) listLength(server.io_processed),
d5d55fc3 7895 (unsigned long) server.io_active_threads,
7896 (unsigned long) server.vm_blocked_clients
7d98e08c 7897 );
1064ef87 7898 unlockThreadedIO();
7d98e08c 7899 }
c3cb078d 7900 for (j = 0; j < server.dbnum; j++) {
7901 long long keys, vkeys;
7902
7903 keys = dictSize(server.db[j].dict);
7904 vkeys = dictSize(server.db[j].expires);
7905 if (keys || vkeys) {
9d65a1bb 7906 info = sdscatprintf(info, "db%d:keys=%lld,expires=%lld\r\n",
c3cb078d 7907 j, keys, vkeys);
7908 }
7909 }
1c85b79f 7910 return info;
7911}
7912
7913static void infoCommand(redisClient *c) {
7914 sds info = genRedisInfoString();
83c6a618 7915 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n",
7916 (unsigned long)sdslen(info)));
ed9b544e 7917 addReplySds(c,info);
70003d28 7918 addReply(c,shared.crlf);
ed9b544e 7919}
7920
3305306f 7921static void monitorCommand(redisClient *c) {
7922 /* ignore MONITOR if aleady slave or in monitor mode */
7923 if (c->flags & REDIS_SLAVE) return;
7924
7925 c->flags |= (REDIS_SLAVE|REDIS_MONITOR);
7926 c->slaveseldb = 0;
6b47e12e 7927 listAddNodeTail(server.monitors,c);
3305306f 7928 addReply(c,shared.ok);
7929}
7930
7931/* ================================= Expire ================================= */
7932static int removeExpire(redisDb *db, robj *key) {
09241813 7933 if (dictDelete(db->expires,key->ptr) == DICT_OK) {
3305306f 7934 return 1;
7935 } else {
7936 return 0;
7937 }
7938}
7939
7940static int setExpire(redisDb *db, robj *key, time_t when) {
09241813 7941 sds copy = sdsdup(key->ptr);
7942 if (dictAdd(db->expires,copy,(void*)when) == DICT_ERR) {
7943 sdsfree(copy);
3305306f 7944 return 0;
7945 } else {
3305306f 7946 return 1;
7947 }
7948}
7949
bb32ede5 7950/* Return the expire time of the specified key, or -1 if no expire
7951 * is associated with this key (i.e. the key is non volatile) */
7952static time_t getExpire(redisDb *db, robj *key) {
7953 dictEntry *de;
7954
7955 /* No expire? return ASAP */
7956 if (dictSize(db->expires) == 0 ||
09241813 7957 (de = dictFind(db->expires,key->ptr)) == NULL) return -1;
bb32ede5 7958
7959 return (time_t) dictGetEntryVal(de);
7960}
7961
3305306f 7962static int expireIfNeeded(redisDb *db, robj *key) {
7963 time_t when;
7964 dictEntry *de;
7965
7966 /* No expire? return ASAP */
7967 if (dictSize(db->expires) == 0 ||
09241813 7968 (de = dictFind(db->expires,key->ptr)) == NULL) return 0;
3305306f 7969
7970 /* Lookup the expire */
7971 when = (time_t) dictGetEntryVal(de);
7972 if (time(NULL) <= when) return 0;
7973
7974 /* Delete the key */
09241813 7975 dbDelete(db,key);
2a6a2ed1 7976 server.stat_expiredkeys++;
09241813 7977 return 1;
3305306f 7978}
7979
7980static int deleteIfVolatile(redisDb *db, robj *key) {
7981 dictEntry *de;
7982
7983 /* No expire? return ASAP */
7984 if (dictSize(db->expires) == 0 ||
09241813 7985 (de = dictFind(db->expires,key->ptr)) == NULL) return 0;
3305306f 7986
7987 /* Delete the key */
0c66a471 7988 server.dirty++;
2a6a2ed1 7989 server.stat_expiredkeys++;
09241813 7990 dictDelete(db->expires,key->ptr);
7991 return dictDelete(db->dict,key->ptr) == DICT_OK;
3305306f 7992}
7993
bbe025e0 7994static void expireGenericCommand(redisClient *c, robj *key, robj *param, long offset) {
3305306f 7995 dictEntry *de;
bbe025e0
AM
7996 time_t seconds;
7997
bd79a6bd 7998 if (getLongFromObjectOrReply(c, param, &seconds, NULL) != REDIS_OK) return;
bbe025e0
AM
7999
8000 seconds -= offset;
3305306f 8001
09241813 8002 de = dictFind(c->db->dict,key->ptr);
3305306f 8003 if (de == NULL) {
8004 addReply(c,shared.czero);
8005 return;
8006 }
d4dd6556 8007 if (seconds <= 0) {
09241813 8008 if (dbDelete(c->db,key)) server.dirty++;
43e5ccdf 8009 addReply(c, shared.cone);
3305306f 8010 return;
8011 } else {
8012 time_t when = time(NULL)+seconds;
802e8373 8013 if (setExpire(c->db,key,when)) {
3305306f 8014 addReply(c,shared.cone);
77423026 8015 server.dirty++;
8016 } else {
3305306f 8017 addReply(c,shared.czero);
77423026 8018 }
3305306f 8019 return;
8020 }
8021}
8022
802e8373 8023static void expireCommand(redisClient *c) {
bbe025e0 8024 expireGenericCommand(c,c->argv[1],c->argv[2],0);
802e8373 8025}
8026
8027static void expireatCommand(redisClient *c) {
bbe025e0 8028 expireGenericCommand(c,c->argv[1],c->argv[2],time(NULL));
802e8373 8029}
8030
fd88489a 8031static void ttlCommand(redisClient *c) {
8032 time_t expire;
8033 int ttl = -1;
8034
8035 expire = getExpire(c->db,c->argv[1]);
8036 if (expire != -1) {
8037 ttl = (int) (expire-time(NULL));
8038 if (ttl < 0) ttl = -1;
8039 }
8040 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",ttl));
8041}
8042
6e469882 8043/* ================================ MULTI/EXEC ============================== */
8044
8045/* Client state initialization for MULTI/EXEC */
8046static void initClientMultiState(redisClient *c) {
8047 c->mstate.commands = NULL;
8048 c->mstate.count = 0;
8049}
8050
8051/* Release all the resources associated with MULTI/EXEC state */
8052static void freeClientMultiState(redisClient *c) {
8053 int j;
8054
8055 for (j = 0; j < c->mstate.count; j++) {
8056 int i;
8057 multiCmd *mc = c->mstate.commands+j;
8058
8059 for (i = 0; i < mc->argc; i++)
8060 decrRefCount(mc->argv[i]);
8061 zfree(mc->argv);
8062 }
8063 zfree(c->mstate.commands);
8064}
8065
8066/* Add a new command into the MULTI commands queue */
8067static void queueMultiCommand(redisClient *c, struct redisCommand *cmd) {
8068 multiCmd *mc;
8069 int j;
8070
8071 c->mstate.commands = zrealloc(c->mstate.commands,
8072 sizeof(multiCmd)*(c->mstate.count+1));
8073 mc = c->mstate.commands+c->mstate.count;
8074 mc->cmd = cmd;
8075 mc->argc = c->argc;
8076 mc->argv = zmalloc(sizeof(robj*)*c->argc);
8077 memcpy(mc->argv,c->argv,sizeof(robj*)*c->argc);
8078 for (j = 0; j < c->argc; j++)
8079 incrRefCount(mc->argv[j]);
8080 c->mstate.count++;
8081}
8082
8083static void multiCommand(redisClient *c) {
6531c94d 8084 if (c->flags & REDIS_MULTI) {
8085 addReplySds(c,sdsnew("-ERR MULTI calls can not be nested\r\n"));
8086 return;
8087 }
6e469882 8088 c->flags |= REDIS_MULTI;
36c548f0 8089 addReply(c,shared.ok);
6e469882 8090}
8091
18b6cb76
DJ
8092static void discardCommand(redisClient *c) {
8093 if (!(c->flags & REDIS_MULTI)) {
8094 addReplySds(c,sdsnew("-ERR DISCARD without MULTI\r\n"));
8095 return;
8096 }
8097
8098 freeClientMultiState(c);
8099 initClientMultiState(c);
8100 c->flags &= (~REDIS_MULTI);
a2645226 8101 unwatchAllKeys(c);
18b6cb76
DJ
8102 addReply(c,shared.ok);
8103}
8104
66c8853f 8105/* Send a MULTI command to all the slaves and AOF file. Check the execCommand
8106 * implememntation for more information. */
8107static void execCommandReplicateMulti(redisClient *c) {
8108 struct redisCommand *cmd;
8109 robj *multistring = createStringObject("MULTI",5);
8110
8111 cmd = lookupCommand("multi");
8112 if (server.appendonly)
8113 feedAppendOnlyFile(cmd,c->db->id,&multistring,1);
8114 if (listLength(server.slaves))
8115 replicationFeedSlaves(server.slaves,c->db->id,&multistring,1);
8116 decrRefCount(multistring);
8117}
8118
6e469882 8119static void execCommand(redisClient *c) {
8120 int j;
8121 robj **orig_argv;
8122 int orig_argc;
8123
8124 if (!(c->flags & REDIS_MULTI)) {
8125 addReplySds(c,sdsnew("-ERR EXEC without MULTI\r\n"));
8126 return;
8127 }
8128
37ab76c9 8129 /* Check if we need to abort the EXEC if some WATCHed key was touched.
8130 * A failed EXEC will return a multi bulk nil object. */
8131 if (c->flags & REDIS_DIRTY_CAS) {
8132 freeClientMultiState(c);
8133 initClientMultiState(c);
8134 c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS);
8135 unwatchAllKeys(c);
8136 addReply(c,shared.nullmultibulk);
8137 return;
8138 }
8139
66c8853f 8140 /* Replicate a MULTI request now that we are sure the block is executed.
8141 * This way we'll deliver the MULTI/..../EXEC block as a whole and
8142 * both the AOF and the replication link will have the same consistency
8143 * and atomicity guarantees. */
8144 execCommandReplicateMulti(c);
8145
8146 /* Exec all the queued commands */
1ad4d316 8147 unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */
6e469882 8148 orig_argv = c->argv;
8149 orig_argc = c->argc;
8150 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->mstate.count));
8151 for (j = 0; j < c->mstate.count; j++) {
8152 c->argc = c->mstate.commands[j].argc;
8153 c->argv = c->mstate.commands[j].argv;
8154 call(c,c->mstate.commands[j].cmd);
8155 }
8156 c->argv = orig_argv;
8157 c->argc = orig_argc;
8158 freeClientMultiState(c);
8159 initClientMultiState(c);
1ad4d316 8160 c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS);
66c8853f 8161 /* Make sure the EXEC command is always replicated / AOF, since we
8162 * always send the MULTI command (we can't know beforehand if the
8163 * next operations will contain at least a modification to the DB). */
8164 server.dirty++;
6e469882 8165}
8166
4409877e 8167/* =========================== Blocking Operations ========================= */
8168
8169/* Currently Redis blocking operations support is limited to list POP ops,
8170 * so the current implementation is not fully generic, but it is also not
8171 * completely specific so it will not require a rewrite to support new
8172 * kind of blocking operations in the future.
8173 *
8174 * Still it's important to note that list blocking operations can be already
8175 * used as a notification mechanism in order to implement other blocking
8176 * operations at application level, so there must be a very strong evidence
8177 * of usefulness and generality before new blocking operations are implemented.
8178 *
8179 * This is how the current blocking POP works, we use BLPOP as example:
8180 * - If the user calls BLPOP and the key exists and contains a non empty list
8181 * then LPOP is called instead. So BLPOP is semantically the same as LPOP
8182 * if there is not to block.
8183 * - If instead BLPOP is called and the key does not exists or the list is
8184 * empty we need to block. In order to do so we remove the notification for
8185 * new data to read in the client socket (so that we'll not serve new
8186 * requests if the blocking request is not served). Also we put the client
37ab76c9 8187 * in a dictionary (db->blocking_keys) mapping keys to a list of clients
4409877e 8188 * blocking for this keys.
8189 * - If a PUSH operation against a key with blocked clients waiting is
8190 * performed, we serve the first in the list: basically instead to push
8191 * the new element inside the list we return it to the (first / oldest)
8192 * blocking client, unblock the client, and remove it form the list.
8193 *
8194 * The above comment and the source code should be enough in order to understand
8195 * the implementation and modify / fix it later.
8196 */
8197
8198/* Set a client in blocking mode for the specified key, with the specified
8199 * timeout */
b177fd30 8200static void blockForKeys(redisClient *c, robj **keys, int numkeys, time_t timeout) {
4409877e 8201 dictEntry *de;
8202 list *l;
b177fd30 8203 int j;
4409877e 8204
37ab76c9 8205 c->blocking_keys = zmalloc(sizeof(robj*)*numkeys);
8206 c->blocking_keys_num = numkeys;
4409877e 8207 c->blockingto = timeout;
b177fd30 8208 for (j = 0; j < numkeys; j++) {
8209 /* Add the key in the client structure, to map clients -> keys */
37ab76c9 8210 c->blocking_keys[j] = keys[j];
b177fd30 8211 incrRefCount(keys[j]);
4409877e 8212
b177fd30 8213 /* And in the other "side", to map keys -> clients */
37ab76c9 8214 de = dictFind(c->db->blocking_keys,keys[j]);
b177fd30 8215 if (de == NULL) {
8216 int retval;
8217
8218 /* For every key we take a list of clients blocked for it */
8219 l = listCreate();
37ab76c9 8220 retval = dictAdd(c->db->blocking_keys,keys[j],l);
b177fd30 8221 incrRefCount(keys[j]);
8222 assert(retval == DICT_OK);
8223 } else {
8224 l = dictGetEntryVal(de);
8225 }
8226 listAddNodeTail(l,c);
4409877e 8227 }
b177fd30 8228 /* Mark the client as a blocked client */
4409877e 8229 c->flags |= REDIS_BLOCKED;
d5d55fc3 8230 server.blpop_blocked_clients++;
4409877e 8231}
8232
8233/* Unblock a client that's waiting in a blocking operation such as BLPOP */
b0d8747d 8234static void unblockClientWaitingData(redisClient *c) {
4409877e 8235 dictEntry *de;
8236 list *l;
b177fd30 8237 int j;
4409877e 8238
37ab76c9 8239 assert(c->blocking_keys != NULL);
b177fd30 8240 /* The client may wait for multiple keys, so unblock it for every key. */
37ab76c9 8241 for (j = 0; j < c->blocking_keys_num; j++) {
b177fd30 8242 /* Remove this client from the list of clients waiting for this key. */
37ab76c9 8243 de = dictFind(c->db->blocking_keys,c->blocking_keys[j]);
b177fd30 8244 assert(de != NULL);
8245 l = dictGetEntryVal(de);
8246 listDelNode(l,listSearchKey(l,c));
8247 /* If the list is empty we need to remove it to avoid wasting memory */
8248 if (listLength(l) == 0)
37ab76c9 8249 dictDelete(c->db->blocking_keys,c->blocking_keys[j]);
8250 decrRefCount(c->blocking_keys[j]);
b177fd30 8251 }
8252 /* Cleanup the client structure */
37ab76c9 8253 zfree(c->blocking_keys);
8254 c->blocking_keys = NULL;
4409877e 8255 c->flags &= (~REDIS_BLOCKED);
d5d55fc3 8256 server.blpop_blocked_clients--;
5921aa36 8257 /* We want to process data if there is some command waiting
b0d8747d 8258 * in the input buffer. Note that this is safe even if
8259 * unblockClientWaitingData() gets called from freeClient() because
8260 * freeClient() will be smart enough to call this function
8261 * *after* c->querybuf was set to NULL. */
4409877e 8262 if (c->querybuf && sdslen(c->querybuf) > 0) processInputBuffer(c);
8263}
8264
8265/* This should be called from any function PUSHing into lists.
8266 * 'c' is the "pushing client", 'key' is the key it is pushing data against,
8267 * 'ele' is the element pushed.
8268 *
8269 * If the function returns 0 there was no client waiting for a list push
8270 * against this key.
8271 *
8272 * If the function returns 1 there was a client waiting for a list push
8273 * against this key, the element was passed to this client thus it's not
8274 * needed to actually add it to the list and the caller should return asap. */
8275static int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
8276 struct dictEntry *de;
8277 redisClient *receiver;
8278 list *l;
8279 listNode *ln;
8280
37ab76c9 8281 de = dictFind(c->db->blocking_keys,key);
4409877e 8282 if (de == NULL) return 0;
8283 l = dictGetEntryVal(de);
8284 ln = listFirst(l);
8285 assert(ln != NULL);
8286 receiver = ln->value;
4409877e 8287
b177fd30 8288 addReplySds(receiver,sdsnew("*2\r\n"));
dd88747b 8289 addReplyBulk(receiver,key);
8290 addReplyBulk(receiver,ele);
b0d8747d 8291 unblockClientWaitingData(receiver);
4409877e 8292 return 1;
8293}
8294
8295/* Blocking RPOP/LPOP */
8296static void blockingPopGenericCommand(redisClient *c, int where) {
8297 robj *o;
8298 time_t timeout;
b177fd30 8299 int j;
4409877e 8300
b177fd30 8301 for (j = 1; j < c->argc-1; j++) {
8302 o = lookupKeyWrite(c->db,c->argv[j]);
8303 if (o != NULL) {
8304 if (o->type != REDIS_LIST) {
8305 addReply(c,shared.wrongtypeerr);
4409877e 8306 return;
b177fd30 8307 } else {
8308 list *list = o->ptr;
8309 if (listLength(list) != 0) {
8310 /* If the list contains elements fall back to the usual
8311 * non-blocking POP operation */
8312 robj *argv[2], **orig_argv;
8313 int orig_argc;
e0a62c7f 8314
b177fd30 8315 /* We need to alter the command arguments before to call
8316 * popGenericCommand() as the command takes a single key. */
8317 orig_argv = c->argv;
8318 orig_argc = c->argc;
8319 argv[1] = c->argv[j];
8320 c->argv = argv;
8321 c->argc = 2;
8322
8323 /* Also the return value is different, we need to output
8324 * the multi bulk reply header and the key name. The
8325 * "real" command will add the last element (the value)
8326 * for us. If this souds like an hack to you it's just
8327 * because it is... */
8328 addReplySds(c,sdsnew("*2\r\n"));
dd88747b 8329 addReplyBulk(c,argv[1]);
b177fd30 8330 popGenericCommand(c,where);
8331
8332 /* Fix the client structure with the original stuff */
8333 c->argv = orig_argv;
8334 c->argc = orig_argc;
8335 return;
8336 }
4409877e 8337 }
8338 }
8339 }
8340 /* If the list is empty or the key does not exists we must block */
b177fd30 8341 timeout = strtol(c->argv[c->argc-1]->ptr,NULL,10);
4409877e 8342 if (timeout > 0) timeout += time(NULL);
b177fd30 8343 blockForKeys(c,c->argv+1,c->argc-2,timeout);
4409877e 8344}
8345
8346static void blpopCommand(redisClient *c) {
8347 blockingPopGenericCommand(c,REDIS_HEAD);
8348}
8349
8350static void brpopCommand(redisClient *c) {
8351 blockingPopGenericCommand(c,REDIS_TAIL);
8352}
8353
ed9b544e 8354/* =============================== Replication ============================= */
8355
a4d1ba9a 8356static int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 8357 ssize_t nwritten, ret = size;
8358 time_t start = time(NULL);
8359
8360 timeout++;
8361 while(size) {
8362 if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
8363 nwritten = write(fd,ptr,size);
8364 if (nwritten == -1) return -1;
8365 ptr += nwritten;
8366 size -= nwritten;
8367 }
8368 if ((time(NULL)-start) > timeout) {
8369 errno = ETIMEDOUT;
8370 return -1;
8371 }
8372 }
8373 return ret;
8374}
8375
a4d1ba9a 8376static int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 8377 ssize_t nread, totread = 0;
8378 time_t start = time(NULL);
8379
8380 timeout++;
8381 while(size) {
8382 if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
8383 nread = read(fd,ptr,size);
8384 if (nread == -1) return -1;
8385 ptr += nread;
8386 size -= nread;
8387 totread += nread;
8388 }
8389 if ((time(NULL)-start) > timeout) {
8390 errno = ETIMEDOUT;
8391 return -1;
8392 }
8393 }
8394 return totread;
8395}
8396
8397static int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
8398 ssize_t nread = 0;
8399
8400 size--;
8401 while(size) {
8402 char c;
8403
8404 if (syncRead(fd,&c,1,timeout) == -1) return -1;
8405 if (c == '\n') {
8406 *ptr = '\0';
8407 if (nread && *(ptr-1) == '\r') *(ptr-1) = '\0';
8408 return nread;
8409 } else {
8410 *ptr++ = c;
8411 *ptr = '\0';
8412 nread++;
8413 }
8414 }
8415 return nread;
8416}
8417
8418static void syncCommand(redisClient *c) {
40d224a9 8419 /* ignore SYNC if aleady slave or in monitor mode */
8420 if (c->flags & REDIS_SLAVE) return;
8421
8422 /* SYNC can't be issued when the server has pending data to send to
8423 * the client about already issued commands. We need a fresh reply
8424 * buffer registering the differences between the BGSAVE and the current
8425 * dataset, so that we can copy to other slaves if needed. */
8426 if (listLength(c->reply) != 0) {
8427 addReplySds(c,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
8428 return;
8429 }
8430
8431 redisLog(REDIS_NOTICE,"Slave ask for synchronization");
8432 /* Here we need to check if there is a background saving operation
8433 * in progress, or if it is required to start one */
9d65a1bb 8434 if (server.bgsavechildpid != -1) {
40d224a9 8435 /* Ok a background save is in progress. Let's check if it is a good
8436 * one for replication, i.e. if there is another slave that is
8437 * registering differences since the server forked to save */
8438 redisClient *slave;
8439 listNode *ln;
c7df85a4 8440 listIter li;
40d224a9 8441
c7df85a4 8442 listRewind(server.slaves,&li);
8443 while((ln = listNext(&li))) {
40d224a9 8444 slave = ln->value;
8445 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break;
40d224a9 8446 }
8447 if (ln) {
8448 /* Perfect, the server is already registering differences for
8449 * another slave. Set the right state, and copy the buffer. */
8450 listRelease(c->reply);
8451 c->reply = listDup(slave->reply);
40d224a9 8452 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
8453 redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC");
8454 } else {
8455 /* No way, we need to wait for the next BGSAVE in order to
8456 * register differences */
8457 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
8458 redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
8459 }
8460 } else {
8461 /* Ok we don't have a BGSAVE in progress, let's start one */
8462 redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
8463 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
8464 redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE");
8465 addReplySds(c,sdsnew("-ERR Unalbe to perform background save\r\n"));
8466 return;
8467 }
8468 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
8469 }
6208b3a7 8470 c->repldbfd = -1;
40d224a9 8471 c->flags |= REDIS_SLAVE;
8472 c->slaveseldb = 0;
6b47e12e 8473 listAddNodeTail(server.slaves,c);
40d224a9 8474 return;
8475}
8476
6208b3a7 8477static void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
8478 redisClient *slave = privdata;
8479 REDIS_NOTUSED(el);
8480 REDIS_NOTUSED(mask);
8481 char buf[REDIS_IOBUF_LEN];
8482 ssize_t nwritten, buflen;
8483
8484 if (slave->repldboff == 0) {
8485 /* Write the bulk write count before to transfer the DB. In theory here
8486 * we don't know how much room there is in the output buffer of the
8487 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
8488 * operations) will never be smaller than the few bytes we need. */
8489 sds bulkcount;
8490
8491 bulkcount = sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
8492 slave->repldbsize);
8493 if (write(fd,bulkcount,sdslen(bulkcount)) != (signed)sdslen(bulkcount))
8494 {
8495 sdsfree(bulkcount);
8496 freeClient(slave);
8497 return;
8498 }
8499 sdsfree(bulkcount);
8500 }
8501 lseek(slave->repldbfd,slave->repldboff,SEEK_SET);
8502 buflen = read(slave->repldbfd,buf,REDIS_IOBUF_LEN);
8503 if (buflen <= 0) {
8504 redisLog(REDIS_WARNING,"Read error sending DB to slave: %s",
8505 (buflen == 0) ? "premature EOF" : strerror(errno));
8506 freeClient(slave);
8507 return;
8508 }
8509 if ((nwritten = write(fd,buf,buflen)) == -1) {
f870935d 8510 redisLog(REDIS_VERBOSE,"Write error sending DB to slave: %s",
6208b3a7 8511 strerror(errno));
8512 freeClient(slave);
8513 return;
8514 }
8515 slave->repldboff += nwritten;
8516 if (slave->repldboff == slave->repldbsize) {
8517 close(slave->repldbfd);
8518 slave->repldbfd = -1;
8519 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
8520 slave->replstate = REDIS_REPL_ONLINE;
8521 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
266373b2 8522 sendReplyToClient, slave) == AE_ERR) {
6208b3a7 8523 freeClient(slave);
8524 return;
8525 }
8526 addReplySds(slave,sdsempty());
8527 redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
8528 }
8529}
ed9b544e 8530
a3b21203 8531/* This function is called at the end of every backgrond saving.
8532 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
8533 * otherwise REDIS_ERR is passed to the function.
8534 *
8535 * The goal of this function is to handle slaves waiting for a successful
8536 * background saving in order to perform non-blocking synchronization. */
8537static void updateSlavesWaitingBgsave(int bgsaveerr) {
6208b3a7 8538 listNode *ln;
8539 int startbgsave = 0;
c7df85a4 8540 listIter li;
ed9b544e 8541
c7df85a4 8542 listRewind(server.slaves,&li);
8543 while((ln = listNext(&li))) {
6208b3a7 8544 redisClient *slave = ln->value;
ed9b544e 8545
6208b3a7 8546 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) {
8547 startbgsave = 1;
8548 slave->replstate = REDIS_REPL_WAIT_BGSAVE_END;
8549 } else if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
dde65f3f 8550 struct redis_stat buf;
e0a62c7f 8551
6208b3a7 8552 if (bgsaveerr != REDIS_OK) {
8553 freeClient(slave);
8554 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE child returned an error");
8555 continue;
8556 }
8557 if ((slave->repldbfd = open(server.dbfilename,O_RDONLY)) == -1 ||
dde65f3f 8558 redis_fstat(slave->repldbfd,&buf) == -1) {
6208b3a7 8559 freeClient(slave);
8560 redisLog(REDIS_WARNING,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno));
8561 continue;
8562 }
8563 slave->repldboff = 0;
8564 slave->repldbsize = buf.st_size;
8565 slave->replstate = REDIS_REPL_SEND_BULK;
8566 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
266373b2 8567 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE, sendBulkToSlave, slave) == AE_ERR) {
6208b3a7 8568 freeClient(slave);
8569 continue;
8570 }
8571 }
ed9b544e 8572 }
6208b3a7 8573 if (startbgsave) {
8574 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
c7df85a4 8575 listIter li;
8576
8577 listRewind(server.slaves,&li);
6208b3a7 8578 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE failed");
c7df85a4 8579 while((ln = listNext(&li))) {
6208b3a7 8580 redisClient *slave = ln->value;
ed9b544e 8581
6208b3a7 8582 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START)
8583 freeClient(slave);
8584 }
8585 }
8586 }
ed9b544e 8587}
8588
8589static int syncWithMaster(void) {
d0ccebcf 8590 char buf[1024], tmpfile[256], authcmd[1024];
18e61fa2 8591 long dumpsize;
ed9b544e 8592 int fd = anetTcpConnect(NULL,server.masterhost,server.masterport);
8c5abee8 8593 int dfd, maxtries = 5;
ed9b544e 8594
8595 if (fd == -1) {
8596 redisLog(REDIS_WARNING,"Unable to connect to MASTER: %s",
8597 strerror(errno));
8598 return REDIS_ERR;
8599 }
d0ccebcf 8600
8601 /* AUTH with the master if required. */
8602 if(server.masterauth) {
8603 snprintf(authcmd, 1024, "AUTH %s\r\n", server.masterauth);
8604 if (syncWrite(fd, authcmd, strlen(server.masterauth)+7, 5) == -1) {
8605 close(fd);
8606 redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",
8607 strerror(errno));
8608 return REDIS_ERR;
8609 }
8610 /* Read the AUTH result. */
8611 if (syncReadLine(fd,buf,1024,3600) == -1) {
8612 close(fd);
8613 redisLog(REDIS_WARNING,"I/O error reading auth result from MASTER: %s",
8614 strerror(errno));
8615 return REDIS_ERR;
8616 }
8617 if (buf[0] != '+') {
8618 close(fd);
8619 redisLog(REDIS_WARNING,"Cannot AUTH to MASTER, is the masterauth password correct?");
8620 return REDIS_ERR;
8621 }
8622 }
8623
ed9b544e 8624 /* Issue the SYNC command */
8625 if (syncWrite(fd,"SYNC \r\n",7,5) == -1) {
8626 close(fd);
8627 redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
8628 strerror(errno));
8629 return REDIS_ERR;
8630 }
8631 /* Read the bulk write count */
8c4d91fc 8632 if (syncReadLine(fd,buf,1024,3600) == -1) {
ed9b544e 8633 close(fd);
8634 redisLog(REDIS_WARNING,"I/O error reading bulk count from MASTER: %s",
8635 strerror(errno));
8636 return REDIS_ERR;
8637 }
4aa701c1 8638 if (buf[0] != '$') {
8639 close(fd);
8640 redisLog(REDIS_WARNING,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
8641 return REDIS_ERR;
8642 }
18e61fa2 8643 dumpsize = strtol(buf+1,NULL,10);
8644 redisLog(REDIS_NOTICE,"Receiving %ld bytes data dump from MASTER",dumpsize);
ed9b544e 8645 /* Read the bulk write data on a temp file */
8c5abee8 8646 while(maxtries--) {
8647 snprintf(tmpfile,256,
8648 "temp-%d.%ld.rdb",(int)time(NULL),(long int)getpid());
8649 dfd = open(tmpfile,O_CREAT|O_WRONLY|O_EXCL,0644);
8650 if (dfd != -1) break;
5de9ad7c 8651 sleep(1);
8c5abee8 8652 }
ed9b544e 8653 if (dfd == -1) {
8654 close(fd);
8655 redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
8656 return REDIS_ERR;
8657 }
8658 while(dumpsize) {
8659 int nread, nwritten;
8660
8661 nread = read(fd,buf,(dumpsize < 1024)?dumpsize:1024);
8662 if (nread == -1) {
8663 redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
8664 strerror(errno));
8665 close(fd);
8666 close(dfd);
8667 return REDIS_ERR;
8668 }
8669 nwritten = write(dfd,buf,nread);
8670 if (nwritten == -1) {
8671 redisLog(REDIS_WARNING,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
8672 close(fd);
8673 close(dfd);
8674 return REDIS_ERR;
8675 }
8676 dumpsize -= nread;
8677 }
8678 close(dfd);
8679 if (rename(tmpfile,server.dbfilename) == -1) {
8680 redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
8681 unlink(tmpfile);
8682 close(fd);
8683 return REDIS_ERR;
8684 }
8685 emptyDb();
f78fd11b 8686 if (rdbLoad(server.dbfilename) != REDIS_OK) {
ed9b544e 8687 redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
8688 close(fd);
8689 return REDIS_ERR;
8690 }
8691 server.master = createClient(fd);
8692 server.master->flags |= REDIS_MASTER;
179b3952 8693 server.master->authenticated = 1;
ed9b544e 8694 server.replstate = REDIS_REPL_CONNECTED;
8695 return REDIS_OK;
8696}
8697
321b0e13 8698static void slaveofCommand(redisClient *c) {
8699 if (!strcasecmp(c->argv[1]->ptr,"no") &&
8700 !strcasecmp(c->argv[2]->ptr,"one")) {
8701 if (server.masterhost) {
8702 sdsfree(server.masterhost);
8703 server.masterhost = NULL;
8704 if (server.master) freeClient(server.master);
8705 server.replstate = REDIS_REPL_NONE;
8706 redisLog(REDIS_NOTICE,"MASTER MODE enabled (user request)");
8707 }
8708 } else {
8709 sdsfree(server.masterhost);
8710 server.masterhost = sdsdup(c->argv[1]->ptr);
8711 server.masterport = atoi(c->argv[2]->ptr);
8712 if (server.master) freeClient(server.master);
8713 server.replstate = REDIS_REPL_CONNECT;
8714 redisLog(REDIS_NOTICE,"SLAVE OF %s:%d enabled (user request)",
8715 server.masterhost, server.masterport);
8716 }
8717 addReply(c,shared.ok);
8718}
8719
3fd78bcd 8720/* ============================ Maxmemory directive ======================== */
8721
a5819310 8722/* Try to free one object form the pre-allocated objects free list.
8723 * This is useful under low mem conditions as by default we take 1 million
8724 * free objects allocated. On success REDIS_OK is returned, otherwise
8725 * REDIS_ERR. */
8726static int tryFreeOneObjectFromFreelist(void) {
f870935d 8727 robj *o;
8728
a5819310 8729 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
8730 if (listLength(server.objfreelist)) {
8731 listNode *head = listFirst(server.objfreelist);
8732 o = listNodeValue(head);
8733 listDelNode(server.objfreelist,head);
8734 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
8735 zfree(o);
8736 return REDIS_OK;
8737 } else {
8738 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
8739 return REDIS_ERR;
8740 }
f870935d 8741}
8742
3fd78bcd 8743/* This function gets called when 'maxmemory' is set on the config file to limit
8744 * the max memory used by the server, and we are out of memory.
8745 * This function will try to, in order:
8746 *
8747 * - Free objects from the free list
8748 * - Try to remove keys with an EXPIRE set
8749 *
8750 * It is not possible to free enough memory to reach used-memory < maxmemory
8751 * the server will start refusing commands that will enlarge even more the
8752 * memory usage.
8753 */
8754static void freeMemoryIfNeeded(void) {
8755 while (server.maxmemory && zmalloc_used_memory() > server.maxmemory) {
a5819310 8756 int j, k, freed = 0;
8757
8758 if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
8759 for (j = 0; j < server.dbnum; j++) {
8760 int minttl = -1;
8761 robj *minkey = NULL;
8762 struct dictEntry *de;
8763
8764 if (dictSize(server.db[j].expires)) {
8765 freed = 1;
8766 /* From a sample of three keys drop the one nearest to
8767 * the natural expire */
8768 for (k = 0; k < 3; k++) {
8769 time_t t;
8770
8771 de = dictGetRandomKey(server.db[j].expires);
8772 t = (time_t) dictGetEntryVal(de);
8773 if (minttl == -1 || t < minttl) {
8774 minkey = dictGetEntryKey(de);
8775 minttl = t;
3fd78bcd 8776 }
3fd78bcd 8777 }
09241813 8778 dbDelete(server.db+j,minkey);
3fd78bcd 8779 }
3fd78bcd 8780 }
a5819310 8781 if (!freed) return; /* nothing to free... */
3fd78bcd 8782 }
8783}
8784
f80dff62 8785/* ============================== Append Only file ========================== */
8786
560db612 8787/* Called when the user switches from "appendonly yes" to "appendonly no"
8788 * at runtime using the CONFIG command. */
8789static void stopAppendOnly(void) {
8790 flushAppendOnlyFile();
8791 aof_fsync(server.appendfd);
8792 close(server.appendfd);
8793
8794 server.appendfd = -1;
8795 server.appendseldb = -1;
8796 server.appendonly = 0;
8797 /* rewrite operation in progress? kill it, wait child exit */
8798 if (server.bgsavechildpid != -1) {
8799 int statloc;
8800
8801 if (kill(server.bgsavechildpid,SIGKILL) != -1)
8802 wait3(&statloc,0,NULL);
8803 /* reset the buffer accumulating changes while the child saves */
8804 sdsfree(server.bgrewritebuf);
8805 server.bgrewritebuf = sdsempty();
8806 server.bgsavechildpid = -1;
8807 }
8808}
8809
8810/* Called when the user switches from "appendonly no" to "appendonly yes"
8811 * at runtime using the CONFIG command. */
8812static int startAppendOnly(void) {
8813 server.appendonly = 1;
8814 server.lastfsync = time(NULL);
8815 server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
8816 if (server.appendfd == -1) {
8817 redisLog(REDIS_WARNING,"Used tried to switch on AOF via CONFIG, but I can't open the AOF file: %s",strerror(errno));
8818 return REDIS_ERR;
8819 }
8820 if (rewriteAppendOnlyFileBackground() == REDIS_ERR) {
8821 server.appendonly = 0;
8822 close(server.appendfd);
8823 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));
8824 return REDIS_ERR;
8825 }
8826 return REDIS_OK;
8827}
8828
28ed1f33 8829/* Write the append only file buffer on disk.
8830 *
8831 * Since we are required to write the AOF before replying to the client,
8832 * and the only way the client socket can get a write is entering when the
8833 * the event loop, we accumulate all the AOF writes in a memory
8834 * buffer and write it on disk using this function just before entering
8835 * the event loop again. */
8836static void flushAppendOnlyFile(void) {
8837 time_t now;
8838 ssize_t nwritten;
8839
8840 if (sdslen(server.aofbuf) == 0) return;
8841
8842 /* We want to perform a single write. This should be guaranteed atomic
8843 * at least if the filesystem we are writing is a real physical one.
8844 * While this will save us against the server being killed I don't think
8845 * there is much to do about the whole server stopping for power problems
8846 * or alike */
8847 nwritten = write(server.appendfd,server.aofbuf,sdslen(server.aofbuf));
8848 if (nwritten != (signed)sdslen(server.aofbuf)) {
8849 /* Ooops, we are in troubles. The best thing to do for now is
8850 * aborting instead of giving the illusion that everything is
8851 * working as expected. */
8852 if (nwritten == -1) {
8853 redisLog(REDIS_WARNING,"Exiting on error writing to the append-only file: %s",strerror(errno));
8854 } else {
8855 redisLog(REDIS_WARNING,"Exiting on short write while writing to the append-only file: %s",strerror(errno));
8856 }
8857 exit(1);
8858 }
8859 sdsfree(server.aofbuf);
8860 server.aofbuf = sdsempty();
8861
38db9171 8862 /* Don't Fsync if no-appendfsync-on-rewrite is set to yes and we have
8863 * childs performing heavy I/O on disk. */
8864 if (server.no_appendfsync_on_rewrite &&
8865 (server.bgrewritechildpid != -1 || server.bgsavechildpid != -1))
8866 return;
28ed1f33 8867 /* Fsync if needed */
8868 now = time(NULL);
8869 if (server.appendfsync == APPENDFSYNC_ALWAYS ||
8870 (server.appendfsync == APPENDFSYNC_EVERYSEC &&
8871 now-server.lastfsync > 1))
8872 {
8873 /* aof_fsync is defined as fdatasync() for Linux in order to avoid
8874 * flushing metadata. */
8875 aof_fsync(server.appendfd); /* Let's try to get this data on the disk */
8876 server.lastfsync = now;
8877 }
8878}
8879
9376e434
PN
8880static sds catAppendOnlyGenericCommand(sds buf, int argc, robj **argv) {
8881 int j;
8882 buf = sdscatprintf(buf,"*%d\r\n",argc);
8883 for (j = 0; j < argc; j++) {
8884 robj *o = getDecodedObject(argv[j]);
8885 buf = sdscatprintf(buf,"$%lu\r\n",(unsigned long)sdslen(o->ptr));
8886 buf = sdscatlen(buf,o->ptr,sdslen(o->ptr));
8887 buf = sdscatlen(buf,"\r\n",2);
8888 decrRefCount(o);
8889 }
8890 return buf;
8891}
8892
8893static sds catAppendOnlyExpireAtCommand(sds buf, robj *key, robj *seconds) {
8894 int argc = 3;
8895 long when;
8896 robj *argv[3];
8897
8898 /* Make sure we can use strtol */
8899 seconds = getDecodedObject(seconds);
8900 when = time(NULL)+strtol(seconds->ptr,NULL,10);
8901 decrRefCount(seconds);
8902
8903 argv[0] = createStringObject("EXPIREAT",8);
8904 argv[1] = key;
8905 argv[2] = createObject(REDIS_STRING,
8906 sdscatprintf(sdsempty(),"%ld",when));
8907 buf = catAppendOnlyGenericCommand(buf, argc, argv);
8908 decrRefCount(argv[0]);
8909 decrRefCount(argv[2]);
8910 return buf;
8911}
8912
f80dff62 8913static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {
8914 sds buf = sdsempty();
f80dff62 8915 robj *tmpargv[3];
8916
8917 /* The DB this command was targetting is not the same as the last command
8918 * we appendend. To issue a SELECT command is needed. */
8919 if (dictid != server.appendseldb) {
8920 char seldb[64];
8921
8922 snprintf(seldb,sizeof(seldb),"%d",dictid);
682ac724 8923 buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
83c6a618 8924 (unsigned long)strlen(seldb),seldb);
f80dff62 8925 server.appendseldb = dictid;
8926 }
8927
f80dff62 8928 if (cmd->proc == expireCommand) {
9376e434
PN
8929 /* Translate EXPIRE into EXPIREAT */
8930 buf = catAppendOnlyExpireAtCommand(buf,argv[1],argv[2]);
8931 } else if (cmd->proc == setexCommand) {
8932 /* Translate SETEX to SET and EXPIREAT */
8933 tmpargv[0] = createStringObject("SET",3);
f80dff62 8934 tmpargv[1] = argv[1];
9376e434
PN
8935 tmpargv[2] = argv[3];
8936 buf = catAppendOnlyGenericCommand(buf,3,tmpargv);
8937 decrRefCount(tmpargv[0]);
8938 buf = catAppendOnlyExpireAtCommand(buf,argv[1],argv[2]);
8939 } else {
8940 buf = catAppendOnlyGenericCommand(buf,argc,argv);
f80dff62 8941 }
8942
28ed1f33 8943 /* Append to the AOF buffer. This will be flushed on disk just before
8944 * of re-entering the event loop, so before the client will get a
8945 * positive reply about the operation performed. */
8946 server.aofbuf = sdscatlen(server.aofbuf,buf,sdslen(buf));
8947
85a83172 8948 /* If a background append only file rewriting is in progress we want to
8949 * accumulate the differences between the child DB and the current one
8950 * in a buffer, so that when the child process will do its work we
8951 * can append the differences to the new append only file. */
8952 if (server.bgrewritechildpid != -1)
8953 server.bgrewritebuf = sdscatlen(server.bgrewritebuf,buf,sdslen(buf));
8954
8955 sdsfree(buf);
f80dff62 8956}
8957
8958/* In Redis commands are always executed in the context of a client, so in
8959 * order to load the append only file we need to create a fake client. */
8960static struct redisClient *createFakeClient(void) {
8961 struct redisClient *c = zmalloc(sizeof(*c));
8962
8963 selectDb(c,0);
8964 c->fd = -1;
8965 c->querybuf = sdsempty();
8966 c->argc = 0;
8967 c->argv = NULL;
8968 c->flags = 0;
9387d17d 8969 /* We set the fake client as a slave waiting for the synchronization
8970 * so that Redis will not try to send replies to this client. */
8971 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
f80dff62 8972 c->reply = listCreate();
8973 listSetFreeMethod(c->reply,decrRefCount);
8974 listSetDupMethod(c->reply,dupClientReplyValue);
4132ad8d 8975 initClientMultiState(c);
f80dff62 8976 return c;
8977}
8978
8979static void freeFakeClient(struct redisClient *c) {
8980 sdsfree(c->querybuf);
8981 listRelease(c->reply);
4132ad8d 8982 freeClientMultiState(c);
f80dff62 8983 zfree(c);
8984}
8985
8986/* Replay the append log file. On error REDIS_OK is returned. On non fatal
8987 * error (the append only file is zero-length) REDIS_ERR is returned. On
8988 * fatal error an error message is logged and the program exists. */
8989int loadAppendOnlyFile(char *filename) {
8990 struct redisClient *fakeClient;
8991 FILE *fp = fopen(filename,"r");
8992 struct redis_stat sb;
4132ad8d 8993 int appendonly = server.appendonly;
f80dff62 8994
8995 if (redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0)
8996 return REDIS_ERR;
8997
8998 if (fp == NULL) {
8999 redisLog(REDIS_WARNING,"Fatal error: can't open the append log file for reading: %s",strerror(errno));
9000 exit(1);
9001 }
9002
4132ad8d
PN
9003 /* Temporarily disable AOF, to prevent EXEC from feeding a MULTI
9004 * to the same file we're about to read. */
9005 server.appendonly = 0;
9006
f80dff62 9007 fakeClient = createFakeClient();
9008 while(1) {
9009 int argc, j;
9010 unsigned long len;
9011 robj **argv;
9012 char buf[128];
9013 sds argsds;
9014 struct redisCommand *cmd;
a89b7013 9015 int force_swapout;
f80dff62 9016
9017 if (fgets(buf,sizeof(buf),fp) == NULL) {
9018 if (feof(fp))
9019 break;
9020 else
9021 goto readerr;
9022 }
9023 if (buf[0] != '*') goto fmterr;
9024 argc = atoi(buf+1);
9025 argv = zmalloc(sizeof(robj*)*argc);
9026 for (j = 0; j < argc; j++) {
9027 if (fgets(buf,sizeof(buf),fp) == NULL) goto readerr;
9028 if (buf[0] != '$') goto fmterr;
9029 len = strtol(buf+1,NULL,10);
9030 argsds = sdsnewlen(NULL,len);
0f151ef1 9031 if (len && fread(argsds,len,1,fp) == 0) goto fmterr;
f80dff62 9032 argv[j] = createObject(REDIS_STRING,argsds);
9033 if (fread(buf,2,1,fp) == 0) goto fmterr; /* discard CRLF */
9034 }
9035
9036 /* Command lookup */
9037 cmd = lookupCommand(argv[0]->ptr);
9038 if (!cmd) {
9039 redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", argv[0]->ptr);
9040 exit(1);
9041 }
bdcb92f2 9042 /* Try object encoding */
f80dff62 9043 if (cmd->flags & REDIS_CMD_BULK)
05df7621 9044 argv[argc-1] = tryObjectEncoding(argv[argc-1]);
f80dff62 9045 /* Run the command in the context of a fake client */
9046 fakeClient->argc = argc;
9047 fakeClient->argv = argv;
9048 cmd->proc(fakeClient);
9049 /* Discard the reply objects list from the fake client */
9050 while(listLength(fakeClient->reply))
9051 listDelNode(fakeClient->reply,listFirst(fakeClient->reply));
9052 /* Clean up, ready for the next command */
9053 for (j = 0; j < argc; j++) decrRefCount(argv[j]);
9054 zfree(argv);
b492cf00 9055 /* Handle swapping while loading big datasets when VM is on */
a89b7013 9056 force_swapout = 0;
9057 if ((zmalloc_used_memory() - server.vm_max_memory) > 1024*1024*32)
9058 force_swapout = 1;
9059
9060 if (server.vm_enabled && force_swapout) {
b492cf00 9061 while (zmalloc_used_memory() > server.vm_max_memory) {
a69a0c9c 9062 if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
b492cf00 9063 }
9064 }
f80dff62 9065 }
4132ad8d
PN
9066
9067 /* This point can only be reached when EOF is reached without errors.
9068 * If the client is in the middle of a MULTI/EXEC, log error and quit. */
9069 if (fakeClient->flags & REDIS_MULTI) goto readerr;
9070
f80dff62 9071 fclose(fp);
9072 freeFakeClient(fakeClient);
4132ad8d 9073 server.appendonly = appendonly;
f80dff62 9074 return REDIS_OK;
9075
9076readerr:
9077 if (feof(fp)) {
9078 redisLog(REDIS_WARNING,"Unexpected end of file reading the append only file");
9079 } else {
9080 redisLog(REDIS_WARNING,"Unrecoverable error reading the append only file: %s", strerror(errno));
9081 }
9082 exit(1);
9083fmterr:
9084 redisLog(REDIS_WARNING,"Bad file format reading the append only file");
9085 exit(1);
9086}
9087
9c8e3cee 9088/* Write binary-safe string into a file in the bulkformat
9089 * $<count>\r\n<payload>\r\n */
9090static int fwriteBulkString(FILE *fp, char *s, unsigned long len) {
9eaef89f
PN
9091 char cbuf[128];
9092 int clen;
9093 cbuf[0] = '$';
9094 clen = 1+ll2string(cbuf+1,sizeof(cbuf)-1,len);
9095 cbuf[clen++] = '\r';
9096 cbuf[clen++] = '\n';
9097 if (fwrite(cbuf,clen,1,fp) == 0) return 0;
9098 if (len > 0 && fwrite(s,len,1,fp) == 0) return 0;
9c8e3cee 9099 if (fwrite("\r\n",2,1,fp) == 0) return 0;
9100 return 1;
9101}
9102
9d65a1bb 9103/* Write a double value in bulk format $<count>\r\n<payload>\r\n */
9104static int fwriteBulkDouble(FILE *fp, double d) {
9105 char buf[128], dbuf[128];
9106
9107 snprintf(dbuf,sizeof(dbuf),"%.17g\r\n",d);
9108 snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(dbuf)-2);
9109 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
9110 if (fwrite(dbuf,strlen(dbuf),1,fp) == 0) return 0;
9111 return 1;
9112}
9113
9114/* Write a long value in bulk format $<count>\r\n<payload>\r\n */
9eaef89f
PN
9115static int fwriteBulkLongLong(FILE *fp, long long l) {
9116 char bbuf[128], lbuf[128];
9117 unsigned int blen, llen;
9118 llen = ll2string(lbuf,32,l);
9119 blen = snprintf(bbuf,sizeof(bbuf),"$%u\r\n%s\r\n",llen,lbuf);
9120 if (fwrite(bbuf,blen,1,fp) == 0) return 0;
9d65a1bb 9121 return 1;
9122}
9123
9eaef89f
PN
9124/* Delegate writing an object to writing a bulk string or bulk long long. */
9125static int fwriteBulkObject(FILE *fp, robj *obj) {
9126 /* Avoid using getDecodedObject to help copy-on-write (we are often
9127 * in a child process when this function is called). */
9128 if (obj->encoding == REDIS_ENCODING_INT) {
9129 return fwriteBulkLongLong(fp,(long)obj->ptr);
9130 } else if (obj->encoding == REDIS_ENCODING_RAW) {
9131 return fwriteBulkString(fp,obj->ptr,sdslen(obj->ptr));
9132 } else {
9133 redisPanic("Unknown string encoding");
9134 }
9135}
9136
9d65a1bb 9137/* Write a sequence of commands able to fully rebuild the dataset into
9138 * "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
9139static int rewriteAppendOnlyFile(char *filename) {
9140 dictIterator *di = NULL;
9141 dictEntry *de;
9142 FILE *fp;
9143 char tmpfile[256];
9144 int j;
9145 time_t now = time(NULL);
9146
9147 /* Note that we have to use a different temp name here compared to the
9148 * one used by rewriteAppendOnlyFileBackground() function. */
9149 snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid());
9150 fp = fopen(tmpfile,"w");
9151 if (!fp) {
9152 redisLog(REDIS_WARNING, "Failed rewriting the append only file: %s", strerror(errno));
9153 return REDIS_ERR;
9154 }
9155 for (j = 0; j < server.dbnum; j++) {
9156 char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n";
9157 redisDb *db = server.db+j;
9158 dict *d = db->dict;
9159 if (dictSize(d) == 0) continue;
9160 di = dictGetIterator(d);
9161 if (!di) {
9162 fclose(fp);
9163 return REDIS_ERR;
9164 }
9165
9166 /* SELECT the new DB */
9167 if (fwrite(selectcmd,sizeof(selectcmd)-1,1,fp) == 0) goto werr;
9eaef89f 9168 if (fwriteBulkLongLong(fp,j) == 0) goto werr;
9d65a1bb 9169
9170 /* Iterate this DB writing every entry */
9171 while((de = dictNext(di)) != NULL) {
09241813 9172 sds keystr = dictGetEntryKey(de);
9173 robj key, *o;
e7546c63 9174 time_t expiretime;
9175 int swapped;
9176
09241813 9177 keystr = dictGetEntryKey(de);
560db612 9178 o = dictGetEntryVal(de);
09241813 9179 initStaticStringObject(key,keystr);
b9bc0eef 9180 /* If the value for this key is swapped, load a preview in memory.
9181 * We use a "swapped" flag to remember if we need to free the
9182 * value object instead to just increment the ref count anyway
9183 * in order to avoid copy-on-write of pages if we are forked() */
560db612 9184 if (!server.vm_enabled || o->storage == REDIS_VM_MEMORY ||
9185 o->storage == REDIS_VM_SWAPPING) {
e7546c63 9186 swapped = 0;
9187 } else {
560db612 9188 o = vmPreviewObject(o);
e7546c63 9189 swapped = 1;
9190 }
09241813 9191 expiretime = getExpire(db,&key);
9d65a1bb 9192
9193 /* Save the key and associated value */
9d65a1bb 9194 if (o->type == REDIS_STRING) {
9195 /* Emit a SET command */
9196 char cmd[]="*3\r\n$3\r\nSET\r\n";
9197 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
9198 /* Key and value */
09241813 9199 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9200 if (fwriteBulkObject(fp,o) == 0) goto werr;
9d65a1bb 9201 } else if (o->type == REDIS_LIST) {
9202 /* Emit the RPUSHes needed to rebuild the list */
6ddc908a
PN
9203 char cmd[]="*3\r\n$5\r\nRPUSH\r\n";
9204 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
9205 unsigned char *zl = o->ptr;
9206 unsigned char *p = ziplistIndex(zl,0);
9207 unsigned char *vstr;
9208 unsigned int vlen;
9209 long long vlong;
9210
9211 while(ziplistGet(p,&vstr,&vlen,&vlong)) {
9212 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
846d8b3e 9213 if (fwriteBulkObject(fp,&key) == 0) goto werr;
6ddc908a
PN
9214 if (vstr) {
9215 if (fwriteBulkString(fp,(char*)vstr,vlen) == 0)
9216 goto werr;
9217 } else {
9218 if (fwriteBulkLongLong(fp,vlong) == 0)
9219 goto werr;
9220 }
9221 p = ziplistNext(zl,p);
9222 }
9223 } else if (o->encoding == REDIS_ENCODING_LIST) {
9224 list *list = o->ptr;
9225 listNode *ln;
9226 listIter li;
9227
9228 listRewind(list,&li);
9229 while((ln = listNext(&li))) {
9230 robj *eleobj = listNodeValue(ln);
9231
9232 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
846d8b3e 9233 if (fwriteBulkObject(fp,&key) == 0) goto werr;
6ddc908a
PN
9234 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
9235 }
9236 } else {
9237 redisPanic("Unknown list encoding");
9d65a1bb 9238 }
9239 } else if (o->type == REDIS_SET) {
9240 /* Emit the SADDs needed to rebuild the set */
9241 dict *set = o->ptr;
9242 dictIterator *di = dictGetIterator(set);
9243 dictEntry *de;
9244
9245 while((de = dictNext(di)) != NULL) {
9246 char cmd[]="*3\r\n$4\r\nSADD\r\n";
9247 robj *eleobj = dictGetEntryKey(de);
9248
9249 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9250 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9251 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
9d65a1bb 9252 }
9253 dictReleaseIterator(di);
9254 } else if (o->type == REDIS_ZSET) {
9255 /* Emit the ZADDs needed to rebuild the sorted set */
9256 zset *zs = o->ptr;
9257 dictIterator *di = dictGetIterator(zs->dict);
9258 dictEntry *de;
9259
9260 while((de = dictNext(di)) != NULL) {
9261 char cmd[]="*4\r\n$4\r\nZADD\r\n";
9262 robj *eleobj = dictGetEntryKey(de);
9263 double *score = dictGetEntryVal(de);
9264
9265 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9266 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9d65a1bb 9267 if (fwriteBulkDouble(fp,*score) == 0) goto werr;
9c8e3cee 9268 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
9d65a1bb 9269 }
9270 dictReleaseIterator(di);
9c8e3cee 9271 } else if (o->type == REDIS_HASH) {
9272 char cmd[]="*4\r\n$4\r\nHSET\r\n";
9273
9274 /* Emit the HSETs needed to rebuild the hash */
9275 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
9276 unsigned char *p = zipmapRewind(o->ptr);
9277 unsigned char *field, *val;
9278 unsigned int flen, vlen;
9279
9280 while((p = zipmapNext(p,&field,&flen,&val,&vlen)) != NULL) {
9281 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9282 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9283 if (fwriteBulkString(fp,(char*)field,flen) == -1)
9284 return -1;
9285 if (fwriteBulkString(fp,(char*)val,vlen) == -1)
9286 return -1;
9287 }
9288 } else {
9289 dictIterator *di = dictGetIterator(o->ptr);
9290 dictEntry *de;
9291
9292 while((de = dictNext(di)) != NULL) {
9293 robj *field = dictGetEntryKey(de);
9294 robj *val = dictGetEntryVal(de);
9295
9296 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9297 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9298 if (fwriteBulkObject(fp,field) == -1) return -1;
9299 if (fwriteBulkObject(fp,val) == -1) return -1;
9300 }
9301 dictReleaseIterator(di);
9302 }
9d65a1bb 9303 } else {
f83c6cb5 9304 redisPanic("Unknown object type");
9d65a1bb 9305 }
9306 /* Save the expire time */
9307 if (expiretime != -1) {
e96e4fbf 9308 char cmd[]="*3\r\n$8\r\nEXPIREAT\r\n";
9d65a1bb 9309 /* If this key is already expired skip it */
9310 if (expiretime < now) continue;
9311 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9312 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9eaef89f 9313 if (fwriteBulkLongLong(fp,expiretime) == 0) goto werr;
9d65a1bb 9314 }
b9bc0eef 9315 if (swapped) decrRefCount(o);
9d65a1bb 9316 }
9317 dictReleaseIterator(di);
9318 }
9319
9320 /* Make sure data will not remain on the OS's output buffers */
9321 fflush(fp);
b0bd87f6 9322 aof_fsync(fileno(fp));
9d65a1bb 9323 fclose(fp);
e0a62c7f 9324
9d65a1bb 9325 /* Use RENAME to make sure the DB file is changed atomically only
9326 * if the generate DB file is ok. */
9327 if (rename(tmpfile,filename) == -1) {
9328 redisLog(REDIS_WARNING,"Error moving temp append only file on the final destination: %s", strerror(errno));
9329 unlink(tmpfile);
9330 return REDIS_ERR;
9331 }
9332 redisLog(REDIS_NOTICE,"SYNC append only file rewrite performed");
9333 return REDIS_OK;
9334
9335werr:
9336 fclose(fp);
9337 unlink(tmpfile);
e96e4fbf 9338 redisLog(REDIS_WARNING,"Write error writing append only file on disk: %s", strerror(errno));
9d65a1bb 9339 if (di) dictReleaseIterator(di);
9340 return REDIS_ERR;
9341}
9342
9343/* This is how rewriting of the append only file in background works:
9344 *
9345 * 1) The user calls BGREWRITEAOF
9346 * 2) Redis calls this function, that forks():
9347 * 2a) the child rewrite the append only file in a temp file.
9348 * 2b) the parent accumulates differences in server.bgrewritebuf.
9349 * 3) When the child finished '2a' exists.
9350 * 4) The parent will trap the exit code, if it's OK, will append the
9351 * data accumulated into server.bgrewritebuf into the temp file, and
9352 * finally will rename(2) the temp file in the actual file name.
9353 * The the new file is reopened as the new append only file. Profit!
9354 */
9355static int rewriteAppendOnlyFileBackground(void) {
9356 pid_t childpid;
9357
9358 if (server.bgrewritechildpid != -1) return REDIS_ERR;
054e426d 9359 if (server.vm_enabled) waitEmptyIOJobsQueue();
9d65a1bb 9360 if ((childpid = fork()) == 0) {
9361 /* Child */
9362 char tmpfile[256];
9d65a1bb 9363
054e426d 9364 if (server.vm_enabled) vmReopenSwapFile();
9365 close(server.fd);
9d65a1bb 9366 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
9367 if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
478c2c6f 9368 _exit(0);
9d65a1bb 9369 } else {
478c2c6f 9370 _exit(1);
9d65a1bb 9371 }
9372 } else {
9373 /* Parent */
9374 if (childpid == -1) {
9375 redisLog(REDIS_WARNING,
9376 "Can't rewrite append only file in background: fork: %s",
9377 strerror(errno));
9378 return REDIS_ERR;
9379 }
9380 redisLog(REDIS_NOTICE,
9381 "Background append only file rewriting started by pid %d",childpid);
9382 server.bgrewritechildpid = childpid;
884d4b39 9383 updateDictResizePolicy();
85a83172 9384 /* We set appendseldb to -1 in order to force the next call to the
9385 * feedAppendOnlyFile() to issue a SELECT command, so the differences
9386 * accumulated by the parent into server.bgrewritebuf will start
9387 * with a SELECT statement and it will be safe to merge. */
9388 server.appendseldb = -1;
9d65a1bb 9389 return REDIS_OK;
9390 }
9391 return REDIS_OK; /* unreached */
9392}
9393
9394static void bgrewriteaofCommand(redisClient *c) {
9395 if (server.bgrewritechildpid != -1) {
9396 addReplySds(c,sdsnew("-ERR background append only file rewriting already in progress\r\n"));
9397 return;
9398 }
9399 if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
49b99ab4 9400 char *status = "+Background append only file rewriting started\r\n";
9401 addReplySds(c,sdsnew(status));
9d65a1bb 9402 } else {
9403 addReply(c,shared.err);
9404 }
9405}
9406
9407static void aofRemoveTempFile(pid_t childpid) {
9408 char tmpfile[256];
9409
9410 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) childpid);
9411 unlink(tmpfile);
9412}
9413
996cb5f7 9414/* Virtual Memory is composed mainly of two subsystems:
9415 * - Blocking Virutal Memory
9416 * - Threaded Virtual Memory I/O
9417 * The two parts are not fully decoupled, but functions are split among two
9418 * different sections of the source code (delimited by comments) in order to
9419 * make more clear what functionality is about the blocking VM and what about
9420 * the threaded (not blocking) VM.
9421 *
9422 * Redis VM design:
9423 *
9424 * Redis VM is a blocking VM (one that blocks reading swapped values from
9425 * disk into memory when a value swapped out is needed in memory) that is made
9426 * unblocking by trying to examine the command argument vector in order to
9427 * load in background values that will likely be needed in order to exec
9428 * the command. The command is executed only once all the relevant keys
9429 * are loaded into memory.
9430 *
9431 * This basically is almost as simple of a blocking VM, but almost as parallel
9432 * as a fully non-blocking VM.
9433 */
9434
560db612 9435/* =================== Virtual Memory - Blocking Side ====================== */
2e5eb04e 9436
560db612 9437/* Create a VM pointer object. This kind of objects are used in place of
9438 * values in the key -> value hash table, for swapped out objects. */
9439static vmpointer *createVmPointer(int vtype) {
9440 vmpointer *vp = zmalloc(sizeof(vmpointer));
2e5eb04e 9441
560db612 9442 vp->type = REDIS_VMPOINTER;
9443 vp->storage = REDIS_VM_SWAPPED;
9444 vp->vtype = vtype;
9445 return vp;
2e5eb04e 9446}
9447
75680a3c 9448static void vmInit(void) {
9449 off_t totsize;
996cb5f7 9450 int pipefds[2];
bcaa7a4f 9451 size_t stacksize;
8b5bb414 9452 struct flock fl;
75680a3c 9453
4ad37480 9454 if (server.vm_max_threads != 0)
9455 zmalloc_enable_thread_safeness(); /* we need thread safe zmalloc() */
9456
054e426d 9457 redisLog(REDIS_NOTICE,"Using '%s' as swap file",server.vm_swap_file);
8b5bb414 9458 /* Try to open the old swap file, otherwise create it */
6fa987e3 9459 if ((server.vm_fp = fopen(server.vm_swap_file,"r+b")) == NULL) {
9460 server.vm_fp = fopen(server.vm_swap_file,"w+b");
9461 }
75680a3c 9462 if (server.vm_fp == NULL) {
6fa987e3 9463 redisLog(REDIS_WARNING,
8b5bb414 9464 "Can't open the swap file: %s. Exiting.",
6fa987e3 9465 strerror(errno));
75680a3c 9466 exit(1);
9467 }
9468 server.vm_fd = fileno(server.vm_fp);
8b5bb414 9469 /* Lock the swap file for writing, this is useful in order to avoid
9470 * another instance to use the same swap file for a config error. */
9471 fl.l_type = F_WRLCK;
9472 fl.l_whence = SEEK_SET;
9473 fl.l_start = fl.l_len = 0;
9474 if (fcntl(server.vm_fd,F_SETLK,&fl) == -1) {
9475 redisLog(REDIS_WARNING,
9476 "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));
9477 exit(1);
9478 }
9479 /* Initialize */
75680a3c 9480 server.vm_next_page = 0;
9481 server.vm_near_pages = 0;
7d98e08c 9482 server.vm_stats_used_pages = 0;
9483 server.vm_stats_swapped_objects = 0;
9484 server.vm_stats_swapouts = 0;
9485 server.vm_stats_swapins = 0;
75680a3c 9486 totsize = server.vm_pages*server.vm_page_size;
9487 redisLog(REDIS_NOTICE,"Allocating %lld bytes of swap file",totsize);
9488 if (ftruncate(server.vm_fd,totsize) == -1) {
9489 redisLog(REDIS_WARNING,"Can't ftruncate swap file: %s. Exiting.",
9490 strerror(errno));
9491 exit(1);
9492 } else {
9493 redisLog(REDIS_NOTICE,"Swap file allocated with success");
9494 }
7d30035d 9495 server.vm_bitmap = zmalloc((server.vm_pages+7)/8);
f870935d 9496 redisLog(REDIS_VERBOSE,"Allocated %lld bytes page table for %lld pages",
4ef8de8a 9497 (long long) (server.vm_pages+7)/8, server.vm_pages);
7d30035d 9498 memset(server.vm_bitmap,0,(server.vm_pages+7)/8);
92f8e882 9499
996cb5f7 9500 /* Initialize threaded I/O (used by Virtual Memory) */
9501 server.io_newjobs = listCreate();
9502 server.io_processing = listCreate();
9503 server.io_processed = listCreate();
d5d55fc3 9504 server.io_ready_clients = listCreate();
92f8e882 9505 pthread_mutex_init(&server.io_mutex,NULL);
a5819310 9506 pthread_mutex_init(&server.obj_freelist_mutex,NULL);
9507 pthread_mutex_init(&server.io_swapfile_mutex,NULL);
92f8e882 9508 server.io_active_threads = 0;
996cb5f7 9509 if (pipe(pipefds) == -1) {
9510 redisLog(REDIS_WARNING,"Unable to intialized VM: pipe(2): %s. Exiting."
9511 ,strerror(errno));
9512 exit(1);
9513 }
9514 server.io_ready_pipe_read = pipefds[0];
9515 server.io_ready_pipe_write = pipefds[1];
9516 redisAssert(anetNonBlock(NULL,server.io_ready_pipe_read) != ANET_ERR);
bcaa7a4f 9517 /* LZF requires a lot of stack */
9518 pthread_attr_init(&server.io_threads_attr);
9519 pthread_attr_getstacksize(&server.io_threads_attr, &stacksize);
9520 while (stacksize < REDIS_THREAD_STACK_SIZE) stacksize *= 2;
9521 pthread_attr_setstacksize(&server.io_threads_attr, stacksize);
b9bc0eef 9522 /* Listen for events in the threaded I/O pipe */
9523 if (aeCreateFileEvent(server.el, server.io_ready_pipe_read, AE_READABLE,
9524 vmThreadedIOCompletedJob, NULL) == AE_ERR)
9525 oom("creating file event");
75680a3c 9526}
9527
06224fec 9528/* Mark the page as used */
9529static void vmMarkPageUsed(off_t page) {
9530 off_t byte = page/8;
9531 int bit = page&7;
970e10bb 9532 redisAssert(vmFreePage(page) == 1);
06224fec 9533 server.vm_bitmap[byte] |= 1<<bit;
9534}
9535
9536/* Mark N contiguous pages as used, with 'page' being the first. */
9537static void vmMarkPagesUsed(off_t page, off_t count) {
9538 off_t j;
9539
9540 for (j = 0; j < count; j++)
7d30035d 9541 vmMarkPageUsed(page+j);
7d98e08c 9542 server.vm_stats_used_pages += count;
7c775e09 9543 redisLog(REDIS_DEBUG,"Mark USED pages: %lld pages at %lld\n",
9544 (long long)count, (long long)page);
06224fec 9545}
9546
9547/* Mark the page as free */
9548static void vmMarkPageFree(off_t page) {
9549 off_t byte = page/8;
9550 int bit = page&7;
970e10bb 9551 redisAssert(vmFreePage(page) == 0);
06224fec 9552 server.vm_bitmap[byte] &= ~(1<<bit);
9553}
9554
9555/* Mark N contiguous pages as free, with 'page' being the first. */
9556static void vmMarkPagesFree(off_t page, off_t count) {
9557 off_t j;
9558
9559 for (j = 0; j < count; j++)
7d30035d 9560 vmMarkPageFree(page+j);
7d98e08c 9561 server.vm_stats_used_pages -= count;
7c775e09 9562 redisLog(REDIS_DEBUG,"Mark FREE pages: %lld pages at %lld\n",
9563 (long long)count, (long long)page);
06224fec 9564}
9565
9566/* Test if the page is free */
9567static int vmFreePage(off_t page) {
9568 off_t byte = page/8;
9569 int bit = page&7;
7d30035d 9570 return (server.vm_bitmap[byte] & (1<<bit)) == 0;
06224fec 9571}
9572
9573/* Find N contiguous free pages storing the first page of the cluster in *first.
e0a62c7f 9574 * Returns REDIS_OK if it was able to find N contiguous pages, otherwise
3a66edc7 9575 * REDIS_ERR is returned.
06224fec 9576 *
9577 * This function uses a simple algorithm: we try to allocate
9578 * REDIS_VM_MAX_NEAR_PAGES sequentially, when we reach this limit we start
9579 * again from the start of the swap file searching for free spaces.
9580 *
9581 * If it looks pretty clear that there are no free pages near our offset
9582 * we try to find less populated places doing a forward jump of
9583 * REDIS_VM_MAX_RANDOM_JUMP, then we start scanning again a few pages
9584 * without hurry, and then we jump again and so forth...
e0a62c7f 9585 *
06224fec 9586 * This function can be improved using a free list to avoid to guess
9587 * too much, since we could collect data about freed pages.
9588 *
9589 * note: I implemented this function just after watching an episode of
9590 * Battlestar Galactica, where the hybrid was continuing to say "JUMP!"
9591 */
c7df85a4 9592static int vmFindContiguousPages(off_t *first, off_t n) {
06224fec 9593 off_t base, offset = 0, since_jump = 0, numfree = 0;
9594
9595 if (server.vm_near_pages == REDIS_VM_MAX_NEAR_PAGES) {
9596 server.vm_near_pages = 0;
9597 server.vm_next_page = 0;
9598 }
9599 server.vm_near_pages++; /* Yet another try for pages near to the old ones */
9600 base = server.vm_next_page;
9601
9602 while(offset < server.vm_pages) {
9603 off_t this = base+offset;
9604
9605 /* If we overflow, restart from page zero */
9606 if (this >= server.vm_pages) {
9607 this -= server.vm_pages;
9608 if (this == 0) {
9609 /* Just overflowed, what we found on tail is no longer
9610 * interesting, as it's no longer contiguous. */
9611 numfree = 0;
9612 }
9613 }
9614 if (vmFreePage(this)) {
9615 /* This is a free page */
9616 numfree++;
9617 /* Already got N free pages? Return to the caller, with success */
9618 if (numfree == n) {
7d30035d 9619 *first = this-(n-1);
9620 server.vm_next_page = this+1;
7c775e09 9621 redisLog(REDIS_DEBUG, "FOUND CONTIGUOUS PAGES: %lld pages at %lld\n", (long long) n, (long long) *first);
3a66edc7 9622 return REDIS_OK;
06224fec 9623 }
9624 } else {
9625 /* The current one is not a free page */
9626 numfree = 0;
9627 }
9628
9629 /* Fast-forward if the current page is not free and we already
9630 * searched enough near this place. */
9631 since_jump++;
9632 if (!numfree && since_jump >= REDIS_VM_MAX_RANDOM_JUMP/4) {
9633 offset += random() % REDIS_VM_MAX_RANDOM_JUMP;
9634 since_jump = 0;
9635 /* Note that even if we rewind after the jump, we are don't need
9636 * to make sure numfree is set to zero as we only jump *if* it
9637 * is set to zero. */
9638 } else {
9639 /* Otherwise just check the next page */
9640 offset++;
9641 }
9642 }
3a66edc7 9643 return REDIS_ERR;
9644}
9645
a5819310 9646/* Write the specified object at the specified page of the swap file */
9647static int vmWriteObjectOnSwap(robj *o, off_t page) {
9648 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
9649 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
9650 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
9651 redisLog(REDIS_WARNING,
9ebed7cf 9652 "Critical VM problem in vmWriteObjectOnSwap(): can't seek: %s",
a5819310 9653 strerror(errno));
9654 return REDIS_ERR;
9655 }
9656 rdbSaveObject(server.vm_fp,o);
ba76a8f9 9657 fflush(server.vm_fp);
a5819310 9658 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
9659 return REDIS_OK;
9660}
9661
a4798f73 9662/* Transfers the 'val' object to disk. Store all the information
9663 * a 'vmpointer' object containing all the information needed to load the
9664 * object back later is returned.
9665 *
3a66edc7 9666 * If we can't find enough contiguous empty pages to swap the object on disk
a4798f73 9667 * NULL is returned. */
560db612 9668static vmpointer *vmSwapObjectBlocking(robj *val) {
b9bc0eef 9669 off_t pages = rdbSavedObjectPages(val,NULL);
3a66edc7 9670 off_t page;
560db612 9671 vmpointer *vp;
3a66edc7 9672
560db612 9673 assert(val->storage == REDIS_VM_MEMORY);
9674 assert(val->refcount == 1);
9675 if (vmFindContiguousPages(&page,pages) == REDIS_ERR) return NULL;
9676 if (vmWriteObjectOnSwap(val,page) == REDIS_ERR) return NULL;
9677
9678 vp = createVmPointer(val->type);
9679 vp->page = page;
9680 vp->usedpages = pages;
3a66edc7 9681 decrRefCount(val); /* Deallocate the object from memory. */
9682 vmMarkPagesUsed(page,pages);
560db612 9683 redisLog(REDIS_DEBUG,"VM: object %p swapped out at %lld (%lld pages)",
9684 (void*) val,
7d30035d 9685 (unsigned long long) page, (unsigned long long) pages);
7d98e08c 9686 server.vm_stats_swapped_objects++;
9687 server.vm_stats_swapouts++;
560db612 9688 return vp;
3a66edc7 9689}
9690
a5819310 9691static robj *vmReadObjectFromSwap(off_t page, int type) {
9692 robj *o;
3a66edc7 9693
a5819310 9694 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
9695 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
3a66edc7 9696 redisLog(REDIS_WARNING,
d5d55fc3 9697 "Unrecoverable VM problem in vmReadObjectFromSwap(): can't seek: %s",
3a66edc7 9698 strerror(errno));
478c2c6f 9699 _exit(1);
3a66edc7 9700 }
a5819310 9701 o = rdbLoadObject(type,server.vm_fp);
9702 if (o == NULL) {
d5d55fc3 9703 redisLog(REDIS_WARNING, "Unrecoverable VM problem in vmReadObjectFromSwap(): can't load object from swap file: %s", strerror(errno));
478c2c6f 9704 _exit(1);
3a66edc7 9705 }
a5819310 9706 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
9707 return o;
9708}
9709
560db612 9710/* Load the specified object from swap to memory.
a5819310 9711 * The newly allocated object is returned.
9712 *
9713 * If preview is true the unserialized object is returned to the caller but
560db612 9714 * the pages are not marked as freed, nor the vp object is freed. */
9715static robj *vmGenericLoadObject(vmpointer *vp, int preview) {
a5819310 9716 robj *val;
9717
560db612 9718 redisAssert(vp->type == REDIS_VMPOINTER &&
9719 (vp->storage == REDIS_VM_SWAPPED || vp->storage == REDIS_VM_LOADING));
9720 val = vmReadObjectFromSwap(vp->page,vp->vtype);
7e69548d 9721 if (!preview) {
560db612 9722 redisLog(REDIS_DEBUG, "VM: object %p loaded from disk", (void*)vp);
9723 vmMarkPagesFree(vp->page,vp->usedpages);
9724 zfree(vp);
7d98e08c 9725 server.vm_stats_swapped_objects--;
38aba9a1 9726 } else {
560db612 9727 redisLog(REDIS_DEBUG, "VM: object %p previewed from disk", (void*)vp);
7e69548d 9728 }
7d98e08c 9729 server.vm_stats_swapins++;
3a66edc7 9730 return val;
06224fec 9731}
9732
560db612 9733/* Plain object loading, from swap to memory.
9734 *
9735 * 'o' is actually a redisVmPointer structure that will be freed by the call.
9736 * The return value is the loaded object. */
9737static robj *vmLoadObject(robj *o) {
996cb5f7 9738 /* If we are loading the object in background, stop it, we
9739 * need to load this object synchronously ASAP. */
560db612 9740 if (o->storage == REDIS_VM_LOADING)
9741 vmCancelThreadedIOJob(o);
9742 return vmGenericLoadObject((vmpointer*)o,0);
7e69548d 9743}
9744
9745/* Just load the value on disk, without to modify the key.
9746 * This is useful when we want to perform some operation on the value
9747 * without to really bring it from swap to memory, like while saving the
9748 * dataset or rewriting the append only log. */
560db612 9749static robj *vmPreviewObject(robj *o) {
9750 return vmGenericLoadObject((vmpointer*)o,1);
7e69548d 9751}
9752
4ef8de8a 9753/* How a good candidate is this object for swapping?
9754 * The better candidate it is, the greater the returned value.
9755 *
9756 * Currently we try to perform a fast estimation of the object size in
9757 * memory, and combine it with aging informations.
9758 *
9759 * Basically swappability = idle-time * log(estimated size)
9760 *
9761 * Bigger objects are preferred over smaller objects, but not
9762 * proportionally, this is why we use the logarithm. This algorithm is
9763 * just a first try and will probably be tuned later. */
9764static double computeObjectSwappability(robj *o) {
560db612 9765 /* actual age can be >= minage, but not < minage. As we use wrapping
9766 * 21 bit clocks with minutes resolution for the LRU. */
9767 time_t minage = abs(server.lruclock - o->lru);
4ef8de8a 9768 long asize = 0;
9769 list *l;
9770 dict *d;
9771 struct dictEntry *de;
9772 int z;
9773
560db612 9774 if (minage <= 0) return 0;
4ef8de8a 9775 switch(o->type) {
9776 case REDIS_STRING:
9777 if (o->encoding != REDIS_ENCODING_RAW) {
9778 asize = sizeof(*o);
9779 } else {
9780 asize = sdslen(o->ptr)+sizeof(*o)+sizeof(long)*2;
9781 }
9782 break;
9783 case REDIS_LIST:
9784 l = o->ptr;
9785 listNode *ln = listFirst(l);
9786
9787 asize = sizeof(list);
9788 if (ln) {
9789 robj *ele = ln->value;
9790 long elesize;
9791
9792 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
560db612 9793 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
4ef8de8a 9794 asize += (sizeof(listNode)+elesize)*listLength(l);
9795 }
9796 break;
9797 case REDIS_SET:
9798 case REDIS_ZSET:
9799 z = (o->type == REDIS_ZSET);
9800 d = z ? ((zset*)o->ptr)->dict : o->ptr;
9801
9802 asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
9803 if (z) asize += sizeof(zset)-sizeof(dict);
9804 if (dictSize(d)) {
9805 long elesize;
9806 robj *ele;
9807
9808 de = dictGetRandomKey(d);
9809 ele = dictGetEntryKey(de);
9810 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
560db612 9811 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
4ef8de8a 9812 asize += (sizeof(struct dictEntry)+elesize)*dictSize(d);
9813 if (z) asize += sizeof(zskiplistNode)*dictSize(d);
9814 }
9815 break;
a97b9060 9816 case REDIS_HASH:
9817 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
9818 unsigned char *p = zipmapRewind((unsigned char*)o->ptr);
9819 unsigned int len = zipmapLen((unsigned char*)o->ptr);
9820 unsigned int klen, vlen;
9821 unsigned char *key, *val;
9822
9823 if ((p = zipmapNext(p,&key,&klen,&val,&vlen)) == NULL) {
9824 klen = 0;
9825 vlen = 0;
9826 }
9827 asize = len*(klen+vlen+3);
9828 } else if (o->encoding == REDIS_ENCODING_HT) {
9829 d = o->ptr;
9830 asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
9831 if (dictSize(d)) {
9832 long elesize;
9833 robj *ele;
9834
9835 de = dictGetRandomKey(d);
9836 ele = dictGetEntryKey(de);
9837 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
560db612 9838 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
a97b9060 9839 ele = dictGetEntryVal(de);
9840 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
560db612 9841 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
a97b9060 9842 asize += (sizeof(struct dictEntry)+elesize)*dictSize(d);
9843 }
9844 }
9845 break;
4ef8de8a 9846 }
560db612 9847 return (double)minage*log(1+asize);
4ef8de8a 9848}
9849
9850/* Try to swap an object that's a good candidate for swapping.
9851 * Returns REDIS_OK if the object was swapped, REDIS_ERR if it's not possible
a69a0c9c 9852 * to swap any object at all.
9853 *
9854 * If 'usethreaded' is true, Redis will try to swap the object in background
9855 * using I/O threads. */
9856static int vmSwapOneObject(int usethreads) {
4ef8de8a 9857 int j, i;
9858 struct dictEntry *best = NULL;
9859 double best_swappability = 0;
b9bc0eef 9860 redisDb *best_db = NULL;
44262c58 9861 robj *val;
9862 sds key;
4ef8de8a 9863
9864 for (j = 0; j < server.dbnum; j++) {
9865 redisDb *db = server.db+j;
b72f6a4b 9866 /* Why maxtries is set to 100?
9867 * Because this way (usually) we'll find 1 object even if just 1% - 2%
9868 * are swappable objects */
b0d8747d 9869 int maxtries = 100;
4ef8de8a 9870
9871 if (dictSize(db->dict) == 0) continue;
9872 for (i = 0; i < 5; i++) {
9873 dictEntry *de;
9874 double swappability;
9875
e3cadb8a 9876 if (maxtries) maxtries--;
4ef8de8a 9877 de = dictGetRandomKey(db->dict);
4ef8de8a 9878 val = dictGetEntryVal(de);
1064ef87 9879 /* Only swap objects that are currently in memory.
9880 *
560db612 9881 * Also don't swap shared objects: not a good idea in general and
9882 * we need to ensure that the main thread does not touch the
1064ef87 9883 * object while the I/O thread is using it, but we can't
9884 * control other keys without adding additional mutex. */
560db612 9885 if (val->storage != REDIS_VM_MEMORY || val->refcount != 1) {
e3cadb8a 9886 if (maxtries) i--; /* don't count this try */
9887 continue;
9888 }
4ef8de8a 9889 swappability = computeObjectSwappability(val);
9890 if (!best || swappability > best_swappability) {
9891 best = de;
9892 best_swappability = swappability;
b9bc0eef 9893 best_db = db;
4ef8de8a 9894 }
9895 }
9896 }
7c775e09 9897 if (best == NULL) return REDIS_ERR;
4ef8de8a 9898 key = dictGetEntryKey(best);
9899 val = dictGetEntryVal(best);
9900
e3cadb8a 9901 redisLog(REDIS_DEBUG,"Key with best swappability: %s, %f",
44262c58 9902 key, best_swappability);
4ef8de8a 9903
4ef8de8a 9904 /* Swap it */
a69a0c9c 9905 if (usethreads) {
4c8f2370 9906 robj *keyobj = createStringObject(key,sdslen(key));
9907 vmSwapObjectThreaded(keyobj,val,best_db);
9908 decrRefCount(keyobj);
4ef8de8a 9909 return REDIS_OK;
9910 } else {
560db612 9911 vmpointer *vp;
9912
9913 if ((vp = vmSwapObjectBlocking(val)) != NULL) {
9914 dictGetEntryVal(best) = vp;
a69a0c9c 9915 return REDIS_OK;
9916 } else {
9917 return REDIS_ERR;
9918 }
4ef8de8a 9919 }
9920}
9921
a69a0c9c 9922static int vmSwapOneObjectBlocking() {
9923 return vmSwapOneObject(0);
9924}
9925
9926static int vmSwapOneObjectThreaded() {
9927 return vmSwapOneObject(1);
9928}
9929
7e69548d 9930/* Return true if it's safe to swap out objects in a given moment.
9931 * Basically we don't want to swap objects out while there is a BGSAVE
9932 * or a BGAEOREWRITE running in backgroud. */
9933static int vmCanSwapOut(void) {
9934 return (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1);
9935}
9936
996cb5f7 9937/* =================== Virtual Memory - Threaded I/O ======================= */
9938
b9bc0eef 9939static void freeIOJob(iojob *j) {
d5d55fc3 9940 if ((j->type == REDIS_IOJOB_PREPARE_SWAP ||
9941 j->type == REDIS_IOJOB_DO_SWAP ||
9942 j->type == REDIS_IOJOB_LOAD) && j->val != NULL)
560db612 9943 {
e4ed181d 9944 /* we fix the storage type, otherwise decrRefCount() will try to
9945 * kill the I/O thread Job (that does no longer exists). */
9946 if (j->val->storage == REDIS_VM_SWAPPING)
560db612 9947 j->val->storage = REDIS_VM_MEMORY;
b9bc0eef 9948 decrRefCount(j->val);
560db612 9949 }
9950 decrRefCount(j->key);
b9bc0eef 9951 zfree(j);
9952}
9953
996cb5f7 9954/* Every time a thread finished a Job, it writes a byte into the write side
9955 * of an unix pipe in order to "awake" the main thread, and this function
9956 * is called. */
9957static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
9958 int mask)
9959{
9960 char buf[1];
b0d8747d 9961 int retval, processed = 0, toprocess = -1, trytoswap = 1;
996cb5f7 9962 REDIS_NOTUSED(el);
9963 REDIS_NOTUSED(mask);
9964 REDIS_NOTUSED(privdata);
9965
9966 /* For every byte we read in the read side of the pipe, there is one
9967 * I/O job completed to process. */
9968 while((retval = read(fd,buf,1)) == 1) {
b9bc0eef 9969 iojob *j;
9970 listNode *ln;
b9bc0eef 9971 struct dictEntry *de;
9972
996cb5f7 9973 redisLog(REDIS_DEBUG,"Processing I/O completed job");
b9bc0eef 9974
9975 /* Get the processed element (the oldest one) */
9976 lockThreadedIO();
1064ef87 9977 assert(listLength(server.io_processed) != 0);
f6c0bba8 9978 if (toprocess == -1) {
9979 toprocess = (listLength(server.io_processed)*REDIS_MAX_COMPLETED_JOBS_PROCESSED)/100;
9980 if (toprocess <= 0) toprocess = 1;
9981 }
b9bc0eef 9982 ln = listFirst(server.io_processed);
9983 j = ln->value;
9984 listDelNode(server.io_processed,ln);
9985 unlockThreadedIO();
9986 /* If this job is marked as canceled, just ignore it */
9987 if (j->canceled) {
9988 freeIOJob(j);
9989 continue;
9990 }
9991 /* Post process it in the main thread, as there are things we
9992 * can do just here to avoid race conditions and/or invasive locks */
560db612 9993 redisLog(REDIS_DEBUG,"COMPLETED Job type: %d, ID %p, key: %s", j->type, (void*)j->id, (unsigned char*)j->key->ptr);
44262c58 9994 de = dictFind(j->db->dict,j->key->ptr);
e4ed181d 9995 redisAssert(de != NULL);
b9bc0eef 9996 if (j->type == REDIS_IOJOB_LOAD) {
d5d55fc3 9997 redisDb *db;
560db612 9998 vmpointer *vp = dictGetEntryVal(de);
d5d55fc3 9999
b9bc0eef 10000 /* Key loaded, bring it at home */
560db612 10001 vmMarkPagesFree(vp->page,vp->usedpages);
b9bc0eef 10002 redisLog(REDIS_DEBUG, "VM: object %s loaded from disk (threaded)",
560db612 10003 (unsigned char*) j->key->ptr);
b9bc0eef 10004 server.vm_stats_swapped_objects--;
10005 server.vm_stats_swapins++;
d5d55fc3 10006 dictGetEntryVal(de) = j->val;
10007 incrRefCount(j->val);
10008 db = j->db;
d5d55fc3 10009 /* Handle clients waiting for this key to be loaded. */
560db612 10010 handleClientsBlockedOnSwappedKey(db,j->key);
10011 freeIOJob(j);
10012 zfree(vp);
b9bc0eef 10013 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
10014 /* Now we know the amount of pages required to swap this object.
10015 * Let's find some space for it, and queue this task again
10016 * rebranded as REDIS_IOJOB_DO_SWAP. */
054e426d 10017 if (!vmCanSwapOut() ||
10018 vmFindContiguousPages(&j->page,j->pages) == REDIS_ERR)
10019 {
10020 /* Ooops... no space or we can't swap as there is
10021 * a fork()ed Redis trying to save stuff on disk. */
560db612 10022 j->val->storage = REDIS_VM_MEMORY; /* undo operation */
b9bc0eef 10023 freeIOJob(j);
10024 } else {
c7df85a4 10025 /* Note that we need to mark this pages as used now,
10026 * if the job will be canceled, we'll mark them as freed
10027 * again. */
10028 vmMarkPagesUsed(j->page,j->pages);
b9bc0eef 10029 j->type = REDIS_IOJOB_DO_SWAP;
10030 lockThreadedIO();
10031 queueIOJob(j);
10032 unlockThreadedIO();
10033 }
10034 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
560db612 10035 vmpointer *vp;
b9bc0eef 10036
10037 /* Key swapped. We can finally free some memory. */
560db612 10038 if (j->val->storage != REDIS_VM_SWAPPING) {
10039 vmpointer *vp = (vmpointer*) j->id;
10040 printf("storage: %d\n",vp->storage);
10041 printf("key->name: %s\n",(char*)j->key->ptr);
6c96ba7d 10042 printf("val: %p\n",(void*)j->val);
10043 printf("val->type: %d\n",j->val->type);
10044 printf("val->ptr: %s\n",(char*)j->val->ptr);
10045 }
560db612 10046 redisAssert(j->val->storage == REDIS_VM_SWAPPING);
10047 vp = createVmPointer(j->val->type);
10048 vp->page = j->page;
10049 vp->usedpages = j->pages;
10050 dictGetEntryVal(de) = vp;
e4ed181d 10051 /* Fix the storage otherwise decrRefCount will attempt to
10052 * remove the associated I/O job */
10053 j->val->storage = REDIS_VM_MEMORY;
560db612 10054 decrRefCount(j->val);
b9bc0eef 10055 redisLog(REDIS_DEBUG,
10056 "VM: object %s swapped out at %lld (%lld pages) (threaded)",
560db612 10057 (unsigned char*) j->key->ptr,
b9bc0eef 10058 (unsigned long long) j->page, (unsigned long long) j->pages);
10059 server.vm_stats_swapped_objects++;
10060 server.vm_stats_swapouts++;
10061 freeIOJob(j);
f11b8647 10062 /* Put a few more swap requests in queue if we are still
10063 * out of memory */
b0d8747d 10064 if (trytoswap && vmCanSwapOut() &&
10065 zmalloc_used_memory() > server.vm_max_memory)
10066 {
f11b8647 10067 int more = 1;
10068 while(more) {
10069 lockThreadedIO();
10070 more = listLength(server.io_newjobs) <
10071 (unsigned) server.vm_max_threads;
10072 unlockThreadedIO();
10073 /* Don't waste CPU time if swappable objects are rare. */
b0d8747d 10074 if (vmSwapOneObjectThreaded() == REDIS_ERR) {
10075 trytoswap = 0;
10076 break;
10077 }
f11b8647 10078 }
10079 }
b9bc0eef 10080 }
c953f24b 10081 processed++;
f6c0bba8 10082 if (processed == toprocess) return;
996cb5f7 10083 }
10084 if (retval < 0 && errno != EAGAIN) {
10085 redisLog(REDIS_WARNING,
10086 "WARNING: read(2) error in vmThreadedIOCompletedJob() %s",
10087 strerror(errno));
10088 }
10089}
10090
10091static void lockThreadedIO(void) {
10092 pthread_mutex_lock(&server.io_mutex);
10093}
10094
10095static void unlockThreadedIO(void) {
10096 pthread_mutex_unlock(&server.io_mutex);
10097}
10098
10099/* Remove the specified object from the threaded I/O queue if still not
10100 * processed, otherwise make sure to flag it as canceled. */
10101static void vmCancelThreadedIOJob(robj *o) {
10102 list *lists[3] = {
6c96ba7d 10103 server.io_newjobs, /* 0 */
10104 server.io_processing, /* 1 */
10105 server.io_processed /* 2 */
996cb5f7 10106 };
10107 int i;
10108
10109 assert(o->storage == REDIS_VM_LOADING || o->storage == REDIS_VM_SWAPPING);
2e111efe 10110again:
996cb5f7 10111 lockThreadedIO();
560db612 10112 /* Search for a matching object in one of the queues */
996cb5f7 10113 for (i = 0; i < 3; i++) {
10114 listNode *ln;
c7df85a4 10115 listIter li;
996cb5f7 10116
c7df85a4 10117 listRewind(lists[i],&li);
10118 while ((ln = listNext(&li)) != NULL) {
996cb5f7 10119 iojob *job = ln->value;
10120
6c96ba7d 10121 if (job->canceled) continue; /* Skip this, already canceled. */
560db612 10122 if (job->id == o) {
dbc289ae 10123 redisLog(REDIS_DEBUG,"*** CANCELED %p (key %s) (type %d) (LIST ID %d)\n",
10124 (void*)job, (char*)job->key->ptr, job->type, i);
427a2153 10125 /* Mark the pages as free since the swap didn't happened
10126 * or happened but is now discarded. */
970e10bb 10127 if (i != 1 && job->type == REDIS_IOJOB_DO_SWAP)
427a2153 10128 vmMarkPagesFree(job->page,job->pages);
10129 /* Cancel the job. It depends on the list the job is
10130 * living in. */
996cb5f7 10131 switch(i) {
10132 case 0: /* io_newjobs */
6c96ba7d 10133 /* If the job was yet not processed the best thing to do
996cb5f7 10134 * is to remove it from the queue at all */
6c96ba7d 10135 freeIOJob(job);
996cb5f7 10136 listDelNode(lists[i],ln);
10137 break;
10138 case 1: /* io_processing */
d5d55fc3 10139 /* Oh Shi- the thread is messing with the Job:
10140 *
10141 * Probably it's accessing the object if this is a
10142 * PREPARE_SWAP or DO_SWAP job.
10143 * If it's a LOAD job it may be reading from disk and
10144 * if we don't wait for the job to terminate before to
10145 * cancel it, maybe in a few microseconds data can be
10146 * corrupted in this pages. So the short story is:
10147 *
10148 * Better to wait for the job to move into the
10149 * next queue (processed)... */
10150
10151 /* We try again and again until the job is completed. */
10152 unlockThreadedIO();
10153 /* But let's wait some time for the I/O thread
10154 * to finish with this job. After all this condition
10155 * should be very rare. */
10156 usleep(1);
10157 goto again;
996cb5f7 10158 case 2: /* io_processed */
2e111efe 10159 /* The job was already processed, that's easy...
10160 * just mark it as canceled so that we'll ignore it
10161 * when processing completed jobs. */
996cb5f7 10162 job->canceled = 1;
10163 break;
10164 }
c7df85a4 10165 /* Finally we have to adjust the storage type of the object
10166 * in order to "UNDO" the operaiton. */
996cb5f7 10167 if (o->storage == REDIS_VM_LOADING)
10168 o->storage = REDIS_VM_SWAPPED;
10169 else if (o->storage == REDIS_VM_SWAPPING)
10170 o->storage = REDIS_VM_MEMORY;
10171 unlockThreadedIO();
e4ed181d 10172 redisLog(REDIS_DEBUG,"*** DONE");
996cb5f7 10173 return;
10174 }
10175 }
10176 }
10177 unlockThreadedIO();
560db612 10178 printf("Not found: %p\n", (void*)o);
10179 redisAssert(1 != 1); /* We should never reach this */
996cb5f7 10180}
10181
b9bc0eef 10182static void *IOThreadEntryPoint(void *arg) {
10183 iojob *j;
10184 listNode *ln;
10185 REDIS_NOTUSED(arg);
10186
10187 pthread_detach(pthread_self());
10188 while(1) {
10189 /* Get a new job to process */
10190 lockThreadedIO();
10191 if (listLength(server.io_newjobs) == 0) {
10192 /* No new jobs in queue, exit. */
9ebed7cf 10193 redisLog(REDIS_DEBUG,"Thread %ld exiting, nothing to do",
10194 (long) pthread_self());
b9bc0eef 10195 server.io_active_threads--;
10196 unlockThreadedIO();
10197 return NULL;
10198 }
10199 ln = listFirst(server.io_newjobs);
10200 j = ln->value;
10201 listDelNode(server.io_newjobs,ln);
10202 /* Add the job in the processing queue */
10203 j->thread = pthread_self();
10204 listAddNodeTail(server.io_processing,j);
10205 ln = listLast(server.io_processing); /* We use ln later to remove it */
10206 unlockThreadedIO();
9ebed7cf 10207 redisLog(REDIS_DEBUG,"Thread %ld got a new job (type %d): %p about key '%s'",
10208 (long) pthread_self(), j->type, (void*)j, (char*)j->key->ptr);
b9bc0eef 10209
10210 /* Process the Job */
10211 if (j->type == REDIS_IOJOB_LOAD) {
560db612 10212 vmpointer *vp = (vmpointer*)j->id;
10213 j->val = vmReadObjectFromSwap(j->page,vp->vtype);
b9bc0eef 10214 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
10215 FILE *fp = fopen("/dev/null","w+");
10216 j->pages = rdbSavedObjectPages(j->val,fp);
10217 fclose(fp);
10218 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
a5819310 10219 if (vmWriteObjectOnSwap(j->val,j->page) == REDIS_ERR)
10220 j->canceled = 1;
b9bc0eef 10221 }
10222
10223 /* Done: insert the job into the processed queue */
9ebed7cf 10224 redisLog(REDIS_DEBUG,"Thread %ld completed the job: %p (key %s)",
10225 (long) pthread_self(), (void*)j, (char*)j->key->ptr);
b9bc0eef 10226 lockThreadedIO();
10227 listDelNode(server.io_processing,ln);
10228 listAddNodeTail(server.io_processed,j);
10229 unlockThreadedIO();
e0a62c7f 10230
b9bc0eef 10231 /* Signal the main thread there is new stuff to process */
10232 assert(write(server.io_ready_pipe_write,"x",1) == 1);
10233 }
10234 return NULL; /* never reached */
10235}
10236
10237static void spawnIOThread(void) {
10238 pthread_t thread;
478c2c6f 10239 sigset_t mask, omask;
a97b9060 10240 int err;
b9bc0eef 10241
478c2c6f 10242 sigemptyset(&mask);
10243 sigaddset(&mask,SIGCHLD);
10244 sigaddset(&mask,SIGHUP);
10245 sigaddset(&mask,SIGPIPE);
10246 pthread_sigmask(SIG_SETMASK, &mask, &omask);
a97b9060 10247 while ((err = pthread_create(&thread,&server.io_threads_attr,IOThreadEntryPoint,NULL)) != 0) {
10248 redisLog(REDIS_WARNING,"Unable to spawn an I/O thread: %s",
10249 strerror(err));
10250 usleep(1000000);
10251 }
478c2c6f 10252 pthread_sigmask(SIG_SETMASK, &omask, NULL);
b9bc0eef 10253 server.io_active_threads++;
10254}
10255
4ee9488d 10256/* We need to wait for the last thread to exit before we are able to
10257 * fork() in order to BGSAVE or BGREWRITEAOF. */
054e426d 10258static void waitEmptyIOJobsQueue(void) {
4ee9488d 10259 while(1) {
76b7233a 10260 int io_processed_len;
10261
4ee9488d 10262 lockThreadedIO();
054e426d 10263 if (listLength(server.io_newjobs) == 0 &&
10264 listLength(server.io_processing) == 0 &&
10265 server.io_active_threads == 0)
10266 {
4ee9488d 10267 unlockThreadedIO();
10268 return;
10269 }
76b7233a 10270 /* While waiting for empty jobs queue condition we post-process some
10271 * finshed job, as I/O threads may be hanging trying to write against
10272 * the io_ready_pipe_write FD but there are so much pending jobs that
10273 * it's blocking. */
10274 io_processed_len = listLength(server.io_processed);
4ee9488d 10275 unlockThreadedIO();
76b7233a 10276 if (io_processed_len) {
10277 vmThreadedIOCompletedJob(NULL,server.io_ready_pipe_read,NULL,0);
10278 usleep(1000); /* 1 millisecond */
10279 } else {
10280 usleep(10000); /* 10 milliseconds */
10281 }
4ee9488d 10282 }
10283}
10284
054e426d 10285static void vmReopenSwapFile(void) {
478c2c6f 10286 /* Note: we don't close the old one as we are in the child process
10287 * and don't want to mess at all with the original file object. */
054e426d 10288 server.vm_fp = fopen(server.vm_swap_file,"r+b");
10289 if (server.vm_fp == NULL) {
10290 redisLog(REDIS_WARNING,"Can't re-open the VM swap file: %s. Exiting.",
10291 server.vm_swap_file);
478c2c6f 10292 _exit(1);
054e426d 10293 }
10294 server.vm_fd = fileno(server.vm_fp);
10295}
10296
b9bc0eef 10297/* This function must be called while with threaded IO locked */
10298static void queueIOJob(iojob *j) {
6c96ba7d 10299 redisLog(REDIS_DEBUG,"Queued IO Job %p type %d about key '%s'\n",
10300 (void*)j, j->type, (char*)j->key->ptr);
b9bc0eef 10301 listAddNodeTail(server.io_newjobs,j);
10302 if (server.io_active_threads < server.vm_max_threads)
10303 spawnIOThread();
10304}
10305
10306static int vmSwapObjectThreaded(robj *key, robj *val, redisDb *db) {
10307 iojob *j;
e0a62c7f 10308
b9bc0eef 10309 j = zmalloc(sizeof(*j));
10310 j->type = REDIS_IOJOB_PREPARE_SWAP;
10311 j->db = db;
78ebe4c8 10312 j->key = key;
7dd8e7cf 10313 incrRefCount(key);
560db612 10314 j->id = j->val = val;
b9bc0eef 10315 incrRefCount(val);
10316 j->canceled = 0;
10317 j->thread = (pthread_t) -1;
560db612 10318 val->storage = REDIS_VM_SWAPPING;
b9bc0eef 10319
10320 lockThreadedIO();
10321 queueIOJob(j);
10322 unlockThreadedIO();
10323 return REDIS_OK;
10324}
10325
b0d8747d 10326/* ============ Virtual Memory - Blocking clients on missing keys =========== */
10327
d5d55fc3 10328/* This function makes the clinet 'c' waiting for the key 'key' to be loaded.
10329 * If there is not already a job loading the key, it is craeted.
10330 * The key is added to the io_keys list in the client structure, and also
10331 * in the hash table mapping swapped keys to waiting clients, that is,
10332 * server.io_waited_keys. */
10333static int waitForSwappedKey(redisClient *c, robj *key) {
10334 struct dictEntry *de;
10335 robj *o;
10336 list *l;
10337
10338 /* If the key does not exist or is already in RAM we don't need to
10339 * block the client at all. */
09241813 10340 de = dictFind(c->db->dict,key->ptr);
d5d55fc3 10341 if (de == NULL) return 0;
560db612 10342 o = dictGetEntryVal(de);
d5d55fc3 10343 if (o->storage == REDIS_VM_MEMORY) {
10344 return 0;
10345 } else if (o->storage == REDIS_VM_SWAPPING) {
10346 /* We were swapping the key, undo it! */
10347 vmCancelThreadedIOJob(o);
10348 return 0;
10349 }
e0a62c7f 10350
d5d55fc3 10351 /* OK: the key is either swapped, or being loaded just now. */
10352
10353 /* Add the key to the list of keys this client is waiting for.
10354 * This maps clients to keys they are waiting for. */
10355 listAddNodeTail(c->io_keys,key);
10356 incrRefCount(key);
10357
10358 /* Add the client to the swapped keys => clients waiting map. */
10359 de = dictFind(c->db->io_keys,key);
10360 if (de == NULL) {
10361 int retval;
10362
10363 /* For every key we take a list of clients blocked for it */
10364 l = listCreate();
10365 retval = dictAdd(c->db->io_keys,key,l);
10366 incrRefCount(key);
10367 assert(retval == DICT_OK);
10368 } else {
10369 l = dictGetEntryVal(de);
10370 }
10371 listAddNodeTail(l,c);
10372
10373 /* Are we already loading the key from disk? If not create a job */
10374 if (o->storage == REDIS_VM_SWAPPED) {
10375 iojob *j;
560db612 10376 vmpointer *vp = (vmpointer*)o;
d5d55fc3 10377
10378 o->storage = REDIS_VM_LOADING;
10379 j = zmalloc(sizeof(*j));
10380 j->type = REDIS_IOJOB_LOAD;
10381 j->db = c->db;
560db612 10382 j->id = (robj*)vp;
10383 j->key = key;
10384 incrRefCount(key);
10385 j->page = vp->page;
d5d55fc3 10386 j->val = NULL;
10387 j->canceled = 0;
10388 j->thread = (pthread_t) -1;
10389 lockThreadedIO();
10390 queueIOJob(j);
10391 unlockThreadedIO();
10392 }
10393 return 1;
10394}
10395
6f078746
PN
10396/* Preload keys for any command with first, last and step values for
10397 * the command keys prototype, as defined in the command table. */
10398static void waitForMultipleSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv) {
10399 int j, last;
10400 if (cmd->vm_firstkey == 0) return;
10401 last = cmd->vm_lastkey;
10402 if (last < 0) last = argc+last;
10403 for (j = cmd->vm_firstkey; j <= last; j += cmd->vm_keystep) {
10404 redisAssert(j < argc);
10405 waitForSwappedKey(c,argv[j]);
10406 }
10407}
10408
5d373da9 10409/* Preload keys needed for the ZUNIONSTORE and ZINTERSTORE commands.
739ba0d2
PN
10410 * Note that the number of keys to preload is user-defined, so we need to
10411 * apply a sanity check against argc. */
ca1788b5 10412static void zunionInterBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv) {
76583ea4 10413 int i, num;
ca1788b5 10414 REDIS_NOTUSED(cmd);
ca1788b5
PN
10415
10416 num = atoi(argv[2]->ptr);
739ba0d2 10417 if (num > (argc-3)) return;
76583ea4 10418 for (i = 0; i < num; i++) {
ca1788b5 10419 waitForSwappedKey(c,argv[3+i]);
76583ea4
PN
10420 }
10421}
10422
3805e04f
PN
10423/* Preload keys needed to execute the entire MULTI/EXEC block.
10424 *
10425 * This function is called by blockClientOnSwappedKeys when EXEC is issued,
10426 * and will block the client when any command requires a swapped out value. */
10427static void execBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv) {
10428 int i, margc;
10429 struct redisCommand *mcmd;
10430 robj **margv;
10431 REDIS_NOTUSED(cmd);
10432 REDIS_NOTUSED(argc);
10433 REDIS_NOTUSED(argv);
10434
10435 if (!(c->flags & REDIS_MULTI)) return;
10436 for (i = 0; i < c->mstate.count; i++) {
10437 mcmd = c->mstate.commands[i].cmd;
10438 margc = c->mstate.commands[i].argc;
10439 margv = c->mstate.commands[i].argv;
10440
10441 if (mcmd->vm_preload_proc != NULL) {
10442 mcmd->vm_preload_proc(c,mcmd,margc,margv);
10443 } else {
10444 waitForMultipleSwappedKeys(c,mcmd,margc,margv);
10445 }
76583ea4
PN
10446 }
10447}
10448
b0d8747d 10449/* Is this client attempting to run a command against swapped keys?
d5d55fc3 10450 * If so, block it ASAP, load the keys in background, then resume it.
b0d8747d 10451 *
d5d55fc3 10452 * The important idea about this function is that it can fail! If keys will
10453 * still be swapped when the client is resumed, this key lookups will
10454 * just block loading keys from disk. In practical terms this should only
10455 * happen with SORT BY command or if there is a bug in this function.
10456 *
10457 * Return 1 if the client is marked as blocked, 0 if the client can
10458 * continue as the keys it is going to access appear to be in memory. */
0a6f3f0f 10459static int blockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd) {
76583ea4 10460 if (cmd->vm_preload_proc != NULL) {
ca1788b5 10461 cmd->vm_preload_proc(c,cmd,c->argc,c->argv);
76583ea4 10462 } else {
6f078746 10463 waitForMultipleSwappedKeys(c,cmd,c->argc,c->argv);
76583ea4
PN
10464 }
10465
d5d55fc3 10466 /* If the client was blocked for at least one key, mark it as blocked. */
10467 if (listLength(c->io_keys)) {
10468 c->flags |= REDIS_IO_WAIT;
10469 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
10470 server.vm_blocked_clients++;
10471 return 1;
10472 } else {
10473 return 0;
10474 }
10475}
10476
10477/* Remove the 'key' from the list of blocked keys for a given client.
10478 *
10479 * The function returns 1 when there are no longer blocking keys after
10480 * the current one was removed (and the client can be unblocked). */
10481static int dontWaitForSwappedKey(redisClient *c, robj *key) {
10482 list *l;
10483 listNode *ln;
10484 listIter li;
10485 struct dictEntry *de;
10486
10487 /* Remove the key from the list of keys this client is waiting for. */
10488 listRewind(c->io_keys,&li);
10489 while ((ln = listNext(&li)) != NULL) {
bf028098 10490 if (equalStringObjects(ln->value,key)) {
d5d55fc3 10491 listDelNode(c->io_keys,ln);
10492 break;
10493 }
10494 }
10495 assert(ln != NULL);
10496
10497 /* Remove the client form the key => waiting clients map. */
10498 de = dictFind(c->db->io_keys,key);
10499 assert(de != NULL);
10500 l = dictGetEntryVal(de);
10501 ln = listSearchKey(l,c);
10502 assert(ln != NULL);
10503 listDelNode(l,ln);
10504 if (listLength(l) == 0)
10505 dictDelete(c->db->io_keys,key);
10506
10507 return listLength(c->io_keys) == 0;
10508}
10509
560db612 10510/* Every time we now a key was loaded back in memory, we handle clients
10511 * waiting for this key if any. */
d5d55fc3 10512static void handleClientsBlockedOnSwappedKey(redisDb *db, robj *key) {
10513 struct dictEntry *de;
10514 list *l;
10515 listNode *ln;
10516 int len;
10517
10518 de = dictFind(db->io_keys,key);
10519 if (!de) return;
10520
10521 l = dictGetEntryVal(de);
10522 len = listLength(l);
10523 /* Note: we can't use something like while(listLength(l)) as the list
10524 * can be freed by the calling function when we remove the last element. */
10525 while (len--) {
10526 ln = listFirst(l);
10527 redisClient *c = ln->value;
10528
10529 if (dontWaitForSwappedKey(c,key)) {
10530 /* Put the client in the list of clients ready to go as we
10531 * loaded all the keys about it. */
10532 listAddNodeTail(server.io_ready_clients,c);
10533 }
10534 }
b0d8747d 10535}
b0d8747d 10536
500ece7c 10537/* =========================== Remote Configuration ========================= */
10538
10539static void configSetCommand(redisClient *c) {
10540 robj *o = getDecodedObject(c->argv[3]);
2e5eb04e 10541 long long ll;
10542
500ece7c 10543 if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) {
10544 zfree(server.dbfilename);
10545 server.dbfilename = zstrdup(o->ptr);
10546 } else if (!strcasecmp(c->argv[2]->ptr,"requirepass")) {
10547 zfree(server.requirepass);
10548 server.requirepass = zstrdup(o->ptr);
10549 } else if (!strcasecmp(c->argv[2]->ptr,"masterauth")) {
10550 zfree(server.masterauth);
10551 server.masterauth = zstrdup(o->ptr);
10552 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory")) {
2e5eb04e 10553 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
10554 ll < 0) goto badfmt;
10555 server.maxmemory = ll;
10556 } else if (!strcasecmp(c->argv[2]->ptr,"timeout")) {
10557 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
10558 ll < 0 || ll > LONG_MAX) goto badfmt;
10559 server.maxidletime = ll;
1b677732 10560 } else if (!strcasecmp(c->argv[2]->ptr,"appendfsync")) {
10561 if (!strcasecmp(o->ptr,"no")) {
10562 server.appendfsync = APPENDFSYNC_NO;
10563 } else if (!strcasecmp(o->ptr,"everysec")) {
10564 server.appendfsync = APPENDFSYNC_EVERYSEC;
10565 } else if (!strcasecmp(o->ptr,"always")) {
10566 server.appendfsync = APPENDFSYNC_ALWAYS;
10567 } else {
10568 goto badfmt;
10569 }
38db9171 10570 } else if (!strcasecmp(c->argv[2]->ptr,"no-appendfsync-on-rewrite")) {
10571 int yn = yesnotoi(o->ptr);
10572
10573 if (yn == -1) goto badfmt;
10574 server.no_appendfsync_on_rewrite = yn;
2e5eb04e 10575 } else if (!strcasecmp(c->argv[2]->ptr,"appendonly")) {
10576 int old = server.appendonly;
10577 int new = yesnotoi(o->ptr);
10578
10579 if (new == -1) goto badfmt;
10580 if (old != new) {
10581 if (new == 0) {
10582 stopAppendOnly();
10583 } else {
10584 if (startAppendOnly() == REDIS_ERR) {
10585 addReplySds(c,sdscatprintf(sdsempty(),
10586 "-ERR Unable to turn on AOF. Check server logs.\r\n"));
10587 decrRefCount(o);
10588 return;
10589 }
10590 }
10591 }
a34e0a25 10592 } else if (!strcasecmp(c->argv[2]->ptr,"save")) {
10593 int vlen, j;
10594 sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen);
10595
10596 /* Perform sanity check before setting the new config:
10597 * - Even number of args
10598 * - Seconds >= 1, changes >= 0 */
10599 if (vlen & 1) {
10600 sdsfreesplitres(v,vlen);
10601 goto badfmt;
10602 }
10603 for (j = 0; j < vlen; j++) {
10604 char *eptr;
10605 long val;
10606
10607 val = strtoll(v[j], &eptr, 10);
10608 if (eptr[0] != '\0' ||
10609 ((j & 1) == 0 && val < 1) ||
10610 ((j & 1) == 1 && val < 0)) {
10611 sdsfreesplitres(v,vlen);
10612 goto badfmt;
10613 }
10614 }
10615 /* Finally set the new config */
10616 resetServerSaveParams();
10617 for (j = 0; j < vlen; j += 2) {
10618 time_t seconds;
10619 int changes;
10620
10621 seconds = strtoll(v[j],NULL,10);
10622 changes = strtoll(v[j+1],NULL,10);
10623 appendServerSaveParams(seconds, changes);
10624 }
10625 sdsfreesplitres(v,vlen);
500ece7c 10626 } else {
10627 addReplySds(c,sdscatprintf(sdsempty(),
10628 "-ERR not supported CONFIG parameter %s\r\n",
10629 (char*)c->argv[2]->ptr));
10630 decrRefCount(o);
10631 return;
10632 }
10633 decrRefCount(o);
10634 addReply(c,shared.ok);
a34e0a25 10635 return;
10636
10637badfmt: /* Bad format errors */
10638 addReplySds(c,sdscatprintf(sdsempty(),
10639 "-ERR invalid argument '%s' for CONFIG SET '%s'\r\n",
10640 (char*)o->ptr,
10641 (char*)c->argv[2]->ptr));
10642 decrRefCount(o);
500ece7c 10643}
10644
10645static void configGetCommand(redisClient *c) {
10646 robj *o = getDecodedObject(c->argv[2]);
10647 robj *lenobj = createObject(REDIS_STRING,NULL);
10648 char *pattern = o->ptr;
10649 int matches = 0;
10650
10651 addReply(c,lenobj);
10652 decrRefCount(lenobj);
10653
10654 if (stringmatch(pattern,"dbfilename",0)) {
10655 addReplyBulkCString(c,"dbfilename");
10656 addReplyBulkCString(c,server.dbfilename);
10657 matches++;
10658 }
10659 if (stringmatch(pattern,"requirepass",0)) {
10660 addReplyBulkCString(c,"requirepass");
10661 addReplyBulkCString(c,server.requirepass);
10662 matches++;
10663 }
10664 if (stringmatch(pattern,"masterauth",0)) {
10665 addReplyBulkCString(c,"masterauth");
10666 addReplyBulkCString(c,server.masterauth);
10667 matches++;
10668 }
10669 if (stringmatch(pattern,"maxmemory",0)) {
10670 char buf[128];
10671
2e5eb04e 10672 ll2string(buf,128,server.maxmemory);
500ece7c 10673 addReplyBulkCString(c,"maxmemory");
10674 addReplyBulkCString(c,buf);
10675 matches++;
10676 }
2e5eb04e 10677 if (stringmatch(pattern,"timeout",0)) {
10678 char buf[128];
10679
10680 ll2string(buf,128,server.maxidletime);
10681 addReplyBulkCString(c,"timeout");
10682 addReplyBulkCString(c,buf);
10683 matches++;
10684 }
10685 if (stringmatch(pattern,"appendonly",0)) {
10686 addReplyBulkCString(c,"appendonly");
10687 addReplyBulkCString(c,server.appendonly ? "yes" : "no");
10688 matches++;
10689 }
38db9171 10690 if (stringmatch(pattern,"no-appendfsync-on-rewrite",0)) {
10691 addReplyBulkCString(c,"no-appendfsync-on-rewrite");
10692 addReplyBulkCString(c,server.no_appendfsync_on_rewrite ? "yes" : "no");
10693 matches++;
10694 }
1b677732 10695 if (stringmatch(pattern,"appendfsync",0)) {
10696 char *policy;
10697
10698 switch(server.appendfsync) {
10699 case APPENDFSYNC_NO: policy = "no"; break;
10700 case APPENDFSYNC_EVERYSEC: policy = "everysec"; break;
10701 case APPENDFSYNC_ALWAYS: policy = "always"; break;
10702 default: policy = "unknown"; break; /* too harmless to panic */
10703 }
10704 addReplyBulkCString(c,"appendfsync");
10705 addReplyBulkCString(c,policy);
10706 matches++;
10707 }
a34e0a25 10708 if (stringmatch(pattern,"save",0)) {
10709 sds buf = sdsempty();
10710 int j;
10711
10712 for (j = 0; j < server.saveparamslen; j++) {
10713 buf = sdscatprintf(buf,"%ld %d",
10714 server.saveparams[j].seconds,
10715 server.saveparams[j].changes);
10716 if (j != server.saveparamslen-1)
10717 buf = sdscatlen(buf," ",1);
10718 }
10719 addReplyBulkCString(c,"save");
10720 addReplyBulkCString(c,buf);
10721 sdsfree(buf);
10722 matches++;
10723 }
500ece7c 10724 decrRefCount(o);
10725 lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",matches*2);
10726}
10727
10728static void configCommand(redisClient *c) {
10729 if (!strcasecmp(c->argv[1]->ptr,"set")) {
10730 if (c->argc != 4) goto badarity;
10731 configSetCommand(c);
10732 } else if (!strcasecmp(c->argv[1]->ptr,"get")) {
10733 if (c->argc != 3) goto badarity;
10734 configGetCommand(c);
10735 } else if (!strcasecmp(c->argv[1]->ptr,"resetstat")) {
10736 if (c->argc != 2) goto badarity;
10737 server.stat_numcommands = 0;
10738 server.stat_numconnections = 0;
10739 server.stat_expiredkeys = 0;
10740 server.stat_starttime = time(NULL);
10741 addReply(c,shared.ok);
10742 } else {
10743 addReplySds(c,sdscatprintf(sdsempty(),
10744 "-ERR CONFIG subcommand must be one of GET, SET, RESETSTAT\r\n"));
10745 }
10746 return;
10747
10748badarity:
10749 addReplySds(c,sdscatprintf(sdsempty(),
10750 "-ERR Wrong number of arguments for CONFIG %s\r\n",
10751 (char*) c->argv[1]->ptr));
10752}
10753
befec3cd 10754/* =========================== Pubsub implementation ======================== */
10755
ffc6b7f8 10756static void freePubsubPattern(void *p) {
10757 pubsubPattern *pat = p;
10758
10759 decrRefCount(pat->pattern);
10760 zfree(pat);
10761}
10762
10763static int listMatchPubsubPattern(void *a, void *b) {
10764 pubsubPattern *pa = a, *pb = b;
10765
10766 return (pa->client == pb->client) &&
bf028098 10767 (equalStringObjects(pa->pattern,pb->pattern));
ffc6b7f8 10768}
10769
10770/* Subscribe a client to a channel. Returns 1 if the operation succeeded, or
10771 * 0 if the client was already subscribed to that channel. */
10772static int pubsubSubscribeChannel(redisClient *c, robj *channel) {
befec3cd 10773 struct dictEntry *de;
10774 list *clients = NULL;
10775 int retval = 0;
10776
ffc6b7f8 10777 /* Add the channel to the client -> channels hash table */
10778 if (dictAdd(c->pubsub_channels,channel,NULL) == DICT_OK) {
befec3cd 10779 retval = 1;
ffc6b7f8 10780 incrRefCount(channel);
10781 /* Add the client to the channel -> list of clients hash table */
10782 de = dictFind(server.pubsub_channels,channel);
befec3cd 10783 if (de == NULL) {
10784 clients = listCreate();
ffc6b7f8 10785 dictAdd(server.pubsub_channels,channel,clients);
10786 incrRefCount(channel);
befec3cd 10787 } else {
10788 clients = dictGetEntryVal(de);
10789 }
10790 listAddNodeTail(clients,c);
10791 }
10792 /* Notify the client */
10793 addReply(c,shared.mbulk3);
10794 addReply(c,shared.subscribebulk);
ffc6b7f8 10795 addReplyBulk(c,channel);
482b672d 10796 addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns));
befec3cd 10797 return retval;
10798}
10799
ffc6b7f8 10800/* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
10801 * 0 if the client was not subscribed to the specified channel. */
10802static int pubsubUnsubscribeChannel(redisClient *c, robj *channel, int notify) {
befec3cd 10803 struct dictEntry *de;
10804 list *clients;
10805 listNode *ln;
10806 int retval = 0;
10807
ffc6b7f8 10808 /* Remove the channel from the client -> channels hash table */
10809 incrRefCount(channel); /* channel may be just a pointer to the same object
201037f5 10810 we have in the hash tables. Protect it... */
ffc6b7f8 10811 if (dictDelete(c->pubsub_channels,channel) == DICT_OK) {
befec3cd 10812 retval = 1;
ffc6b7f8 10813 /* Remove the client from the channel -> clients list hash table */
10814 de = dictFind(server.pubsub_channels,channel);
befec3cd 10815 assert(de != NULL);
10816 clients = dictGetEntryVal(de);
10817 ln = listSearchKey(clients,c);
10818 assert(ln != NULL);
10819 listDelNode(clients,ln);
ff767a75 10820 if (listLength(clients) == 0) {
10821 /* Free the list and associated hash entry at all if this was
10822 * the latest client, so that it will be possible to abuse
ffc6b7f8 10823 * Redis PUBSUB creating millions of channels. */
10824 dictDelete(server.pubsub_channels,channel);
ff767a75 10825 }
befec3cd 10826 }
10827 /* Notify the client */
10828 if (notify) {
10829 addReply(c,shared.mbulk3);
10830 addReply(c,shared.unsubscribebulk);
ffc6b7f8 10831 addReplyBulk(c,channel);
482b672d 10832 addReplyLongLong(c,dictSize(c->pubsub_channels)+
ffc6b7f8 10833 listLength(c->pubsub_patterns));
10834
10835 }
10836 decrRefCount(channel); /* it is finally safe to release it */
10837 return retval;
10838}
10839
10840/* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the clinet was already subscribed to that pattern. */
10841static int pubsubSubscribePattern(redisClient *c, robj *pattern) {
10842 int retval = 0;
10843
10844 if (listSearchKey(c->pubsub_patterns,pattern) == NULL) {
10845 retval = 1;
10846 pubsubPattern *pat;
10847 listAddNodeTail(c->pubsub_patterns,pattern);
10848 incrRefCount(pattern);
10849 pat = zmalloc(sizeof(*pat));
10850 pat->pattern = getDecodedObject(pattern);
10851 pat->client = c;
10852 listAddNodeTail(server.pubsub_patterns,pat);
10853 }
10854 /* Notify the client */
10855 addReply(c,shared.mbulk3);
10856 addReply(c,shared.psubscribebulk);
10857 addReplyBulk(c,pattern);
482b672d 10858 addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns));
ffc6b7f8 10859 return retval;
10860}
10861
10862/* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
10863 * 0 if the client was not subscribed to the specified channel. */
10864static int pubsubUnsubscribePattern(redisClient *c, robj *pattern, int notify) {
10865 listNode *ln;
10866 pubsubPattern pat;
10867 int retval = 0;
10868
10869 incrRefCount(pattern); /* Protect the object. May be the same we remove */
10870 if ((ln = listSearchKey(c->pubsub_patterns,pattern)) != NULL) {
10871 retval = 1;
10872 listDelNode(c->pubsub_patterns,ln);
10873 pat.client = c;
10874 pat.pattern = pattern;
10875 ln = listSearchKey(server.pubsub_patterns,&pat);
10876 listDelNode(server.pubsub_patterns,ln);
10877 }
10878 /* Notify the client */
10879 if (notify) {
10880 addReply(c,shared.mbulk3);
10881 addReply(c,shared.punsubscribebulk);
10882 addReplyBulk(c,pattern);
482b672d 10883 addReplyLongLong(c,dictSize(c->pubsub_channels)+
ffc6b7f8 10884 listLength(c->pubsub_patterns));
befec3cd 10885 }
ffc6b7f8 10886 decrRefCount(pattern);
befec3cd 10887 return retval;
10888}
10889
ffc6b7f8 10890/* Unsubscribe from all the channels. Return the number of channels the
10891 * client was subscribed from. */
10892static int pubsubUnsubscribeAllChannels(redisClient *c, int notify) {
10893 dictIterator *di = dictGetIterator(c->pubsub_channels);
befec3cd 10894 dictEntry *de;
10895 int count = 0;
10896
10897 while((de = dictNext(di)) != NULL) {
ffc6b7f8 10898 robj *channel = dictGetEntryKey(de);
befec3cd 10899
ffc6b7f8 10900 count += pubsubUnsubscribeChannel(c,channel,notify);
befec3cd 10901 }
10902 dictReleaseIterator(di);
10903 return count;
10904}
10905
ffc6b7f8 10906/* Unsubscribe from all the patterns. Return the number of patterns the
10907 * client was subscribed from. */
10908static int pubsubUnsubscribeAllPatterns(redisClient *c, int notify) {
10909 listNode *ln;
10910 listIter li;
10911 int count = 0;
10912
10913 listRewind(c->pubsub_patterns,&li);
10914 while ((ln = listNext(&li)) != NULL) {
10915 robj *pattern = ln->value;
10916
10917 count += pubsubUnsubscribePattern(c,pattern,notify);
10918 }
10919 return count;
10920}
10921
befec3cd 10922/* Publish a message */
ffc6b7f8 10923static int pubsubPublishMessage(robj *channel, robj *message) {
befec3cd 10924 int receivers = 0;
10925 struct dictEntry *de;
ffc6b7f8 10926 listNode *ln;
10927 listIter li;
befec3cd 10928
ffc6b7f8 10929 /* Send to clients listening for that channel */
10930 de = dictFind(server.pubsub_channels,channel);
befec3cd 10931 if (de) {
10932 list *list = dictGetEntryVal(de);
10933 listNode *ln;
10934 listIter li;
10935
10936 listRewind(list,&li);
10937 while ((ln = listNext(&li)) != NULL) {
10938 redisClient *c = ln->value;
10939
10940 addReply(c,shared.mbulk3);
10941 addReply(c,shared.messagebulk);
ffc6b7f8 10942 addReplyBulk(c,channel);
befec3cd 10943 addReplyBulk(c,message);
10944 receivers++;
10945 }
10946 }
ffc6b7f8 10947 /* Send to clients listening to matching channels */
10948 if (listLength(server.pubsub_patterns)) {
10949 listRewind(server.pubsub_patterns,&li);
10950 channel = getDecodedObject(channel);
10951 while ((ln = listNext(&li)) != NULL) {
10952 pubsubPattern *pat = ln->value;
10953
10954 if (stringmatchlen((char*)pat->pattern->ptr,
10955 sdslen(pat->pattern->ptr),
10956 (char*)channel->ptr,
10957 sdslen(channel->ptr),0)) {
c8d0ea0e 10958 addReply(pat->client,shared.mbulk4);
10959 addReply(pat->client,shared.pmessagebulk);
10960 addReplyBulk(pat->client,pat->pattern);
ffc6b7f8 10961 addReplyBulk(pat->client,channel);
10962 addReplyBulk(pat->client,message);
10963 receivers++;
10964 }
10965 }
10966 decrRefCount(channel);
10967 }
befec3cd 10968 return receivers;
10969}
10970
10971static void subscribeCommand(redisClient *c) {
10972 int j;
10973
10974 for (j = 1; j < c->argc; j++)
ffc6b7f8 10975 pubsubSubscribeChannel(c,c->argv[j]);
befec3cd 10976}
10977
10978static void unsubscribeCommand(redisClient *c) {
10979 if (c->argc == 1) {
ffc6b7f8 10980 pubsubUnsubscribeAllChannels(c,1);
10981 return;
10982 } else {
10983 int j;
10984
10985 for (j = 1; j < c->argc; j++)
10986 pubsubUnsubscribeChannel(c,c->argv[j],1);
10987 }
10988}
10989
10990static void psubscribeCommand(redisClient *c) {
10991 int j;
10992
10993 for (j = 1; j < c->argc; j++)
10994 pubsubSubscribePattern(c,c->argv[j]);
10995}
10996
10997static void punsubscribeCommand(redisClient *c) {
10998 if (c->argc == 1) {
10999 pubsubUnsubscribeAllPatterns(c,1);
befec3cd 11000 return;
11001 } else {
11002 int j;
11003
11004 for (j = 1; j < c->argc; j++)
ffc6b7f8 11005 pubsubUnsubscribePattern(c,c->argv[j],1);
befec3cd 11006 }
11007}
11008
11009static void publishCommand(redisClient *c) {
11010 int receivers = pubsubPublishMessage(c->argv[1],c->argv[2]);
482b672d 11011 addReplyLongLong(c,receivers);
befec3cd 11012}
11013
37ab76c9 11014/* ===================== WATCH (CAS alike for MULTI/EXEC) ===================
11015 *
11016 * The implementation uses a per-DB hash table mapping keys to list of clients
11017 * WATCHing those keys, so that given a key that is going to be modified
11018 * we can mark all the associated clients as dirty.
11019 *
11020 * Also every client contains a list of WATCHed keys so that's possible to
11021 * un-watch such keys when the client is freed or when UNWATCH is called. */
11022
11023/* In the client->watched_keys list we need to use watchedKey structures
11024 * as in order to identify a key in Redis we need both the key name and the
11025 * DB */
11026typedef struct watchedKey {
11027 robj *key;
11028 redisDb *db;
11029} watchedKey;
11030
11031/* Watch for the specified key */
11032static void watchForKey(redisClient *c, robj *key) {
11033 list *clients = NULL;
11034 listIter li;
11035 listNode *ln;
11036 watchedKey *wk;
11037
11038 /* Check if we are already watching for this key */
11039 listRewind(c->watched_keys,&li);
11040 while((ln = listNext(&li))) {
11041 wk = listNodeValue(ln);
11042 if (wk->db == c->db && equalStringObjects(key,wk->key))
11043 return; /* Key already watched */
11044 }
11045 /* This key is not already watched in this DB. Let's add it */
11046 clients = dictFetchValue(c->db->watched_keys,key);
11047 if (!clients) {
11048 clients = listCreate();
11049 dictAdd(c->db->watched_keys,key,clients);
11050 incrRefCount(key);
11051 }
11052 listAddNodeTail(clients,c);
11053 /* Add the new key to the lits of keys watched by this client */
11054 wk = zmalloc(sizeof(*wk));
11055 wk->key = key;
11056 wk->db = c->db;
11057 incrRefCount(key);
11058 listAddNodeTail(c->watched_keys,wk);
11059}
11060
11061/* Unwatch all the keys watched by this client. To clean the EXEC dirty
11062 * flag is up to the caller. */
11063static void unwatchAllKeys(redisClient *c) {
11064 listIter li;
11065 listNode *ln;
11066
11067 if (listLength(c->watched_keys) == 0) return;
11068 listRewind(c->watched_keys,&li);
11069 while((ln = listNext(&li))) {
11070 list *clients;
11071 watchedKey *wk;
11072
11073 /* Lookup the watched key -> clients list and remove the client
11074 * from the list */
11075 wk = listNodeValue(ln);
11076 clients = dictFetchValue(wk->db->watched_keys, wk->key);
11077 assert(clients != NULL);
11078 listDelNode(clients,listSearchKey(clients,c));
11079 /* Kill the entry at all if this was the only client */
11080 if (listLength(clients) == 0)
11081 dictDelete(wk->db->watched_keys, wk->key);
11082 /* Remove this watched key from the client->watched list */
11083 listDelNode(c->watched_keys,ln);
11084 decrRefCount(wk->key);
11085 zfree(wk);
11086 }
11087}
11088
ca3f830b 11089/* "Touch" a key, so that if this key is being WATCHed by some client the
37ab76c9 11090 * next EXEC will fail. */
11091static void touchWatchedKey(redisDb *db, robj *key) {
11092 list *clients;
11093 listIter li;
11094 listNode *ln;
11095
11096 if (dictSize(db->watched_keys) == 0) return;
11097 clients = dictFetchValue(db->watched_keys, key);
11098 if (!clients) return;
11099
11100 /* Mark all the clients watching this key as REDIS_DIRTY_CAS */
11101 /* Check if we are already watching for this key */
11102 listRewind(clients,&li);
11103 while((ln = listNext(&li))) {
11104 redisClient *c = listNodeValue(ln);
11105
11106 c->flags |= REDIS_DIRTY_CAS;
11107 }
11108}
11109
9b30e1a2 11110/* On FLUSHDB or FLUSHALL all the watched keys that are present before the
11111 * flush but will be deleted as effect of the flushing operation should
11112 * be touched. "dbid" is the DB that's getting the flush. -1 if it is
11113 * a FLUSHALL operation (all the DBs flushed). */
11114static void touchWatchedKeysOnFlush(int dbid) {
11115 listIter li1, li2;
11116 listNode *ln;
11117
11118 /* For every client, check all the waited keys */
11119 listRewind(server.clients,&li1);
11120 while((ln = listNext(&li1))) {
11121 redisClient *c = listNodeValue(ln);
11122 listRewind(c->watched_keys,&li2);
11123 while((ln = listNext(&li2))) {
11124 watchedKey *wk = listNodeValue(ln);
11125
11126 /* For every watched key matching the specified DB, if the
11127 * key exists, mark the client as dirty, as the key will be
11128 * removed. */
11129 if (dbid == -1 || wk->db->id == dbid) {
09241813 11130 if (dictFind(wk->db->dict, wk->key->ptr) != NULL)
9b30e1a2 11131 c->flags |= REDIS_DIRTY_CAS;
11132 }
11133 }
11134 }
11135}
11136
37ab76c9 11137static void watchCommand(redisClient *c) {
11138 int j;
11139
6531c94d 11140 if (c->flags & REDIS_MULTI) {
11141 addReplySds(c,sdsnew("-ERR WATCH inside MULTI is not allowed\r\n"));
11142 return;
11143 }
37ab76c9 11144 for (j = 1; j < c->argc; j++)
11145 watchForKey(c,c->argv[j]);
11146 addReply(c,shared.ok);
11147}
11148
11149static void unwatchCommand(redisClient *c) {
11150 unwatchAllKeys(c);
11151 c->flags &= (~REDIS_DIRTY_CAS);
11152 addReply(c,shared.ok);
11153}
11154
7f957c92 11155/* ================================= Debugging ============================== */
11156
ba798261 11157/* Compute the sha1 of string at 's' with 'len' bytes long.
11158 * The SHA1 is then xored againt the string pointed by digest.
11159 * Since xor is commutative, this operation is used in order to
11160 * "add" digests relative to unordered elements.
11161 *
11162 * So digest(a,b,c,d) will be the same of digest(b,a,c,d) */
11163static void xorDigest(unsigned char *digest, void *ptr, size_t len) {
11164 SHA1_CTX ctx;
11165 unsigned char hash[20], *s = ptr;
11166 int j;
11167
11168 SHA1Init(&ctx);
11169 SHA1Update(&ctx,s,len);
11170 SHA1Final(hash,&ctx);
11171
11172 for (j = 0; j < 20; j++)
11173 digest[j] ^= hash[j];
11174}
11175
11176static void xorObjectDigest(unsigned char *digest, robj *o) {
11177 o = getDecodedObject(o);
11178 xorDigest(digest,o->ptr,sdslen(o->ptr));
11179 decrRefCount(o);
11180}
11181
11182/* This function instead of just computing the SHA1 and xoring it
11183 * against diget, also perform the digest of "digest" itself and
11184 * replace the old value with the new one.
11185 *
11186 * So the final digest will be:
11187 *
11188 * digest = SHA1(digest xor SHA1(data))
11189 *
11190 * This function is used every time we want to preserve the order so
11191 * that digest(a,b,c,d) will be different than digest(b,c,d,a)
11192 *
11193 * Also note that mixdigest("foo") followed by mixdigest("bar")
11194 * will lead to a different digest compared to "fo", "obar".
11195 */
11196static void mixDigest(unsigned char *digest, void *ptr, size_t len) {
11197 SHA1_CTX ctx;
11198 char *s = ptr;
11199
11200 xorDigest(digest,s,len);
11201 SHA1Init(&ctx);
11202 SHA1Update(&ctx,digest,20);
11203 SHA1Final(digest,&ctx);
11204}
11205
11206static void mixObjectDigest(unsigned char *digest, robj *o) {
11207 o = getDecodedObject(o);
11208 mixDigest(digest,o->ptr,sdslen(o->ptr));
11209 decrRefCount(o);
11210}
11211
11212/* Compute the dataset digest. Since keys, sets elements, hashes elements
11213 * are not ordered, we use a trick: every aggregate digest is the xor
11214 * of the digests of their elements. This way the order will not change
11215 * the result. For list instead we use a feedback entering the output digest
11216 * as input in order to ensure that a different ordered list will result in
11217 * a different digest. */
11218static void computeDatasetDigest(unsigned char *final) {
11219 unsigned char digest[20];
11220 char buf[128];
11221 dictIterator *di = NULL;
11222 dictEntry *de;
11223 int j;
11224 uint32_t aux;
11225
11226 memset(final,0,20); /* Start with a clean result */
11227
11228 for (j = 0; j < server.dbnum; j++) {
11229 redisDb *db = server.db+j;
11230
11231 if (dictSize(db->dict) == 0) continue;
11232 di = dictGetIterator(db->dict);
11233
11234 /* hash the DB id, so the same dataset moved in a different
11235 * DB will lead to a different digest */
11236 aux = htonl(j);
11237 mixDigest(final,&aux,sizeof(aux));
11238
11239 /* Iterate this DB writing every entry */
11240 while((de = dictNext(di)) != NULL) {
09241813 11241 sds key;
11242 robj *keyobj, *o;
ba798261 11243 time_t expiretime;
11244
11245 memset(digest,0,20); /* This key-val digest */
11246 key = dictGetEntryKey(de);
09241813 11247 keyobj = createStringObject(key,sdslen(key));
11248
11249 mixDigest(digest,key,sdslen(key));
11250
11251 /* Make sure the key is loaded if VM is active */
11252 o = lookupKeyRead(db,keyobj);
cbae1d34 11253
ba798261 11254 aux = htonl(o->type);
11255 mixDigest(digest,&aux,sizeof(aux));
09241813 11256 expiretime = getExpire(db,keyobj);
ba798261 11257
11258 /* Save the key and associated value */
11259 if (o->type == REDIS_STRING) {
11260 mixObjectDigest(digest,o);
11261 } else if (o->type == REDIS_LIST) {
003f0840
PN
11262 listTypeIterator *li = listTypeInitIterator(o,0,REDIS_TAIL);
11263 listTypeEntry entry;
11264 while(listTypeNext(li,&entry)) {
11265 robj *eleobj = listTypeGet(&entry);
ba798261 11266 mixObjectDigest(digest,eleobj);
dc845730 11267 decrRefCount(eleobj);
ba798261 11268 }
003f0840 11269 listTypeReleaseIterator(li);
ba798261 11270 } else if (o->type == REDIS_SET) {
11271 dict *set = o->ptr;
11272 dictIterator *di = dictGetIterator(set);
11273 dictEntry *de;
11274
11275 while((de = dictNext(di)) != NULL) {
11276 robj *eleobj = dictGetEntryKey(de);
11277
11278 xorObjectDigest(digest,eleobj);
11279 }
11280 dictReleaseIterator(di);
11281 } else if (o->type == REDIS_ZSET) {
11282 zset *zs = o->ptr;
11283 dictIterator *di = dictGetIterator(zs->dict);
11284 dictEntry *de;
11285
11286 while((de = dictNext(di)) != NULL) {
11287 robj *eleobj = dictGetEntryKey(de);
11288 double *score = dictGetEntryVal(de);
11289 unsigned char eledigest[20];
11290
11291 snprintf(buf,sizeof(buf),"%.17g",*score);
11292 memset(eledigest,0,20);
11293 mixObjectDigest(eledigest,eleobj);
11294 mixDigest(eledigest,buf,strlen(buf));
11295 xorDigest(digest,eledigest,20);
11296 }
11297 dictReleaseIterator(di);
11298 } else if (o->type == REDIS_HASH) {
d1578a33 11299 hashTypeIterator *hi;
ba798261 11300 robj *obj;
11301
d1578a33
PN
11302 hi = hashTypeInitIterator(o);
11303 while (hashTypeNext(hi) != REDIS_ERR) {
ba798261 11304 unsigned char eledigest[20];
11305
11306 memset(eledigest,0,20);
d1578a33 11307 obj = hashTypeCurrent(hi,REDIS_HASH_KEY);
ba798261 11308 mixObjectDigest(eledigest,obj);
11309 decrRefCount(obj);
d1578a33 11310 obj = hashTypeCurrent(hi,REDIS_HASH_VALUE);
ba798261 11311 mixObjectDigest(eledigest,obj);
11312 decrRefCount(obj);
11313 xorDigest(digest,eledigest,20);
11314 }
d1578a33 11315 hashTypeReleaseIterator(hi);
ba798261 11316 } else {
11317 redisPanic("Unknown object type");
11318 }
ba798261 11319 /* If the key has an expire, add it to the mix */
11320 if (expiretime != -1) xorDigest(digest,"!!expire!!",10);
11321 /* We can finally xor the key-val digest to the final digest */
11322 xorDigest(final,digest,20);
09241813 11323 decrRefCount(keyobj);
ba798261 11324 }
11325 dictReleaseIterator(di);
11326 }
11327}
11328
7f957c92 11329static void debugCommand(redisClient *c) {
11330 if (!strcasecmp(c->argv[1]->ptr,"segfault")) {
11331 *((char*)-1) = 'x';
210e29f7 11332 } else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
11333 if (rdbSave(server.dbfilename) != REDIS_OK) {
11334 addReply(c,shared.err);
11335 return;
11336 }
11337 emptyDb();
11338 if (rdbLoad(server.dbfilename) != REDIS_OK) {
11339 addReply(c,shared.err);
11340 return;
11341 }
11342 redisLog(REDIS_WARNING,"DB reloaded by DEBUG RELOAD");
11343 addReply(c,shared.ok);
71c2b467 11344 } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) {
11345 emptyDb();
11346 if (loadAppendOnlyFile(server.appendfilename) != REDIS_OK) {
11347 addReply(c,shared.err);
11348 return;
11349 }
11350 redisLog(REDIS_WARNING,"Append Only File loaded by DEBUG LOADAOF");
11351 addReply(c,shared.ok);
333298da 11352 } else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
09241813 11353 dictEntry *de = dictFind(c->db->dict,c->argv[2]->ptr);
11354 robj *val;
333298da 11355
11356 if (!de) {
11357 addReply(c,shared.nokeyerr);
11358 return;
11359 }
333298da 11360 val = dictGetEntryVal(de);
560db612 11361 if (!server.vm_enabled || (val->storage == REDIS_VM_MEMORY ||
11362 val->storage == REDIS_VM_SWAPPING)) {
07efaf74 11363 char *strenc;
11364 char buf[128];
11365
11366 if (val->encoding < (sizeof(strencoding)/sizeof(char*))) {
11367 strenc = strencoding[val->encoding];
11368 } else {
11369 snprintf(buf,64,"unknown encoding %d\n", val->encoding);
11370 strenc = buf;
11371 }
ace06542 11372 addReplySds(c,sdscatprintf(sdsempty(),
09241813 11373 "+Value at:%p refcount:%d "
07efaf74 11374 "encoding:%s serializedlength:%lld\r\n",
09241813 11375 (void*)val, val->refcount,
07efaf74 11376 strenc, (long long) rdbSavedObjectLen(val,NULL)));
ace06542 11377 } else {
560db612 11378 vmpointer *vp = (vmpointer*) val;
ace06542 11379 addReplySds(c,sdscatprintf(sdsempty(),
09241813 11380 "+Value swapped at: page %llu "
ace06542 11381 "using %llu pages\r\n",
09241813 11382 (unsigned long long) vp->page,
560db612 11383 (unsigned long long) vp->usedpages));
ace06542 11384 }
78ebe4c8 11385 } else if (!strcasecmp(c->argv[1]->ptr,"swapin") && c->argc == 3) {
11386 lookupKeyRead(c->db,c->argv[2]);
11387 addReply(c,shared.ok);
7d30035d 11388 } else if (!strcasecmp(c->argv[1]->ptr,"swapout") && c->argc == 3) {
09241813 11389 dictEntry *de = dictFind(c->db->dict,c->argv[2]->ptr);
11390 robj *val;
560db612 11391 vmpointer *vp;
7d30035d 11392
11393 if (!server.vm_enabled) {
11394 addReplySds(c,sdsnew("-ERR Virtual Memory is disabled\r\n"));
11395 return;
11396 }
11397 if (!de) {
11398 addReply(c,shared.nokeyerr);
11399 return;
11400 }
7d30035d 11401 val = dictGetEntryVal(de);
4ef8de8a 11402 /* Swap it */
560db612 11403 if (val->storage != REDIS_VM_MEMORY) {
7d30035d 11404 addReplySds(c,sdsnew("-ERR This key is not in memory\r\n"));
560db612 11405 } else if (val->refcount != 1) {
11406 addReplySds(c,sdsnew("-ERR Object is shared\r\n"));
11407 } else if ((vp = vmSwapObjectBlocking(val)) != NULL) {
11408 dictGetEntryVal(de) = vp;
7d30035d 11409 addReply(c,shared.ok);
11410 } else {
11411 addReply(c,shared.err);
11412 }
59305dc7 11413 } else if (!strcasecmp(c->argv[1]->ptr,"populate") && c->argc == 3) {
11414 long keys, j;
11415 robj *key, *val;
11416 char buf[128];
11417
11418 if (getLongFromObjectOrReply(c, c->argv[2], &keys, NULL) != REDIS_OK)
11419 return;
11420 for (j = 0; j < keys; j++) {
11421 snprintf(buf,sizeof(buf),"key:%lu",j);
11422 key = createStringObject(buf,strlen(buf));
11423 if (lookupKeyRead(c->db,key) != NULL) {
11424 decrRefCount(key);
11425 continue;
11426 }
11427 snprintf(buf,sizeof(buf),"value:%lu",j);
11428 val = createStringObject(buf,strlen(buf));
09241813 11429 dbAdd(c->db,key,val);
11430 decrRefCount(key);
59305dc7 11431 }
11432 addReply(c,shared.ok);
ba798261 11433 } else if (!strcasecmp(c->argv[1]->ptr,"digest") && c->argc == 2) {
11434 unsigned char digest[20];
11435 sds d = sdsnew("+");
11436 int j;
11437
11438 computeDatasetDigest(digest);
11439 for (j = 0; j < 20; j++)
11440 d = sdscatprintf(d, "%02x",digest[j]);
11441
11442 d = sdscatlen(d,"\r\n",2);
11443 addReplySds(c,d);
7f957c92 11444 } else {
333298da 11445 addReplySds(c,sdsnew(
bdcb92f2 11446 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPIN <key>|SWAPOUT <key>|RELOAD]\r\n"));
7f957c92 11447 }
11448}
56906eef 11449
6c96ba7d 11450static void _redisAssert(char *estr, char *file, int line) {
dfc5e96c 11451 redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
fdfb02e7 11452 redisLog(REDIS_WARNING,"==> %s:%d '%s' is not true",file,line,estr);
dfc5e96c 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
c651fd9e 11459static void _redisPanic(char *msg, char *file, int line) {
11460 redisLog(REDIS_WARNING,"!!! Software Failure. Press left mouse button to continue");
17772754 11461 redisLog(REDIS_WARNING,"Guru Meditation: %s #%s:%d",msg,file,line);
c651fd9e 11462#ifdef HAVE_BACKTRACE
11463 redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
11464 *((char*)-1) = 'x';
11465#endif
11466}
11467
bcfc686d 11468/* =================================== Main! ================================ */
56906eef 11469
bcfc686d 11470#ifdef __linux__
11471int linuxOvercommitMemoryValue(void) {
11472 FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
11473 char buf[64];
56906eef 11474
bcfc686d 11475 if (!fp) return -1;
11476 if (fgets(buf,64,fp) == NULL) {
11477 fclose(fp);
11478 return -1;
11479 }
11480 fclose(fp);
56906eef 11481
bcfc686d 11482 return atoi(buf);
11483}
11484
11485void linuxOvercommitMemoryWarning(void) {
11486 if (linuxOvercommitMemoryValue() == 0) {
7ccd2d0a 11487 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 11488 }
11489}
11490#endif /* __linux__ */
11491
11492static void daemonize(void) {
11493 int fd;
11494 FILE *fp;
11495
11496 if (fork() != 0) exit(0); /* parent exits */
11497 setsid(); /* create a new session */
11498
11499 /* Every output goes to /dev/null. If Redis is daemonized but
11500 * the 'logfile' is set to 'stdout' in the configuration file
11501 * it will not log at all. */
11502 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
11503 dup2(fd, STDIN_FILENO);
11504 dup2(fd, STDOUT_FILENO);
11505 dup2(fd, STDERR_FILENO);
11506 if (fd > STDERR_FILENO) close(fd);
11507 }
11508 /* Try to write the pid file */
11509 fp = fopen(server.pidfile,"w");
11510 if (fp) {
11511 fprintf(fp,"%d\n",getpid());
11512 fclose(fp);
56906eef 11513 }
56906eef 11514}
11515
42ab0172 11516static void version() {
8a3b0d2d 11517 printf("Redis server version %s (%s:%d)\n", REDIS_VERSION,
11518 REDIS_GIT_SHA1, atoi(REDIS_GIT_DIRTY) > 0);
42ab0172
AO
11519 exit(0);
11520}
11521
723fb69b
AO
11522static void usage() {
11523 fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
e9409273 11524 fprintf(stderr," ./redis-server - (read config from stdin)\n");
723fb69b
AO
11525 exit(1);
11526}
11527
bcfc686d 11528int main(int argc, char **argv) {
9651a787 11529 time_t start;
11530
bcfc686d 11531 initServerConfig();
1a132bbc 11532 sortCommandTable();
bcfc686d 11533 if (argc == 2) {
44efe66e 11534 if (strcmp(argv[1], "-v") == 0 ||
11535 strcmp(argv[1], "--version") == 0) version();
11536 if (strcmp(argv[1], "--help") == 0) usage();
bcfc686d 11537 resetServerSaveParams();
11538 loadServerConfig(argv[1]);
723fb69b
AO
11539 } else if ((argc > 2)) {
11540 usage();
bcfc686d 11541 } else {
11542 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'");
11543 }
bcfc686d 11544 if (server.daemonize) daemonize();
71c54b21 11545 initServer();
bcfc686d 11546 redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
11547#ifdef __linux__
11548 linuxOvercommitMemoryWarning();
11549#endif
9651a787 11550 start = time(NULL);
bcfc686d 11551 if (server.appendonly) {
11552 if (loadAppendOnlyFile(server.appendfilename) == REDIS_OK)
9651a787 11553 redisLog(REDIS_NOTICE,"DB loaded from append only file: %ld seconds",time(NULL)-start);
bcfc686d 11554 } else {
11555 if (rdbLoad(server.dbfilename) == REDIS_OK)
9651a787 11556 redisLog(REDIS_NOTICE,"DB loaded from disk: %ld seconds",time(NULL)-start);
bcfc686d 11557 }
bcfc686d 11558 redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
d5d55fc3 11559 aeSetBeforeSleepProc(server.el,beforeSleep);
bcfc686d 11560 aeMain(server.el);
11561 aeDeleteEventLoop(server.el);
11562 return 0;
11563}
11564
11565/* ============================= Backtrace support ========================= */
11566
11567#ifdef HAVE_BACKTRACE
11568static char *findFuncName(void *pointer, unsigned long *offset);
11569
56906eef 11570static void *getMcontextEip(ucontext_t *uc) {
11571#if defined(__FreeBSD__)
11572 return (void*) uc->uc_mcontext.mc_eip;
11573#elif defined(__dietlibc__)
11574 return (void*) uc->uc_mcontext.eip;
06db1f50 11575#elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
da0a1620 11576 #if __x86_64__
11577 return (void*) uc->uc_mcontext->__ss.__rip;
11578 #else
56906eef 11579 return (void*) uc->uc_mcontext->__ss.__eip;
da0a1620 11580 #endif
06db1f50 11581#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
cb7e07cc 11582 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
06db1f50 11583 return (void*) uc->uc_mcontext->__ss.__rip;
cbc59b38 11584 #else
11585 return (void*) uc->uc_mcontext->__ss.__eip;
e0a62c7f 11586 #endif
54bac49d 11587#elif defined(__i386__) || defined(__X86_64__) || defined(__x86_64__)
c04c9ac9 11588 return (void*) uc->uc_mcontext.gregs[REG_EIP]; /* Linux 32/64 bit */
b91cf5ef 11589#elif defined(__ia64__) /* Linux IA64 */
11590 return (void*) uc->uc_mcontext.sc_ip;
11591#else
11592 return NULL;
56906eef 11593#endif
11594}
11595
11596static void segvHandler(int sig, siginfo_t *info, void *secret) {
11597 void *trace[100];
11598 char **messages = NULL;
11599 int i, trace_size = 0;
11600 unsigned long offset=0;
56906eef 11601 ucontext_t *uc = (ucontext_t*) secret;
1c85b79f 11602 sds infostring;
56906eef 11603 REDIS_NOTUSED(info);
11604
11605 redisLog(REDIS_WARNING,
11606 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION, sig);
1c85b79f 11607 infostring = genRedisInfoString();
11608 redisLog(REDIS_WARNING, "%s",infostring);
11609 /* It's not safe to sdsfree() the returned string under memory
11610 * corruption conditions. Let it leak as we are going to abort */
e0a62c7f 11611
56906eef 11612 trace_size = backtrace(trace, 100);
de96dbfe 11613 /* overwrite sigaction with caller's address */
b91cf5ef 11614 if (getMcontextEip(uc) != NULL) {
11615 trace[1] = getMcontextEip(uc);
11616 }
56906eef 11617 messages = backtrace_symbols(trace, trace_size);
fe3bbfbe 11618
d76412d1 11619 for (i=1; i<trace_size; ++i) {
56906eef 11620 char *fn = findFuncName(trace[i], &offset), *p;
11621
11622 p = strchr(messages[i],'+');
11623 if (!fn || (p && ((unsigned long)strtol(p+1,NULL,10)) < offset)) {
11624 redisLog(REDIS_WARNING,"%s", messages[i]);
11625 } else {
11626 redisLog(REDIS_WARNING,"%d redis-server %p %s + %d", i, trace[i], fn, (unsigned int)offset);
11627 }
11628 }
b177fd30 11629 /* free(messages); Don't call free() with possibly corrupted memory. */
478c2c6f 11630 _exit(0);
fe3bbfbe 11631}
56906eef 11632
fab43727 11633static void sigtermHandler(int sig) {
11634 REDIS_NOTUSED(sig);
b58ba105 11635
fab43727 11636 redisLog(REDIS_WARNING,"SIGTERM received, scheduling shutting down...");
11637 server.shutdown_asap = 1;
b58ba105
AM
11638}
11639
56906eef 11640static void setupSigSegvAction(void) {
11641 struct sigaction act;
11642
11643 sigemptyset (&act.sa_mask);
11644 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
11645 * is used. Otherwise, sa_handler is used */
11646 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
11647 act.sa_sigaction = segvHandler;
11648 sigaction (SIGSEGV, &act, NULL);
11649 sigaction (SIGBUS, &act, NULL);
12fea928 11650 sigaction (SIGFPE, &act, NULL);
11651 sigaction (SIGILL, &act, NULL);
11652 sigaction (SIGBUS, &act, NULL);
b58ba105
AM
11653
11654 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
fab43727 11655 act.sa_handler = sigtermHandler;
b58ba105 11656 sigaction (SIGTERM, &act, NULL);
e65fdc78 11657 return;
56906eef 11658}
e65fdc78 11659
bcfc686d 11660#include "staticsymbols.h"
11661/* This function try to convert a pointer into a function name. It's used in
11662 * oreder to provide a backtrace under segmentation fault that's able to
11663 * display functions declared as static (otherwise the backtrace is useless). */
11664static char *findFuncName(void *pointer, unsigned long *offset){
11665 int i, ret = -1;
11666 unsigned long off, minoff = 0;
ed9b544e 11667
bcfc686d 11668 /* Try to match against the Symbol with the smallest offset */
11669 for (i=0; symsTable[i].pointer; i++) {
11670 unsigned long lp = (unsigned long) pointer;
0bc03378 11671
bcfc686d 11672 if (lp != (unsigned long)-1 && lp >= symsTable[i].pointer) {
11673 off=lp-symsTable[i].pointer;
11674 if (ret < 0 || off < minoff) {
11675 minoff=off;
11676 ret=i;
11677 }
11678 }
0bc03378 11679 }
bcfc686d 11680 if (ret == -1) return NULL;
11681 *offset = minoff;
11682 return symsTable[ret].name;
0bc03378 11683}
bcfc686d 11684#else /* HAVE_BACKTRACE */
11685static void setupSigSegvAction(void) {
0bc03378 11686}
bcfc686d 11687#endif /* HAVE_BACKTRACE */
0bc03378 11688
ed9b544e 11689
ed9b544e 11690
bcfc686d 11691/* The End */
11692
11693
ed9b544e 11694