]> git.saurik.com Git - redis.git/blame - redis.c
fix behavior for out-of-range negative end index on ZREMRANGEBYRANK
[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 */
ba798261 79#include "sha1.h" /* SHA1 is used for DEBUG DIGEST */
ed9b544e 80
81/* Error codes */
82#define REDIS_OK 0
83#define REDIS_ERR -1
84
85/* Static server configuration */
86#define REDIS_SERVERPORT 6379 /* TCP port */
87#define REDIS_MAXIDLETIME (60*5) /* default client timeout */
6208b3a7 88#define REDIS_IOBUF_LEN 1024
ed9b544e 89#define REDIS_LOADBUF_LEN 1024
248ea310 90#define REDIS_STATIC_ARGS 8
ed9b544e 91#define REDIS_DEFAULT_DBNUM 16
92#define REDIS_CONFIGLINE_MAX 1024
93#define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
94#define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
8ca3e9d1 95#define REDIS_EXPIRELOOKUPS_PER_CRON 10 /* lookup 10 expires per loop */
6f376729 96#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
2895e862 97#define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
98
99/* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
100#define REDIS_WRITEV_THRESHOLD 3
101/* Max number of iovecs used for each writev call */
102#define REDIS_WRITEV_IOVEC_COUNT 256
ed9b544e 103
104/* Hash table parameters */
105#define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
ed9b544e 106
107/* Command flags */
3fd78bcd 108#define REDIS_CMD_BULK 1 /* Bulk write command */
109#define REDIS_CMD_INLINE 2 /* Inline command */
110/* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
111 this flags will return an error when the 'maxmemory' option is set in the
112 config file and the server is using more than maxmemory bytes of memory.
113 In short this commands are denied on low memory conditions. */
114#define REDIS_CMD_DENYOOM 4
4005fef1 115#define REDIS_CMD_FORCE_REPLICATION 8 /* Force replication even if dirty is 0 */
ed9b544e 116
117/* Object types */
118#define REDIS_STRING 0
119#define REDIS_LIST 1
120#define REDIS_SET 2
1812e024 121#define REDIS_ZSET 3
122#define REDIS_HASH 4
560db612 123#define REDIS_VMPOINTER 8
f78fd11b 124
5234952b 125/* Objects encoding. Some kind of objects like Strings and Hashes can be
126 * internally represented in multiple ways. The 'encoding' field of the object
127 * is set to one of this fields for this object. */
c7d9d662
PN
128#define REDIS_ENCODING_RAW 0 /* Raw representation */
129#define REDIS_ENCODING_INT 1 /* Encoded as integer */
130#define REDIS_ENCODING_HT 2 /* Encoded as hash table */
131#define REDIS_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
7e79de54 132#define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
c7d9d662 133#define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
942a3961 134
07efaf74 135static char* strencoding[] = {
7e79de54 136 "raw", "int", "hashtable", "zipmap", "linkedlist", "ziplist"
07efaf74 137};
138
f78fd11b 139/* Object types only used for dumping to disk */
bb32ede5 140#define REDIS_EXPIRETIME 253
ed9b544e 141#define REDIS_SELECTDB 254
142#define REDIS_EOF 255
143
f78fd11b 144/* Defines related to the dump file format. To store 32 bits lengths for short
145 * keys requires a lot of space, so we check the most significant 2 bits of
146 * the first byte to interpreter the length:
147 *
148 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
149 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
150 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
a4d1ba9a 151 * 11|000000 this means: specially encoded object will follow. The six bits
152 * number specify the kind of object that follows.
153 * See the REDIS_RDB_ENC_* defines.
f78fd11b 154 *
10c43610 155 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
156 * values, will fit inside. */
f78fd11b 157#define REDIS_RDB_6BITLEN 0
158#define REDIS_RDB_14BITLEN 1
159#define REDIS_RDB_32BITLEN 2
17be1a4a 160#define REDIS_RDB_ENCVAL 3
f78fd11b 161#define REDIS_RDB_LENERR UINT_MAX
162
a4d1ba9a 163/* When a length of a string object stored on disk has the first two bits
164 * set, the remaining two bits specify a special encoding for the object
165 * accordingly to the following defines: */
166#define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
167#define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
168#define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
774e3047 169#define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
a4d1ba9a 170
75680a3c 171/* Virtual memory object->where field. */
172#define REDIS_VM_MEMORY 0 /* The object is on memory */
173#define REDIS_VM_SWAPPED 1 /* The object is on disk */
174#define REDIS_VM_SWAPPING 2 /* Redis is swapping this object on disk */
175#define REDIS_VM_LOADING 3 /* Redis is loading this object from disk */
176
06224fec 177/* Virtual memory static configuration stuff.
178 * Check vmFindContiguousPages() to know more about this magic numbers. */
179#define REDIS_VM_MAX_NEAR_PAGES 65536
180#define REDIS_VM_MAX_RANDOM_JUMP 4096
92f8e882 181#define REDIS_VM_MAX_THREADS 32
bcaa7a4f 182#define REDIS_THREAD_STACK_SIZE (1024*1024*4)
f6c0bba8 183/* The following is the *percentage* of completed I/O jobs to process when the
184 * handelr is called. While Virtual Memory I/O operations are performed by
185 * threads, this operations must be processed by the main thread when completed
186 * in order to take effect. */
c953f24b 187#define REDIS_MAX_COMPLETED_JOBS_PROCESSED 1
06224fec 188
ed9b544e 189/* Client flags */
d5d55fc3 190#define REDIS_SLAVE 1 /* This client is a slave server */
191#define REDIS_MASTER 2 /* This client is a master server */
192#define REDIS_MONITOR 4 /* This client is a slave monitor, see MONITOR */
193#define REDIS_MULTI 8 /* This client is in a MULTI context */
194#define REDIS_BLOCKED 16 /* The client is waiting in a blocking operation */
195#define REDIS_IO_WAIT 32 /* The client is waiting for Virtual Memory I/O */
37ab76c9 196#define REDIS_DIRTY_CAS 64 /* Watched keys modified. EXEC will fail. */
ed9b544e 197
40d224a9 198/* Slave replication state - slave side */
ed9b544e 199#define REDIS_REPL_NONE 0 /* No active replication */
200#define REDIS_REPL_CONNECT 1 /* Must connect to master */
201#define REDIS_REPL_CONNECTED 2 /* Connected to master */
202
40d224a9 203/* Slave replication state - from the point of view of master
204 * Note that in SEND_BULK and ONLINE state the slave receives new updates
205 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
206 * to start the next background saving in order to send updates to it. */
207#define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
208#define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
209#define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
210#define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
211
ed9b544e 212/* List related stuff */
213#define REDIS_HEAD 0
214#define REDIS_TAIL 1
215
216/* Sort operations */
217#define REDIS_SORT_GET 0
443c6409 218#define REDIS_SORT_ASC 1
219#define REDIS_SORT_DESC 2
ed9b544e 220#define REDIS_SORTKEY_MAX 1024
221
222/* Log levels */
223#define REDIS_DEBUG 0
f870935d 224#define REDIS_VERBOSE 1
225#define REDIS_NOTICE 2
226#define REDIS_WARNING 3
ed9b544e 227
228/* Anti-warning macro... */
229#define REDIS_NOTUSED(V) ((void) V)
230
6b47e12e 231#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
232#define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
ed9b544e 233
48f0308a 234/* Append only defines */
235#define APPENDFSYNC_NO 0
236#define APPENDFSYNC_ALWAYS 1
237#define APPENDFSYNC_EVERYSEC 2
238
d0686e07 239/* Zip structure related defaults */
cbba7dd7 240#define REDIS_HASH_MAX_ZIPMAP_ENTRIES 64
241#define REDIS_HASH_MAX_ZIPMAP_VALUE 512
d0686e07
PN
242#define REDIS_LIST_MAX_ZIPLIST_ENTRIES 1024
243#define REDIS_LIST_MAX_ZIPLIST_VALUE 32
cbba7dd7 244
dfc5e96c 245/* We can print the stacktrace, so our assert is defined this way: */
478c2c6f 246#define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),_exit(1)))
c651fd9e 247#define redisPanic(_e) _redisPanic(#_e,__FILE__,__LINE__),_exit(1)
6c96ba7d 248static void _redisAssert(char *estr, char *file, int line);
c651fd9e 249static void _redisPanic(char *msg, char *file, int line);
dfc5e96c 250
ed9b544e 251/*================================= Data types ============================== */
252
253/* A redis object, that is a type able to hold a string / list / set */
75680a3c 254
75680a3c 255/* The actual Redis Object */
ed9b544e 256typedef struct redisObject {
560db612 257 unsigned type:4;
258 unsigned storage:2; /* REDIS_VM_MEMORY or REDIS_VM_SWAPPING */
259 unsigned encoding:4;
260 unsigned lru:22; /* lru time (relative to server.lruclock) */
ed9b544e 261 int refcount;
560db612 262 void *ptr;
dedff272 263 /* VM fields are only allocated if VM is active, otherwise the
75680a3c 264 * object allocation function will just allocate
265 * sizeof(redisObjct) minus sizeof(redisObjectVM), so using
266 * Redis without VM active will not have any overhead. */
ed9b544e 267} robj;
268
560db612 269/* The VM pointer structure - identifies an object in the swap file.
270 *
271 * This object is stored in place of the value
272 * object in the main key->value hash table representing a database.
273 * Note that the first fields (type, storage) are the same as the redisObject
274 * structure so that vmPointer strucuters can be accessed even when casted
275 * as redisObject structures.
276 *
277 * This is useful as we don't know if a value object is or not on disk, but we
169dd6b7 278 * are always able to read obj->storage to check this. For vmPointer
560db612 279 * structures "type" is set to REDIS_VMPOINTER (even if without this field
280 * is still possible to check the kind of object from the value of 'storage').*/
281typedef struct vmPointer {
282 unsigned type:4;
283 unsigned storage:2; /* REDIS_VM_SWAPPED or REDIS_VM_LOADING */
284 unsigned notused:26;
285 unsigned int vtype; /* type of the object stored in the swap file */
286 off_t page; /* the page at witch the object is stored on disk */
287 off_t usedpages; /* number of pages used on disk */
288} vmpointer;
289
dfc5e96c 290/* Macro used to initalize a Redis object allocated on the stack.
291 * Note that this macro is taken near the structure definition to make sure
292 * we'll update it when the structure is changed, to avoid bugs like
293 * bug #85 introduced exactly in this way. */
294#define initStaticStringObject(_var,_ptr) do { \
295 _var.refcount = 1; \
296 _var.type = REDIS_STRING; \
297 _var.encoding = REDIS_ENCODING_RAW; \
298 _var.ptr = _ptr; \
560db612 299 _var.storage = REDIS_VM_MEMORY; \
dfc5e96c 300} while(0);
301
3305306f 302typedef struct redisDb {
4409877e 303 dict *dict; /* The keyspace for this DB */
304 dict *expires; /* Timeout of keys with a timeout set */
37ab76c9 305 dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) */
d5d55fc3 306 dict *io_keys; /* Keys with clients waiting for VM I/O */
37ab76c9 307 dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
3305306f 308 int id;
309} redisDb;
310
6e469882 311/* Client MULTI/EXEC state */
312typedef struct multiCmd {
313 robj **argv;
314 int argc;
315 struct redisCommand *cmd;
316} multiCmd;
317
318typedef struct multiState {
319 multiCmd *commands; /* Array of MULTI commands */
320 int count; /* Total number of MULTI commands */
321} multiState;
322
ed9b544e 323/* With multiplexing we need to take per-clinet state.
324 * Clients are taken in a liked list. */
325typedef struct redisClient {
326 int fd;
3305306f 327 redisDb *db;
ed9b544e 328 int dictid;
329 sds querybuf;
e8a74421 330 robj **argv, **mbargv;
331 int argc, mbargc;
40d224a9 332 int bulklen; /* bulk read len. -1 if not in bulk read mode */
e8a74421 333 int multibulk; /* multi bulk command format active */
ed9b544e 334 list *reply;
335 int sentlen;
336 time_t lastinteraction; /* time of the last interaction, used for timeout */
d5d55fc3 337 int flags; /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
40d224a9 338 int slaveseldb; /* slave selected db, if this client is a slave */
339 int authenticated; /* when requirepass is non-NULL */
340 int replstate; /* replication state if this is a slave */
341 int repldbfd; /* replication DB file descriptor */
6e469882 342 long repldboff; /* replication DB file offset */
40d224a9 343 off_t repldbsize; /* replication DB file size */
6e469882 344 multiState mstate; /* MULTI/EXEC state */
37ab76c9 345 robj **blocking_keys; /* The key we are waiting to terminate a blocking
4409877e 346 * operation such as BLPOP. Otherwise NULL. */
37ab76c9 347 int blocking_keys_num; /* Number of blocking keys */
4409877e 348 time_t blockingto; /* Blocking operation timeout. If UNIX current time
349 * is >= blockingto then the operation timed out. */
92f8e882 350 list *io_keys; /* Keys this client is waiting to be loaded from the
351 * swap file in order to continue. */
37ab76c9 352 list *watched_keys; /* Keys WATCHED for MULTI/EXEC CAS */
ffc6b7f8 353 dict *pubsub_channels; /* channels a client is interested in (SUBSCRIBE) */
354 list *pubsub_patterns; /* patterns a client is interested in (SUBSCRIBE) */
ed9b544e 355} redisClient;
356
357struct saveparam {
358 time_t seconds;
359 int changes;
360};
361
362/* Global server state structure */
363struct redisServer {
364 int port;
365 int fd;
3305306f 366 redisDb *db;
ed9b544e 367 long long dirty; /* changes to DB from the last save */
368 list *clients;
87eca727 369 list *slaves, *monitors;
ed9b544e 370 char neterr[ANET_ERR_LEN];
371 aeEventLoop *el;
372 int cronloops; /* number of times the cron function run */
373 list *objfreelist; /* A list of freed objects to avoid malloc() */
374 time_t lastsave; /* Unix time of last save succeeede */
ed9b544e 375 /* Fields used only for stats */
376 time_t stat_starttime; /* server start time */
377 long long stat_numcommands; /* number of processed commands */
378 long long stat_numconnections; /* number of connections received */
2a6a2ed1 379 long long stat_expiredkeys; /* number of expired keys */
ed9b544e 380 /* Configuration */
381 int verbosity;
382 int glueoutputbuf;
383 int maxidletime;
384 int dbnum;
385 int daemonize;
44b38ef4 386 int appendonly;
48f0308a 387 int appendfsync;
38db9171 388 int no_appendfsync_on_rewrite;
fab43727 389 int shutdown_asap;
48f0308a 390 time_t lastfsync;
44b38ef4 391 int appendfd;
392 int appendseldb;
ed329fcf 393 char *pidfile;
9f3c422c 394 pid_t bgsavechildpid;
9d65a1bb 395 pid_t bgrewritechildpid;
396 sds bgrewritebuf; /* buffer taken by parent during oppend only rewrite */
28ed1f33 397 sds aofbuf; /* AOF buffer, written before entering the event loop */
ed9b544e 398 struct saveparam *saveparams;
399 int saveparamslen;
400 char *logfile;
401 char *bindaddr;
402 char *dbfilename;
44b38ef4 403 char *appendfilename;
abcb223e 404 char *requirepass;
121f70cf 405 int rdbcompression;
8ca3e9d1 406 int activerehashing;
ed9b544e 407 /* Replication related */
408 int isslave;
d0ccebcf 409 char *masterauth;
ed9b544e 410 char *masterhost;
411 int masterport;
40d224a9 412 redisClient *master; /* client that is master for this slave */
ed9b544e 413 int replstate;
285add55 414 unsigned int maxclients;
4ef8de8a 415 unsigned long long maxmemory;
d5d55fc3 416 unsigned int blpop_blocked_clients;
417 unsigned int vm_blocked_clients;
ed9b544e 418 /* Sort parameters - qsort_r() is only available under BSD so we
419 * have to take this state global, in order to pass it to sortCompare() */
420 int sort_desc;
421 int sort_alpha;
422 int sort_bypattern;
75680a3c 423 /* Virtual memory configuration */
424 int vm_enabled;
054e426d 425 char *vm_swap_file;
75680a3c 426 off_t vm_page_size;
427 off_t vm_pages;
4ef8de8a 428 unsigned long long vm_max_memory;
d0686e07 429 /* Zip structure config */
cbba7dd7 430 size_t hash_max_zipmap_entries;
431 size_t hash_max_zipmap_value;
d0686e07
PN
432 size_t list_max_ziplist_entries;
433 size_t list_max_ziplist_value;
75680a3c 434 /* Virtual memory state */
435 FILE *vm_fp;
436 int vm_fd;
437 off_t vm_next_page; /* Next probably empty page */
438 off_t vm_near_pages; /* Number of pages allocated sequentially */
06224fec 439 unsigned char *vm_bitmap; /* Bitmap of free/used pages */
3a66edc7 440 time_t unixtime; /* Unix time sampled every second. */
92f8e882 441 /* Virtual memory I/O threads stuff */
92f8e882 442 /* An I/O thread process an element taken from the io_jobs queue and
996cb5f7 443 * put the result of the operation in the io_done list. While the
444 * job is being processed, it's put on io_processing queue. */
445 list *io_newjobs; /* List of VM I/O jobs yet to be processed */
446 list *io_processing; /* List of VM I/O jobs being processed */
447 list *io_processed; /* List of VM I/O jobs already processed */
d5d55fc3 448 list *io_ready_clients; /* Clients ready to be unblocked. All keys loaded */
996cb5f7 449 pthread_mutex_t io_mutex; /* lock to access io_jobs/io_done/io_thread_job */
a5819310 450 pthread_mutex_t obj_freelist_mutex; /* safe redis objects creation/free */
451 pthread_mutex_t io_swapfile_mutex; /* So we can lseek + write */
bcaa7a4f 452 pthread_attr_t io_threads_attr; /* attributes for threads creation */
92f8e882 453 int io_active_threads; /* Number of running I/O threads */
454 int vm_max_threads; /* Max number of I/O threads running at the same time */
996cb5f7 455 /* Our main thread is blocked on the event loop, locking for sockets ready
456 * to be read or written, so when a threaded I/O operation is ready to be
457 * processed by the main thread, the I/O thread will use a unix pipe to
458 * awake the main thread. The followings are the two pipe FDs. */
459 int io_ready_pipe_read;
460 int io_ready_pipe_write;
7d98e08c 461 /* Virtual memory stats */
462 unsigned long long vm_stats_used_pages;
463 unsigned long long vm_stats_swapped_objects;
464 unsigned long long vm_stats_swapouts;
465 unsigned long long vm_stats_swapins;
befec3cd 466 /* Pubsub */
ffc6b7f8 467 dict *pubsub_channels; /* Map channels to list of subscribed clients */
468 list *pubsub_patterns; /* A list of pubsub_patterns */
befec3cd 469 /* Misc */
b9bc0eef 470 FILE *devnull;
560db612 471 unsigned lruclock:22; /* clock incrementing every minute, for LRU */
472 unsigned lruclock_padding:10;
ed9b544e 473};
474
ffc6b7f8 475typedef struct pubsubPattern {
476 redisClient *client;
477 robj *pattern;
478} pubsubPattern;
479
ed9b544e 480typedef void redisCommandProc(redisClient *c);
ca1788b5 481typedef void redisVmPreloadProc(redisClient *c, struct redisCommand *cmd, int argc, robj **argv);
ed9b544e 482struct redisCommand {
483 char *name;
484 redisCommandProc *proc;
485 int arity;
486 int flags;
76583ea4
PN
487 /* Use a function to determine which keys need to be loaded
488 * in the background prior to executing this command. Takes precedence
489 * over vm_firstkey and others, ignored when NULL */
ca1788b5 490 redisVmPreloadProc *vm_preload_proc;
7c775e09 491 /* What keys should be loaded in background when calling this command? */
492 int vm_firstkey; /* The first argument that's a key (0 = no keys) */
493 int vm_lastkey; /* THe last argument that's a key */
494 int vm_keystep; /* The step between first and last key */
ed9b544e 495};
496
de96dbfe 497struct redisFunctionSym {
498 char *name;
56906eef 499 unsigned long pointer;
de96dbfe 500};
501
ed9b544e 502typedef struct _redisSortObject {
503 robj *obj;
504 union {
505 double score;
506 robj *cmpobj;
507 } u;
508} redisSortObject;
509
510typedef struct _redisSortOperation {
511 int type;
512 robj *pattern;
513} redisSortOperation;
514
6b47e12e 515/* ZSETs use a specialized version of Skiplists */
516
517typedef struct zskiplistNode {
518 struct zskiplistNode **forward;
e3870fab 519 struct zskiplistNode *backward;
912b9165 520 unsigned int *span;
6b47e12e 521 double score;
522 robj *obj;
523} zskiplistNode;
524
525typedef struct zskiplist {
e3870fab 526 struct zskiplistNode *header, *tail;
d13f767c 527 unsigned long length;
6b47e12e 528 int level;
529} zskiplist;
530
1812e024 531typedef struct zset {
532 dict *dict;
6b47e12e 533 zskiplist *zsl;
1812e024 534} zset;
535
6b47e12e 536/* Our shared "common" objects */
537
05df7621 538#define REDIS_SHARED_INTEGERS 10000
ed9b544e 539struct sharedObjectsStruct {
23d3a5fe 540 robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *cnegone, *pong, *space,
6e469882 541 *colon, *nullbulk, *nullmultibulk, *queued,
c937aa89 542 *emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr,
543 *outofrangeerr, *plus,
ed9b544e 544 *select0, *select1, *select2, *select3, *select4,
befec3cd 545 *select5, *select6, *select7, *select8, *select9,
c8d0ea0e 546 *messagebulk, *pmessagebulk, *subscribebulk, *unsubscribebulk, *mbulk3,
547 *mbulk4, *psubscribebulk, *punsubscribebulk,
548 *integers[REDIS_SHARED_INTEGERS];
ed9b544e 549} shared;
550
a7866db6 551/* Global vars that are actally used as constants. The following double
552 * values are used for double on-disk serialization, and are initialized
553 * at runtime to avoid strange compiler optimizations. */
554
555static double R_Zero, R_PosInf, R_NegInf, R_Nan;
556
92f8e882 557/* VM threaded I/O request message */
b9bc0eef 558#define REDIS_IOJOB_LOAD 0 /* Load from disk to memory */
559#define REDIS_IOJOB_PREPARE_SWAP 1 /* Compute needed pages */
560#define REDIS_IOJOB_DO_SWAP 2 /* Swap from memory to disk */
d5d55fc3 561typedef struct iojob {
996cb5f7 562 int type; /* Request type, REDIS_IOJOB_* */
b9bc0eef 563 redisDb *db;/* Redis database */
92f8e882 564 robj *key; /* This I/O request is about swapping this key */
560db612 565 robj *id; /* Unique identifier of this job:
566 this is the object to swap for REDIS_IOREQ_*_SWAP, or the
567 vmpointer objct for REDIS_IOREQ_LOAD. */
b9bc0eef 568 robj *val; /* the value to swap for REDIS_IOREQ_*_SWAP, otherwise this
92f8e882 569 * field is populated by the I/O thread for REDIS_IOREQ_LOAD. */
570 off_t page; /* Swap page where to read/write the object */
248ea310 571 off_t pages; /* Swap pages needed to save object. PREPARE_SWAP return val */
996cb5f7 572 int canceled; /* True if this command was canceled by blocking side of VM */
573 pthread_t thread; /* ID of the thread processing this entry */
574} iojob;
92f8e882 575
ed9b544e 576/*================================ Prototypes =============================== */
7c4fc71c 577char *redisGitSHA1(void);
578char *redisGitDirty(void);
ed9b544e 579
580static void freeStringObject(robj *o);
581static void freeListObject(robj *o);
582static void freeSetObject(robj *o);
583static void decrRefCount(void *o);
584static robj *createObject(int type, void *ptr);
585static void freeClient(redisClient *c);
f78fd11b 586static int rdbLoad(char *filename);
ed9b544e 587static void addReply(redisClient *c, robj *obj);
588static void addReplySds(redisClient *c, sds s);
589static void incrRefCount(robj *o);
f78fd11b 590static int rdbSaveBackground(char *filename);
ed9b544e 591static robj *createStringObject(char *ptr, size_t len);
4ef8de8a 592static robj *dupStringObject(robj *o);
248ea310 593static void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc);
dd142b9c 594static void replicationFeedMonitors(list *monitors, int dictid, robj **argv, int argc);
28ed1f33 595static void flushAppendOnlyFile(void);
44b38ef4 596static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc);
ed9b544e 597static int syncWithMaster(void);
05df7621 598static robj *tryObjectEncoding(robj *o);
9d65a1bb 599static robj *getDecodedObject(robj *o);
3305306f 600static int removeExpire(redisDb *db, robj *key);
601static int expireIfNeeded(redisDb *db, robj *key);
602static int deleteIfVolatile(redisDb *db, robj *key);
09241813 603static int dbDelete(redisDb *db, robj *key);
bb32ede5 604static time_t getExpire(redisDb *db, robj *key);
605static int setExpire(redisDb *db, robj *key, time_t when);
a3b21203 606static void updateSlavesWaitingBgsave(int bgsaveerr);
3fd78bcd 607static void freeMemoryIfNeeded(void);
de96dbfe 608static int processCommand(redisClient *c);
56906eef 609static void setupSigSegvAction(void);
a3b21203 610static void rdbRemoveTempFile(pid_t childpid);
9d65a1bb 611static void aofRemoveTempFile(pid_t childpid);
0ea663ea 612static size_t stringObjectLen(robj *o);
638e42ac 613static void processInputBuffer(redisClient *c);
6b47e12e 614static zskiplist *zslCreate(void);
fd8ccf44 615static void zslFree(zskiplist *zsl);
2b59cfdf 616static void zslInsert(zskiplist *zsl, double score, robj *obj);
2895e862 617static void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask);
6e469882 618static void initClientMultiState(redisClient *c);
619static void freeClientMultiState(redisClient *c);
620static void queueMultiCommand(redisClient *c, struct redisCommand *cmd);
b0d8747d 621static void unblockClientWaitingData(redisClient *c);
4409877e 622static int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele);
75680a3c 623static void vmInit(void);
a35ddf12 624static void vmMarkPagesFree(off_t page, off_t count);
560db612 625static robj *vmLoadObject(robj *o);
626static robj *vmPreviewObject(robj *o);
a69a0c9c 627static int vmSwapOneObjectBlocking(void);
628static int vmSwapOneObjectThreaded(void);
7e69548d 629static int vmCanSwapOut(void);
a5819310 630static int tryFreeOneObjectFromFreelist(void);
996cb5f7 631static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask);
632static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata, int mask);
633static void vmCancelThreadedIOJob(robj *o);
b9bc0eef 634static void lockThreadedIO(void);
635static void unlockThreadedIO(void);
636static int vmSwapObjectThreaded(robj *key, robj *val, redisDb *db);
637static void freeIOJob(iojob *j);
638static void queueIOJob(iojob *j);
a5819310 639static int vmWriteObjectOnSwap(robj *o, off_t page);
640static robj *vmReadObjectFromSwap(off_t page, int type);
054e426d 641static void waitEmptyIOJobsQueue(void);
642static void vmReopenSwapFile(void);
970e10bb 643static int vmFreePage(off_t page);
ca1788b5 644static void zunionInterBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv);
3805e04f 645static void execBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv);
0a6f3f0f 646static int blockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd);
d5d55fc3 647static int dontWaitForSwappedKey(redisClient *c, robj *key);
648static void handleClientsBlockedOnSwappedKey(redisDb *db, robj *key);
649static void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask);
650static struct redisCommand *lookupCommand(char *name);
651static void call(redisClient *c, struct redisCommand *cmd);
652static void resetClient(redisClient *c);
ada386b2 653static void convertToRealHash(robj *o);
003f0840 654static void listTypeConvert(robj *o, int enc);
ffc6b7f8 655static int pubsubUnsubscribeAllChannels(redisClient *c, int notify);
656static int pubsubUnsubscribeAllPatterns(redisClient *c, int notify);
657static void freePubsubPattern(void *p);
658static int listMatchPubsubPattern(void *a, void *b);
659static int compareStringObjects(robj *a, robj *b);
bf028098 660static int equalStringObjects(robj *a, robj *b);
befec3cd 661static void usage();
8f63ddca 662static int rewriteAppendOnlyFileBackground(void);
560db612 663static vmpointer *vmSwapObjectBlocking(robj *val);
fab43727 664static int prepareForShutdown();
37ab76c9 665static void touchWatchedKey(redisDb *db, robj *key);
9b30e1a2 666static void touchWatchedKeysOnFlush(int dbid);
37ab76c9 667static void unwatchAllKeys(redisClient *c);
ed9b544e 668
abcb223e 669static void authCommand(redisClient *c);
ed9b544e 670static void pingCommand(redisClient *c);
671static void echoCommand(redisClient *c);
672static void setCommand(redisClient *c);
673static void setnxCommand(redisClient *c);
526d00a5 674static void setexCommand(redisClient *c);
ed9b544e 675static void getCommand(redisClient *c);
676static void delCommand(redisClient *c);
677static void existsCommand(redisClient *c);
678static void incrCommand(redisClient *c);
679static void decrCommand(redisClient *c);
680static void incrbyCommand(redisClient *c);
681static void decrbyCommand(redisClient *c);
682static void selectCommand(redisClient *c);
683static void randomkeyCommand(redisClient *c);
684static void keysCommand(redisClient *c);
685static void dbsizeCommand(redisClient *c);
686static void lastsaveCommand(redisClient *c);
687static void saveCommand(redisClient *c);
688static void bgsaveCommand(redisClient *c);
9d65a1bb 689static void bgrewriteaofCommand(redisClient *c);
ed9b544e 690static void shutdownCommand(redisClient *c);
691static void moveCommand(redisClient *c);
692static void renameCommand(redisClient *c);
693static void renamenxCommand(redisClient *c);
694static void lpushCommand(redisClient *c);
695static void rpushCommand(redisClient *c);
dedff272
RP
696static void lpushxCommand(redisClient *c);
697static void rpushxCommand(redisClient *c);
698static void linsertCommand(redisClient *c);
ed9b544e 699static void lpopCommand(redisClient *c);
700static void rpopCommand(redisClient *c);
701static void llenCommand(redisClient *c);
702static void lindexCommand(redisClient *c);
703static void lrangeCommand(redisClient *c);
704static void ltrimCommand(redisClient *c);
705static void typeCommand(redisClient *c);
706static void lsetCommand(redisClient *c);
707static void saddCommand(redisClient *c);
708static void sremCommand(redisClient *c);
a4460ef4 709static void smoveCommand(redisClient *c);
ed9b544e 710static void sismemberCommand(redisClient *c);
711static void scardCommand(redisClient *c);
12fea928 712static void spopCommand(redisClient *c);
2abb95a9 713static void srandmemberCommand(redisClient *c);
ed9b544e 714static void sinterCommand(redisClient *c);
715static void sinterstoreCommand(redisClient *c);
40d224a9 716static void sunionCommand(redisClient *c);
717static void sunionstoreCommand(redisClient *c);
f4f56e1d 718static void sdiffCommand(redisClient *c);
719static void sdiffstoreCommand(redisClient *c);
ed9b544e 720static void syncCommand(redisClient *c);
721static void flushdbCommand(redisClient *c);
722static void flushallCommand(redisClient *c);
723static void sortCommand(redisClient *c);
724static void lremCommand(redisClient *c);
0f5f7e9a 725static void rpoplpushcommand(redisClient *c);
ed9b544e 726static void infoCommand(redisClient *c);
70003d28 727static void mgetCommand(redisClient *c);
87eca727 728static void monitorCommand(redisClient *c);
3305306f 729static void expireCommand(redisClient *c);
802e8373 730static void expireatCommand(redisClient *c);
f6b141c5 731static void getsetCommand(redisClient *c);
fd88489a 732static void ttlCommand(redisClient *c);
321b0e13 733static void slaveofCommand(redisClient *c);
7f957c92 734static void debugCommand(redisClient *c);
f6b141c5 735static void msetCommand(redisClient *c);
736static void msetnxCommand(redisClient *c);
fd8ccf44 737static void zaddCommand(redisClient *c);
7db723ad 738static void zincrbyCommand(redisClient *c);
cc812361 739static void zrangeCommand(redisClient *c);
50c55df5 740static void zrangebyscoreCommand(redisClient *c);
f44dd428 741static void zcountCommand(redisClient *c);
e3870fab 742static void zrevrangeCommand(redisClient *c);
3c41331e 743static void zcardCommand(redisClient *c);
1b7106e7 744static void zremCommand(redisClient *c);
6e333bbe 745static void zscoreCommand(redisClient *c);
1807985b 746static void zremrangebyscoreCommand(redisClient *c);
6e469882 747static void multiCommand(redisClient *c);
748static void execCommand(redisClient *c);
18b6cb76 749static void discardCommand(redisClient *c);
4409877e 750static void blpopCommand(redisClient *c);
751static void brpopCommand(redisClient *c);
4b00bebd 752static void appendCommand(redisClient *c);
39191553 753static void substrCommand(redisClient *c);
69d95c3e 754static void zrankCommand(redisClient *c);
798d9e55 755static void zrevrankCommand(redisClient *c);
978c2c94 756static void hsetCommand(redisClient *c);
1f1c7695 757static void hsetnxCommand(redisClient *c);
978c2c94 758static void hgetCommand(redisClient *c);
09aeb579
PN
759static void hmsetCommand(redisClient *c);
760static void hmgetCommand(redisClient *c);
07efaf74 761static void hdelCommand(redisClient *c);
92b27fe9 762static void hlenCommand(redisClient *c);
9212eafd 763static void zremrangebyrankCommand(redisClient *c);
5d373da9 764static void zunionstoreCommand(redisClient *c);
765static void zinterstoreCommand(redisClient *c);
78409a0f 766static void hkeysCommand(redisClient *c);
767static void hvalsCommand(redisClient *c);
768static void hgetallCommand(redisClient *c);
a86f14b1 769static void hexistsCommand(redisClient *c);
500ece7c 770static void configCommand(redisClient *c);
01426b05 771static void hincrbyCommand(redisClient *c);
befec3cd 772static void subscribeCommand(redisClient *c);
773static void unsubscribeCommand(redisClient *c);
ffc6b7f8 774static void psubscribeCommand(redisClient *c);
775static void punsubscribeCommand(redisClient *c);
befec3cd 776static void publishCommand(redisClient *c);
37ab76c9 777static void watchCommand(redisClient *c);
778static void unwatchCommand(redisClient *c);
f6b141c5 779
ed9b544e 780/*================================= Globals ================================= */
781
782/* Global vars */
783static struct redisServer server; /* server global state */
1a132bbc 784static struct redisCommand *commandTable;
1a132bbc 785static struct redisCommand readonlyCommandTable[] = {
76583ea4
PN
786 {"get",getCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
787 {"set",setCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,0,0,0},
788 {"setnx",setnxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,0,0,0},
526d00a5 789 {"setex",setexCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,0,0,0},
76583ea4
PN
790 {"append",appendCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
791 {"substr",substrCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
792 {"del",delCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
793 {"exists",existsCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
794 {"incr",incrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
795 {"decr",decrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
796 {"mget",mgetCommand,-2,REDIS_CMD_INLINE,NULL,1,-1,1},
797 {"rpush",rpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
798 {"lpush",lpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
dedff272
RP
799 {"rpushx",rpushxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
800 {"lpushx",lpushxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
801 {"linsert",linsertCommand,5,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
76583ea4
PN
802 {"rpop",rpopCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
803 {"lpop",lpopCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
804 {"brpop",brpopCommand,-3,REDIS_CMD_INLINE,NULL,1,1,1},
805 {"blpop",blpopCommand,-3,REDIS_CMD_INLINE,NULL,1,1,1},
806 {"llen",llenCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
807 {"lindex",lindexCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
808 {"lset",lsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
809 {"lrange",lrangeCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
810 {"ltrim",ltrimCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
811 {"lrem",lremCommand,4,REDIS_CMD_BULK,NULL,1,1,1},
812 {"rpoplpush",rpoplpushcommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,2,1},
813 {"sadd",saddCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
814 {"srem",sremCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
815 {"smove",smoveCommand,4,REDIS_CMD_BULK,NULL,1,2,1},
816 {"sismember",sismemberCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
817 {"scard",scardCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
818 {"spop",spopCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
819 {"srandmember",srandmemberCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
820 {"sinter",sinterCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,-1,1},
821 {"sinterstore",sinterstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,2,-1,1},
822 {"sunion",sunionCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,-1,1},
823 {"sunionstore",sunionstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,2,-1,1},
824 {"sdiff",sdiffCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,-1,1},
825 {"sdiffstore",sdiffstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,2,-1,1},
826 {"smembers",sinterCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
827 {"zadd",zaddCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
828 {"zincrby",zincrbyCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
829 {"zrem",zremCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
830 {"zremrangebyscore",zremrangebyscoreCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
831 {"zremrangebyrank",zremrangebyrankCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
5d373da9 832 {"zunionstore",zunionstoreCommand,-4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,zunionInterBlockClientOnSwappedKeys,0,0,0},
833 {"zinterstore",zinterstoreCommand,-4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,zunionInterBlockClientOnSwappedKeys,0,0,0},
76583ea4
PN
834 {"zrange",zrangeCommand,-4,REDIS_CMD_INLINE,NULL,1,1,1},
835 {"zrangebyscore",zrangebyscoreCommand,-4,REDIS_CMD_INLINE,NULL,1,1,1},
836 {"zcount",zcountCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
837 {"zrevrange",zrevrangeCommand,-4,REDIS_CMD_INLINE,NULL,1,1,1},
838 {"zcard",zcardCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
839 {"zscore",zscoreCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
840 {"zrank",zrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
841 {"zrevrank",zrevrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
842 {"hset",hsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
1f1c7695 843 {"hsetnx",hsetnxCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
09aeb579 844 {"hget",hgetCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
d33278d1 845 {"hmset",hmsetCommand,-4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
09aeb579 846 {"hmget",hmgetCommand,-3,REDIS_CMD_BULK,NULL,1,1,1},
01426b05 847 {"hincrby",hincrbyCommand,4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
76583ea4
PN
848 {"hdel",hdelCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
849 {"hlen",hlenCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
850 {"hkeys",hkeysCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
851 {"hvals",hvalsCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
852 {"hgetall",hgetallCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
4583c4f0 853 {"hexists",hexistsCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
76583ea4
PN
854 {"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
855 {"decrby",decrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
856 {"getset",getsetCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
857 {"mset",msetCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,-1,2},
858 {"msetnx",msetnxCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,-1,2},
859 {"randomkey",randomkeyCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
860 {"select",selectCommand,2,REDIS_CMD_INLINE,NULL,0,0,0},
861 {"move",moveCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
862 {"rename",renameCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
863 {"renamenx",renamenxCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
864 {"expire",expireCommand,3,REDIS_CMD_INLINE,NULL,0,0,0},
865 {"expireat",expireatCommand,3,REDIS_CMD_INLINE,NULL,0,0,0},
866 {"keys",keysCommand,2,REDIS_CMD_INLINE,NULL,0,0,0},
867 {"dbsize",dbsizeCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
868 {"auth",authCommand,2,REDIS_CMD_INLINE,NULL,0,0,0},
869 {"ping",pingCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
870 {"echo",echoCommand,2,REDIS_CMD_BULK,NULL,0,0,0},
871 {"save",saveCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
872 {"bgsave",bgsaveCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
873 {"bgrewriteaof",bgrewriteaofCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
874 {"shutdown",shutdownCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
875 {"lastsave",lastsaveCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
876 {"type",typeCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
877 {"multi",multiCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
3805e04f 878 {"exec",execCommand,1,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,execBlockClientOnSwappedKeys,0,0,0},
76583ea4
PN
879 {"discard",discardCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
880 {"sync",syncCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
881 {"flushdb",flushdbCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
882 {"flushall",flushallCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
883 {"sort",sortCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
884 {"info",infoCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
885 {"monitor",monitorCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
886 {"ttl",ttlCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
887 {"slaveof",slaveofCommand,3,REDIS_CMD_INLINE,NULL,0,0,0},
888 {"debug",debugCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
500ece7c 889 {"config",configCommand,-2,REDIS_CMD_BULK,NULL,0,0,0},
befec3cd 890 {"subscribe",subscribeCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
891 {"unsubscribe",unsubscribeCommand,-1,REDIS_CMD_INLINE,NULL,0,0,0},
ffc6b7f8 892 {"psubscribe",psubscribeCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
893 {"punsubscribe",punsubscribeCommand,-1,REDIS_CMD_INLINE,NULL,0,0,0},
4005fef1 894 {"publish",publishCommand,3,REDIS_CMD_BULK|REDIS_CMD_FORCE_REPLICATION,NULL,0,0,0},
37ab76c9 895 {"watch",watchCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
d55d5c5d 896 {"unwatch",unwatchCommand,1,REDIS_CMD_INLINE,NULL,0,0,0}
ed9b544e 897};
bcfc686d 898
ed9b544e 899/*============================ Utility functions ============================ */
900
901/* Glob-style pattern matching. */
500ece7c 902static int stringmatchlen(const char *pattern, int patternLen,
ed9b544e 903 const char *string, int stringLen, int nocase)
904{
905 while(patternLen) {
906 switch(pattern[0]) {
907 case '*':
908 while (pattern[1] == '*') {
909 pattern++;
910 patternLen--;
911 }
912 if (patternLen == 1)
913 return 1; /* match */
914 while(stringLen) {
915 if (stringmatchlen(pattern+1, patternLen-1,
916 string, stringLen, nocase))
917 return 1; /* match */
918 string++;
919 stringLen--;
920 }
921 return 0; /* no match */
922 break;
923 case '?':
924 if (stringLen == 0)
925 return 0; /* no match */
926 string++;
927 stringLen--;
928 break;
929 case '[':
930 {
931 int not, match;
932
933 pattern++;
934 patternLen--;
935 not = pattern[0] == '^';
936 if (not) {
937 pattern++;
938 patternLen--;
939 }
940 match = 0;
941 while(1) {
942 if (pattern[0] == '\\') {
943 pattern++;
944 patternLen--;
945 if (pattern[0] == string[0])
946 match = 1;
947 } else if (pattern[0] == ']') {
948 break;
949 } else if (patternLen == 0) {
950 pattern--;
951 patternLen++;
952 break;
953 } else if (pattern[1] == '-' && patternLen >= 3) {
954 int start = pattern[0];
955 int end = pattern[2];
956 int c = string[0];
957 if (start > end) {
958 int t = start;
959 start = end;
960 end = t;
961 }
962 if (nocase) {
963 start = tolower(start);
964 end = tolower(end);
965 c = tolower(c);
966 }
967 pattern += 2;
968 patternLen -= 2;
969 if (c >= start && c <= end)
970 match = 1;
971 } else {
972 if (!nocase) {
973 if (pattern[0] == string[0])
974 match = 1;
975 } else {
976 if (tolower((int)pattern[0]) == tolower((int)string[0]))
977 match = 1;
978 }
979 }
980 pattern++;
981 patternLen--;
982 }
983 if (not)
984 match = !match;
985 if (!match)
986 return 0; /* no match */
987 string++;
988 stringLen--;
989 break;
990 }
991 case '\\':
992 if (patternLen >= 2) {
993 pattern++;
994 patternLen--;
995 }
996 /* fall through */
997 default:
998 if (!nocase) {
999 if (pattern[0] != string[0])
1000 return 0; /* no match */
1001 } else {
1002 if (tolower((int)pattern[0]) != tolower((int)string[0]))
1003 return 0; /* no match */
1004 }
1005 string++;
1006 stringLen--;
1007 break;
1008 }
1009 pattern++;
1010 patternLen--;
1011 if (stringLen == 0) {
1012 while(*pattern == '*') {
1013 pattern++;
1014 patternLen--;
1015 }
1016 break;
1017 }
1018 }
1019 if (patternLen == 0 && stringLen == 0)
1020 return 1;
1021 return 0;
1022}
1023
500ece7c 1024static int stringmatch(const char *pattern, const char *string, int nocase) {
1025 return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
1026}
1027
2b619329 1028/* Convert a string representing an amount of memory into the number of
1029 * bytes, so for instance memtoll("1Gi") will return 1073741824 that is
1030 * (1024*1024*1024).
1031 *
1032 * On parsing error, if *err is not NULL, it's set to 1, otherwise it's
1033 * set to 0 */
1034static long long memtoll(const char *p, int *err) {
1035 const char *u;
1036 char buf[128];
1037 long mul; /* unit multiplier */
1038 long long val;
1039 unsigned int digits;
1040
1041 if (err) *err = 0;
1042 /* Search the first non digit character. */
1043 u = p;
1044 if (*u == '-') u++;
1045 while(*u && isdigit(*u)) u++;
1046 if (*u == '\0' || !strcasecmp(u,"b")) {
1047 mul = 1;
72324005 1048 } else if (!strcasecmp(u,"k")) {
2b619329 1049 mul = 1000;
72324005 1050 } else if (!strcasecmp(u,"kb")) {
2b619329 1051 mul = 1024;
72324005 1052 } else if (!strcasecmp(u,"m")) {
2b619329 1053 mul = 1000*1000;
72324005 1054 } else if (!strcasecmp(u,"mb")) {
2b619329 1055 mul = 1024*1024;
72324005 1056 } else if (!strcasecmp(u,"g")) {
2b619329 1057 mul = 1000L*1000*1000;
72324005 1058 } else if (!strcasecmp(u,"gb")) {
2b619329 1059 mul = 1024L*1024*1024;
1060 } else {
1061 if (err) *err = 1;
1062 mul = 1;
1063 }
1064 digits = u-p;
1065 if (digits >= sizeof(buf)) {
1066 if (err) *err = 1;
1067 return LLONG_MAX;
1068 }
1069 memcpy(buf,p,digits);
1070 buf[digits] = '\0';
1071 val = strtoll(buf,NULL,10);
1072 return val*mul;
1073}
1074
ee14da56 1075/* Convert a long long into a string. Returns the number of
1076 * characters needed to represent the number, that can be shorter if passed
1077 * buffer length is not enough to store the whole number. */
1078static int ll2string(char *s, size_t len, long long value) {
1079 char buf[32], *p;
1080 unsigned long long v;
1081 size_t l;
1082
1083 if (len == 0) return 0;
1084 v = (value < 0) ? -value : value;
1085 p = buf+31; /* point to the last character */
1086 do {
1087 *p-- = '0'+(v%10);
1088 v /= 10;
1089 } while(v);
1090 if (value < 0) *p-- = '-';
1091 p++;
1092 l = 32-(p-buf);
1093 if (l+1 > len) l = len-1; /* Make sure it fits, including the nul term */
1094 memcpy(s,p,l);
1095 s[l] = '\0';
1096 return l;
1097}
1098
56906eef 1099static void redisLog(int level, const char *fmt, ...) {
ed9b544e 1100 va_list ap;
1101 FILE *fp;
1102
1103 fp = (server.logfile == NULL) ? stdout : fopen(server.logfile,"a");
1104 if (!fp) return;
1105
1106 va_start(ap, fmt);
1107 if (level >= server.verbosity) {
6766f45e 1108 char *c = ".-*#";
1904ecc1 1109 char buf[64];
1110 time_t now;
1111
1112 now = time(NULL);
6c9385e0 1113 strftime(buf,64,"%d %b %H:%M:%S",localtime(&now));
054e426d 1114 fprintf(fp,"[%d] %s %c ",(int)getpid(),buf,c[level]);
ed9b544e 1115 vfprintf(fp, fmt, ap);
1116 fprintf(fp,"\n");
1117 fflush(fp);
1118 }
1119 va_end(ap);
1120
1121 if (server.logfile) fclose(fp);
1122}
1123
1124/*====================== Hash table type implementation ==================== */
1125
1126/* This is an hash table type that uses the SDS dynamic strings libary as
1127 * keys and radis objects as values (objects can hold SDS strings,
1128 * lists, sets). */
1129
1812e024 1130static void dictVanillaFree(void *privdata, void *val)
1131{
1132 DICT_NOTUSED(privdata);
1133 zfree(val);
1134}
1135
4409877e 1136static void dictListDestructor(void *privdata, void *val)
1137{
1138 DICT_NOTUSED(privdata);
1139 listRelease((list*)val);
1140}
1141
09241813 1142static int dictSdsKeyCompare(void *privdata, const void *key1,
ed9b544e 1143 const void *key2)
1144{
1145 int l1,l2;
1146 DICT_NOTUSED(privdata);
1147
1148 l1 = sdslen((sds)key1);
1149 l2 = sdslen((sds)key2);
1150 if (l1 != l2) return 0;
1151 return memcmp(key1, key2, l1) == 0;
1152}
1153
1154static void dictRedisObjectDestructor(void *privdata, void *val)
1155{
1156 DICT_NOTUSED(privdata);
1157
a35ddf12 1158 if (val == NULL) return; /* Values of swapped out keys as set to NULL */
ed9b544e 1159 decrRefCount(val);
1160}
1161
09241813 1162static void dictSdsDestructor(void *privdata, void *val)
1163{
1164 DICT_NOTUSED(privdata);
1165
1166 sdsfree(val);
1167}
1168
942a3961 1169static int dictObjKeyCompare(void *privdata, const void *key1,
ed9b544e 1170 const void *key2)
1171{
1172 const robj *o1 = key1, *o2 = key2;
09241813 1173 return dictSdsKeyCompare(privdata,o1->ptr,o2->ptr);
ed9b544e 1174}
1175
942a3961 1176static unsigned int dictObjHash(const void *key) {
ed9b544e 1177 const robj *o = key;
1178 return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
1179}
1180
09241813 1181static unsigned int dictSdsHash(const void *key) {
1182 return dictGenHashFunction((unsigned char*)key, sdslen((char*)key));
1183}
1184
942a3961 1185static int dictEncObjKeyCompare(void *privdata, const void *key1,
1186 const void *key2)
1187{
9d65a1bb 1188 robj *o1 = (robj*) key1, *o2 = (robj*) key2;
1189 int cmp;
942a3961 1190
2a1198b4 1191 if (o1->encoding == REDIS_ENCODING_INT &&
dc05abde 1192 o2->encoding == REDIS_ENCODING_INT)
1193 return o1->ptr == o2->ptr;
2a1198b4 1194
9d65a1bb 1195 o1 = getDecodedObject(o1);
1196 o2 = getDecodedObject(o2);
09241813 1197 cmp = dictSdsKeyCompare(privdata,o1->ptr,o2->ptr);
9d65a1bb 1198 decrRefCount(o1);
1199 decrRefCount(o2);
1200 return cmp;
942a3961 1201}
1202
1203static unsigned int dictEncObjHash(const void *key) {
9d65a1bb 1204 robj *o = (robj*) key;
942a3961 1205
ed9e4966 1206 if (o->encoding == REDIS_ENCODING_RAW) {
1207 return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
1208 } else {
1209 if (o->encoding == REDIS_ENCODING_INT) {
1210 char buf[32];
1211 int len;
1212
ee14da56 1213 len = ll2string(buf,32,(long)o->ptr);
ed9e4966 1214 return dictGenHashFunction((unsigned char*)buf, len);
1215 } else {
1216 unsigned int hash;
1217
1218 o = getDecodedObject(o);
1219 hash = dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
1220 decrRefCount(o);
1221 return hash;
1222 }
1223 }
942a3961 1224}
1225
09241813 1226/* Sets type */
ed9b544e 1227static dictType setDictType = {
942a3961 1228 dictEncObjHash, /* hash function */
ed9b544e 1229 NULL, /* key dup */
1230 NULL, /* val dup */
942a3961 1231 dictEncObjKeyCompare, /* key compare */
ed9b544e 1232 dictRedisObjectDestructor, /* key destructor */
1233 NULL /* val destructor */
1234};
1235
f2d9f50f 1236/* Sorted sets hash (note: a skiplist is used in addition to the hash table) */
1812e024 1237static dictType zsetDictType = {
1238 dictEncObjHash, /* hash function */
1239 NULL, /* key dup */
1240 NULL, /* val dup */
1241 dictEncObjKeyCompare, /* key compare */
1242 dictRedisObjectDestructor, /* key destructor */
da0a1620 1243 dictVanillaFree /* val destructor of malloc(sizeof(double)) */
1812e024 1244};
1245
09241813 1246/* Db->dict, keys are sds strings, vals are Redis objects. */
5234952b 1247static dictType dbDictType = {
09241813 1248 dictSdsHash, /* hash function */
ed9b544e 1249 NULL, /* key dup */
1250 NULL, /* val dup */
09241813 1251 dictSdsKeyCompare, /* key compare */
1252 dictSdsDestructor, /* key destructor */
ed9b544e 1253 dictRedisObjectDestructor /* val destructor */
1254};
1255
f2d9f50f 1256/* Db->expires */
1257static dictType keyptrDictType = {
09241813 1258 dictSdsHash, /* hash function */
f2d9f50f 1259 NULL, /* key dup */
1260 NULL, /* val dup */
09241813 1261 dictSdsKeyCompare, /* key compare */
829137b9 1262 NULL, /* key destructor */
f2d9f50f 1263 NULL /* val destructor */
1264};
1265
5234952b 1266/* Hash type hash table (note that small hashes are represented with zimpaps) */
1267static dictType hashDictType = {
1268 dictEncObjHash, /* hash function */
1269 NULL, /* key dup */
1270 NULL, /* val dup */
1271 dictEncObjKeyCompare, /* key compare */
1272 dictRedisObjectDestructor, /* key destructor */
1273 dictRedisObjectDestructor /* val destructor */
1274};
1275
4409877e 1276/* Keylist hash table type has unencoded redis objects as keys and
d5d55fc3 1277 * lists as values. It's used for blocking operations (BLPOP) and to
1278 * map swapped keys to a list of clients waiting for this keys to be loaded. */
4409877e 1279static dictType keylistDictType = {
1280 dictObjHash, /* hash function */
1281 NULL, /* key dup */
1282 NULL, /* val dup */
1283 dictObjKeyCompare, /* key compare */
1284 dictRedisObjectDestructor, /* key destructor */
1285 dictListDestructor /* val destructor */
1286};
1287
42ab0172
AO
1288static void version();
1289
ed9b544e 1290/* ========================= Random utility functions ======================= */
1291
1292/* Redis generally does not try to recover from out of memory conditions
1293 * when allocating objects or strings, it is not clear if it will be possible
1294 * to report this condition to the client since the networking layer itself
1295 * is based on heap allocation for send buffers, so we simply abort.
1296 * At least the code will be simpler to read... */
1297static void oom(const char *msg) {
71c54b21 1298 redisLog(REDIS_WARNING, "%s: Out of memory\n",msg);
ed9b544e 1299 sleep(1);
1300 abort();
1301}
1302
1303/* ====================== Redis server networking stuff ===================== */
56906eef 1304static void closeTimedoutClients(void) {
ed9b544e 1305 redisClient *c;
ed9b544e 1306 listNode *ln;
1307 time_t now = time(NULL);
c7df85a4 1308 listIter li;
ed9b544e 1309
c7df85a4 1310 listRewind(server.clients,&li);
1311 while ((ln = listNext(&li)) != NULL) {
ed9b544e 1312 c = listNodeValue(ln);
f86a74e9 1313 if (server.maxidletime &&
1314 !(c->flags & REDIS_SLAVE) && /* no timeout for slaves */
c7cf2ec9 1315 !(c->flags & REDIS_MASTER) && /* no timeout for masters */
ffc6b7f8 1316 dictSize(c->pubsub_channels) == 0 && /* no timeout for pubsub */
1317 listLength(c->pubsub_patterns) == 0 &&
d6cc8867 1318 (now - c->lastinteraction > server.maxidletime))
f86a74e9 1319 {
f870935d 1320 redisLog(REDIS_VERBOSE,"Closing idle client");
ed9b544e 1321 freeClient(c);
f86a74e9 1322 } else if (c->flags & REDIS_BLOCKED) {
58d976b8 1323 if (c->blockingto != 0 && c->blockingto < now) {
b177fd30 1324 addReply(c,shared.nullmultibulk);
b0d8747d 1325 unblockClientWaitingData(c);
f86a74e9 1326 }
ed9b544e 1327 }
1328 }
ed9b544e 1329}
1330
12fea928 1331static int htNeedsResize(dict *dict) {
1332 long long size, used;
1333
1334 size = dictSlots(dict);
1335 used = dictSize(dict);
1336 return (size && used && size > DICT_HT_INITIAL_SIZE &&
1337 (used*100/size < REDIS_HT_MINFILL));
1338}
1339
0bc03378 1340/* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
1341 * we resize the hash table to save memory */
56906eef 1342static void tryResizeHashTables(void) {
0bc03378 1343 int j;
1344
1345 for (j = 0; j < server.dbnum; j++) {
5413c40d 1346 if (htNeedsResize(server.db[j].dict))
0bc03378 1347 dictResize(server.db[j].dict);
12fea928 1348 if (htNeedsResize(server.db[j].expires))
1349 dictResize(server.db[j].expires);
0bc03378 1350 }
1351}
1352
8ca3e9d1 1353/* Our hash table implementation performs rehashing incrementally while
1354 * we write/read from the hash table. Still if the server is idle, the hash
1355 * table will use two tables for a long time. So we try to use 1 millisecond
1356 * of CPU time at every serverCron() loop in order to rehash some key. */
1357static void incrementallyRehash(void) {
1358 int j;
1359
1360 for (j = 0; j < server.dbnum; j++) {
1361 if (dictIsRehashing(server.db[j].dict)) {
1362 dictRehashMilliseconds(server.db[j].dict,1);
1363 break; /* already used our millisecond for this loop... */
1364 }
1365 }
1366}
1367
9d65a1bb 1368/* A background saving child (BGSAVE) terminated its work. Handle this. */
1369void backgroundSaveDoneHandler(int statloc) {
1370 int exitcode = WEXITSTATUS(statloc);
1371 int bysignal = WIFSIGNALED(statloc);
1372
1373 if (!bysignal && exitcode == 0) {
1374 redisLog(REDIS_NOTICE,
1375 "Background saving terminated with success");
1376 server.dirty = 0;
1377 server.lastsave = time(NULL);
1378 } else if (!bysignal && exitcode != 0) {
1379 redisLog(REDIS_WARNING, "Background saving error");
1380 } else {
1381 redisLog(REDIS_WARNING,
454eea7c 1382 "Background saving terminated by signal %d", WTERMSIG(statloc));
9d65a1bb 1383 rdbRemoveTempFile(server.bgsavechildpid);
1384 }
1385 server.bgsavechildpid = -1;
1386 /* Possibly there are slaves waiting for a BGSAVE in order to be served
1387 * (the first stage of SYNC is a bulk transfer of dump.rdb) */
1388 updateSlavesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR);
1389}
1390
1391/* A background append only file rewriting (BGREWRITEAOF) terminated its work.
1392 * Handle this. */
1393void backgroundRewriteDoneHandler(int statloc) {
1394 int exitcode = WEXITSTATUS(statloc);
1395 int bysignal = WIFSIGNALED(statloc);
1396
1397 if (!bysignal && exitcode == 0) {
1398 int fd;
1399 char tmpfile[256];
1400
1401 redisLog(REDIS_NOTICE,
1402 "Background append only file rewriting terminated with success");
1403 /* Now it's time to flush the differences accumulated by the parent */
1404 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) server.bgrewritechildpid);
1405 fd = open(tmpfile,O_WRONLY|O_APPEND);
1406 if (fd == -1) {
1407 redisLog(REDIS_WARNING, "Not able to open the temp append only file produced by the child: %s", strerror(errno));
1408 goto cleanup;
1409 }
1410 /* Flush our data... */
1411 if (write(fd,server.bgrewritebuf,sdslen(server.bgrewritebuf)) !=
1412 (signed) sdslen(server.bgrewritebuf)) {
1413 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));
1414 close(fd);
1415 goto cleanup;
1416 }
b32627cd 1417 redisLog(REDIS_NOTICE,"Parent diff flushed into the new append log file with success (%lu bytes)",sdslen(server.bgrewritebuf));
9d65a1bb 1418 /* Now our work is to rename the temp file into the stable file. And
1419 * switch the file descriptor used by the server for append only. */
1420 if (rename(tmpfile,server.appendfilename) == -1) {
1421 redisLog(REDIS_WARNING,"Can't rename the temp append only file into the stable one: %s", strerror(errno));
1422 close(fd);
1423 goto cleanup;
1424 }
1425 /* Mission completed... almost */
1426 redisLog(REDIS_NOTICE,"Append only file successfully rewritten.");
1427 if (server.appendfd != -1) {
1428 /* If append only is actually enabled... */
1429 close(server.appendfd);
1430 server.appendfd = fd;
d5d23dab 1431 if (server.appendfsync != APPENDFSYNC_NO) aof_fsync(fd);
85a83172 1432 server.appendseldb = -1; /* Make sure it will issue SELECT */
9d65a1bb 1433 redisLog(REDIS_NOTICE,"The new append only file was selected for future appends.");
1434 } else {
1435 /* If append only is disabled we just generate a dump in this
1436 * format. Why not? */
1437 close(fd);
1438 }
1439 } else if (!bysignal && exitcode != 0) {
1440 redisLog(REDIS_WARNING, "Background append only file rewriting error");
1441 } else {
1442 redisLog(REDIS_WARNING,
454eea7c 1443 "Background append only file rewriting terminated by signal %d",
1444 WTERMSIG(statloc));
9d65a1bb 1445 }
1446cleanup:
1447 sdsfree(server.bgrewritebuf);
1448 server.bgrewritebuf = sdsempty();
1449 aofRemoveTempFile(server.bgrewritechildpid);
1450 server.bgrewritechildpid = -1;
1451}
1452
884d4b39 1453/* This function is called once a background process of some kind terminates,
1454 * as we want to avoid resizing the hash tables when there is a child in order
1455 * to play well with copy-on-write (otherwise when a resize happens lots of
1456 * memory pages are copied). The goal of this function is to update the ability
1457 * for dict.c to resize the hash tables accordingly to the fact we have o not
1458 * running childs. */
1459static void updateDictResizePolicy(void) {
1460 if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1)
1461 dictEnableResize();
1462 else
1463 dictDisableResize();
1464}
1465
56906eef 1466static int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
94754ccc 1467 int j, loops = server.cronloops++;
ed9b544e 1468 REDIS_NOTUSED(eventLoop);
1469 REDIS_NOTUSED(id);
1470 REDIS_NOTUSED(clientData);
1471
3a66edc7 1472 /* We take a cached value of the unix time in the global state because
1473 * with virtual memory and aging there is to store the current time
1474 * in objects at every object access, and accuracy is not needed.
1475 * To access a global var is faster than calling time(NULL) */
1476 server.unixtime = time(NULL);
560db612 1477 /* We have just 21 bits per object for LRU information.
1478 * So we use an (eventually wrapping) LRU clock with minutes resolution.
1479 *
1480 * When we need to select what object to swap, we compute the minimum
1481 * time distance between the current lruclock and the object last access
1482 * lruclock info. Even if clocks will wrap on overflow, there is
1483 * the interesting property that we are sure that at least
1484 * ABS(A-B) minutes passed between current time and timestamp B.
1485 *
1486 * This is not precise but we don't need at all precision, but just
1487 * something statistically reasonable.
1488 */
1489 server.lruclock = (time(NULL)/60)&((1<<21)-1);
3a66edc7 1490
fab43727 1491 /* We received a SIGTERM, shutting down here in a safe way, as it is
1492 * not ok doing so inside the signal handler. */
1493 if (server.shutdown_asap) {
1494 if (prepareForShutdown() == REDIS_OK) exit(0);
1495 redisLog(REDIS_WARNING,"SIGTERM received but errors trying to shut down the server, check the logs for more information");
1496 }
1497
0bc03378 1498 /* Show some info about non-empty databases */
ed9b544e 1499 for (j = 0; j < server.dbnum; j++) {
dec423d9 1500 long long size, used, vkeys;
94754ccc 1501
3305306f 1502 size = dictSlots(server.db[j].dict);
1503 used = dictSize(server.db[j].dict);
94754ccc 1504 vkeys = dictSize(server.db[j].expires);
1763929f 1505 if (!(loops % 50) && (used || vkeys)) {
f870935d 1506 redisLog(REDIS_VERBOSE,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j,used,vkeys,size);
a4d1ba9a 1507 /* dictPrintStats(server.dict); */
ed9b544e 1508 }
ed9b544e 1509 }
1510
0bc03378 1511 /* We don't want to resize the hash tables while a bacground saving
1512 * is in progress: the saving child is created using fork() that is
1513 * implemented with a copy-on-write semantic in most modern systems, so
1514 * if we resize the HT while there is the saving child at work actually
1515 * a lot of memory movements in the parent will cause a lot of pages
1516 * copied. */
8ca3e9d1 1517 if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1) {
1518 if (!(loops % 10)) tryResizeHashTables();
1519 if (server.activerehashing) incrementallyRehash();
884d4b39 1520 }
0bc03378 1521
ed9b544e 1522 /* Show information about connected clients */
1763929f 1523 if (!(loops % 50)) {
bdcb92f2 1524 redisLog(REDIS_VERBOSE,"%d clients connected (%d slaves), %zu bytes in use",
ed9b544e 1525 listLength(server.clients)-listLength(server.slaves),
1526 listLength(server.slaves),
bdcb92f2 1527 zmalloc_used_memory());
ed9b544e 1528 }
1529
1530 /* Close connections of timedout clients */
1763929f 1531 if ((server.maxidletime && !(loops % 100)) || server.blpop_blocked_clients)
ed9b544e 1532 closeTimedoutClients();
1533
9d65a1bb 1534 /* Check if a background saving or AOF rewrite in progress terminated */
1535 if (server.bgsavechildpid != -1 || server.bgrewritechildpid != -1) {
ed9b544e 1536 int statloc;
9d65a1bb 1537 pid_t pid;
1538
1539 if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
1540 if (pid == server.bgsavechildpid) {
1541 backgroundSaveDoneHandler(statloc);
ed9b544e 1542 } else {
9d65a1bb 1543 backgroundRewriteDoneHandler(statloc);
ed9b544e 1544 }
884d4b39 1545 updateDictResizePolicy();
ed9b544e 1546 }
1547 } else {
1548 /* If there is not a background saving in progress check if
1549 * we have to save now */
1550 time_t now = time(NULL);
1551 for (j = 0; j < server.saveparamslen; j++) {
1552 struct saveparam *sp = server.saveparams+j;
1553
1554 if (server.dirty >= sp->changes &&
1555 now-server.lastsave > sp->seconds) {
1556 redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...",
1557 sp->changes, sp->seconds);
f78fd11b 1558 rdbSaveBackground(server.dbfilename);
ed9b544e 1559 break;
1560 }
1561 }
1562 }
94754ccc 1563
f2324293 1564 /* Try to expire a few timed out keys. The algorithm used is adaptive and
1565 * will use few CPU cycles if there are few expiring keys, otherwise
1566 * it will get more aggressive to avoid that too much memory is used by
1567 * keys that can be removed from the keyspace. */
94754ccc 1568 for (j = 0; j < server.dbnum; j++) {
f2324293 1569 int expired;
94754ccc 1570 redisDb *db = server.db+j;
94754ccc 1571
f2324293 1572 /* Continue to expire if at the end of the cycle more than 25%
1573 * of the keys were expired. */
1574 do {
4ef8de8a 1575 long num = dictSize(db->expires);
94754ccc 1576 time_t now = time(NULL);
1577
f2324293 1578 expired = 0;
94754ccc 1579 if (num > REDIS_EXPIRELOOKUPS_PER_CRON)
1580 num = REDIS_EXPIRELOOKUPS_PER_CRON;
1581 while (num--) {
1582 dictEntry *de;
1583 time_t t;
1584
1585 if ((de = dictGetRandomKey(db->expires)) == NULL) break;
1586 t = (time_t) dictGetEntryVal(de);
1587 if (now > t) {
09241813 1588 sds key = dictGetEntryKey(de);
1589 robj *keyobj = createStringObject(key,sdslen(key));
1590
1591 dbDelete(db,keyobj);
1592 decrRefCount(keyobj);
f2324293 1593 expired++;
2a6a2ed1 1594 server.stat_expiredkeys++;
94754ccc 1595 }
1596 }
f2324293 1597 } while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/4);
94754ccc 1598 }
1599
4ef8de8a 1600 /* Swap a few keys on disk if we are over the memory limit and VM
f870935d 1601 * is enbled. Try to free objects from the free list first. */
7e69548d 1602 if (vmCanSwapOut()) {
1603 while (server.vm_enabled && zmalloc_used_memory() >
f870935d 1604 server.vm_max_memory)
1605 {
72e9fd40 1606 int retval;
1607
a5819310 1608 if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
72e9fd40 1609 retval = (server.vm_max_threads == 0) ?
1610 vmSwapOneObjectBlocking() :
1611 vmSwapOneObjectThreaded();
1763929f 1612 if (retval == REDIS_ERR && !(loops % 300) &&
72e9fd40 1613 zmalloc_used_memory() >
1614 (server.vm_max_memory+server.vm_max_memory/10))
1615 {
1616 redisLog(REDIS_WARNING,"WARNING: vm-max-memory limit exceeded by more than 10%% but unable to swap more objects out!");
7e69548d 1617 }
72e9fd40 1618 /* Note that when using threade I/O we free just one object,
1619 * because anyway when the I/O thread in charge to swap this
1620 * object out will finish, the handler of completed jobs
1621 * will try to swap more objects if we are still out of memory. */
1622 if (retval == REDIS_ERR || server.vm_max_threads > 0) break;
4ef8de8a 1623 }
1624 }
1625
ed9b544e 1626 /* Check if we should connect to a MASTER */
1763929f 1627 if (server.replstate == REDIS_REPL_CONNECT && !(loops % 10)) {
ed9b544e 1628 redisLog(REDIS_NOTICE,"Connecting to MASTER...");
1629 if (syncWithMaster() == REDIS_OK) {
1630 redisLog(REDIS_NOTICE,"MASTER <-> SLAVE sync succeeded");
8f63ddca 1631 if (server.appendonly) rewriteAppendOnlyFileBackground();
ed9b544e 1632 }
1633 }
1763929f 1634 return 100;
ed9b544e 1635}
1636
d5d55fc3 1637/* This function gets called every time Redis is entering the
1638 * main loop of the event driven library, that is, before to sleep
1639 * for ready file descriptors. */
1640static void beforeSleep(struct aeEventLoop *eventLoop) {
1641 REDIS_NOTUSED(eventLoop);
1642
28ed1f33 1643 /* Awake clients that got all the swapped keys they requested */
d5d55fc3 1644 if (server.vm_enabled && listLength(server.io_ready_clients)) {
1645 listIter li;
1646 listNode *ln;
1647
1648 listRewind(server.io_ready_clients,&li);
1649 while((ln = listNext(&li))) {
1650 redisClient *c = ln->value;
1651 struct redisCommand *cmd;
1652
1653 /* Resume the client. */
1654 listDelNode(server.io_ready_clients,ln);
1655 c->flags &= (~REDIS_IO_WAIT);
1656 server.vm_blocked_clients--;
1657 aeCreateFileEvent(server.el, c->fd, AE_READABLE,
1658 readQueryFromClient, c);
1659 cmd = lookupCommand(c->argv[0]->ptr);
1660 assert(cmd != NULL);
1661 call(c,cmd);
1662 resetClient(c);
1663 /* There may be more data to process in the input buffer. */
1664 if (c->querybuf && sdslen(c->querybuf) > 0)
1665 processInputBuffer(c);
1666 }
1667 }
28ed1f33 1668 /* Write the AOF buffer on disk */
1669 flushAppendOnlyFile();
d5d55fc3 1670}
1671
ed9b544e 1672static void createSharedObjects(void) {
05df7621 1673 int j;
1674
ed9b544e 1675 shared.crlf = createObject(REDIS_STRING,sdsnew("\r\n"));
1676 shared.ok = createObject(REDIS_STRING,sdsnew("+OK\r\n"));
1677 shared.err = createObject(REDIS_STRING,sdsnew("-ERR\r\n"));
c937aa89 1678 shared.emptybulk = createObject(REDIS_STRING,sdsnew("$0\r\n\r\n"));
1679 shared.czero = createObject(REDIS_STRING,sdsnew(":0\r\n"));
1680 shared.cone = createObject(REDIS_STRING,sdsnew(":1\r\n"));
23d3a5fe 1681 shared.cnegone = createObject(REDIS_STRING,sdsnew(":-1\r\n"));
c937aa89 1682 shared.nullbulk = createObject(REDIS_STRING,sdsnew("$-1\r\n"));
1683 shared.nullmultibulk = createObject(REDIS_STRING,sdsnew("*-1\r\n"));
1684 shared.emptymultibulk = createObject(REDIS_STRING,sdsnew("*0\r\n"));
ed9b544e 1685 shared.pong = createObject(REDIS_STRING,sdsnew("+PONG\r\n"));
6e469882 1686 shared.queued = createObject(REDIS_STRING,sdsnew("+QUEUED\r\n"));
ed9b544e 1687 shared.wrongtypeerr = createObject(REDIS_STRING,sdsnew(
1688 "-ERR Operation against a key holding the wrong kind of value\r\n"));
ed9b544e 1689 shared.nokeyerr = createObject(REDIS_STRING,sdsnew(
1690 "-ERR no such key\r\n"));
ed9b544e 1691 shared.syntaxerr = createObject(REDIS_STRING,sdsnew(
1692 "-ERR syntax error\r\n"));
c937aa89 1693 shared.sameobjecterr = createObject(REDIS_STRING,sdsnew(
1694 "-ERR source and destination objects are the same\r\n"));
1695 shared.outofrangeerr = createObject(REDIS_STRING,sdsnew(
1696 "-ERR index out of range\r\n"));
ed9b544e 1697 shared.space = createObject(REDIS_STRING,sdsnew(" "));
c937aa89 1698 shared.colon = createObject(REDIS_STRING,sdsnew(":"));
1699 shared.plus = createObject(REDIS_STRING,sdsnew("+"));
ed9b544e 1700 shared.select0 = createStringObject("select 0\r\n",10);
1701 shared.select1 = createStringObject("select 1\r\n",10);
1702 shared.select2 = createStringObject("select 2\r\n",10);
1703 shared.select3 = createStringObject("select 3\r\n",10);
1704 shared.select4 = createStringObject("select 4\r\n",10);
1705 shared.select5 = createStringObject("select 5\r\n",10);
1706 shared.select6 = createStringObject("select 6\r\n",10);
1707 shared.select7 = createStringObject("select 7\r\n",10);
1708 shared.select8 = createStringObject("select 8\r\n",10);
1709 shared.select9 = createStringObject("select 9\r\n",10);
befec3cd 1710 shared.messagebulk = createStringObject("$7\r\nmessage\r\n",13);
c8d0ea0e 1711 shared.pmessagebulk = createStringObject("$8\r\npmessage\r\n",14);
befec3cd 1712 shared.subscribebulk = createStringObject("$9\r\nsubscribe\r\n",15);
fc46bb71 1713 shared.unsubscribebulk = createStringObject("$11\r\nunsubscribe\r\n",18);
ffc6b7f8 1714 shared.psubscribebulk = createStringObject("$10\r\npsubscribe\r\n",17);
1715 shared.punsubscribebulk = createStringObject("$12\r\npunsubscribe\r\n",19);
befec3cd 1716 shared.mbulk3 = createStringObject("*3\r\n",4);
c8d0ea0e 1717 shared.mbulk4 = createStringObject("*4\r\n",4);
05df7621 1718 for (j = 0; j < REDIS_SHARED_INTEGERS; j++) {
1719 shared.integers[j] = createObject(REDIS_STRING,(void*)(long)j);
1720 shared.integers[j]->encoding = REDIS_ENCODING_INT;
1721 }
ed9b544e 1722}
1723
1724static void appendServerSaveParams(time_t seconds, int changes) {
1725 server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));
ed9b544e 1726 server.saveparams[server.saveparamslen].seconds = seconds;
1727 server.saveparams[server.saveparamslen].changes = changes;
1728 server.saveparamslen++;
1729}
1730
bcfc686d 1731static void resetServerSaveParams() {
ed9b544e 1732 zfree(server.saveparams);
1733 server.saveparams = NULL;
1734 server.saveparamslen = 0;
1735}
1736
1737static void initServerConfig() {
1738 server.dbnum = REDIS_DEFAULT_DBNUM;
1739 server.port = REDIS_SERVERPORT;
f870935d 1740 server.verbosity = REDIS_VERBOSE;
ed9b544e 1741 server.maxidletime = REDIS_MAXIDLETIME;
1742 server.saveparams = NULL;
1743 server.logfile = NULL; /* NULL = log on standard output */
1744 server.bindaddr = NULL;
1745 server.glueoutputbuf = 1;
1746 server.daemonize = 0;
44b38ef4 1747 server.appendonly = 0;
1b677732 1748 server.appendfsync = APPENDFSYNC_EVERYSEC;
38db9171 1749 server.no_appendfsync_on_rewrite = 0;
48f0308a 1750 server.lastfsync = time(NULL);
44b38ef4 1751 server.appendfd = -1;
1752 server.appendseldb = -1; /* Make sure the first time will not match */
500ece7c 1753 server.pidfile = zstrdup("/var/run/redis.pid");
1754 server.dbfilename = zstrdup("dump.rdb");
1755 server.appendfilename = zstrdup("appendonly.aof");
abcb223e 1756 server.requirepass = NULL;
b0553789 1757 server.rdbcompression = 1;
8ca3e9d1 1758 server.activerehashing = 1;
285add55 1759 server.maxclients = 0;
d5d55fc3 1760 server.blpop_blocked_clients = 0;
3fd78bcd 1761 server.maxmemory = 0;
75680a3c 1762 server.vm_enabled = 0;
054e426d 1763 server.vm_swap_file = zstrdup("/tmp/redis-%p.vm");
75680a3c 1764 server.vm_page_size = 256; /* 256 bytes per page */
1765 server.vm_pages = 1024*1024*100; /* 104 millions of pages */
1766 server.vm_max_memory = 1024LL*1024*1024*1; /* 1 GB of RAM */
92f8e882 1767 server.vm_max_threads = 4;
d5d55fc3 1768 server.vm_blocked_clients = 0;
cbba7dd7 1769 server.hash_max_zipmap_entries = REDIS_HASH_MAX_ZIPMAP_ENTRIES;
1770 server.hash_max_zipmap_value = REDIS_HASH_MAX_ZIPMAP_VALUE;
d0686e07
PN
1771 server.list_max_ziplist_entries = REDIS_LIST_MAX_ZIPLIST_ENTRIES;
1772 server.list_max_ziplist_value = REDIS_LIST_MAX_ZIPLIST_VALUE;
fab43727 1773 server.shutdown_asap = 0;
75680a3c 1774
bcfc686d 1775 resetServerSaveParams();
ed9b544e 1776
1777 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
1778 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
1779 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1780 /* Replication related */
1781 server.isslave = 0;
d0ccebcf 1782 server.masterauth = NULL;
ed9b544e 1783 server.masterhost = NULL;
1784 server.masterport = 6379;
1785 server.master = NULL;
1786 server.replstate = REDIS_REPL_NONE;
a7866db6 1787
1788 /* Double constants initialization */
1789 R_Zero = 0.0;
1790 R_PosInf = 1.0/R_Zero;
1791 R_NegInf = -1.0/R_Zero;
1792 R_Nan = R_Zero/R_Zero;
ed9b544e 1793}
1794
1795static void initServer() {
1796 int j;
1797
1798 signal(SIGHUP, SIG_IGN);
1799 signal(SIGPIPE, SIG_IGN);
fe3bbfbe 1800 setupSigSegvAction();
ed9b544e 1801
b9bc0eef 1802 server.devnull = fopen("/dev/null","w");
1803 if (server.devnull == NULL) {
1804 redisLog(REDIS_WARNING, "Can't open /dev/null: %s", server.neterr);
1805 exit(1);
1806 }
ed9b544e 1807 server.clients = listCreate();
1808 server.slaves = listCreate();
87eca727 1809 server.monitors = listCreate();
ed9b544e 1810 server.objfreelist = listCreate();
1811 createSharedObjects();
1812 server.el = aeCreateEventLoop();
3305306f 1813 server.db = zmalloc(sizeof(redisDb)*server.dbnum);
ed9b544e 1814 server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr);
1815 if (server.fd == -1) {
1816 redisLog(REDIS_WARNING, "Opening TCP port: %s", server.neterr);
1817 exit(1);
1818 }
3305306f 1819 for (j = 0; j < server.dbnum; j++) {
5234952b 1820 server.db[j].dict = dictCreate(&dbDictType,NULL);
f2d9f50f 1821 server.db[j].expires = dictCreate(&keyptrDictType,NULL);
37ab76c9 1822 server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL);
1823 server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);
d5d55fc3 1824 if (server.vm_enabled)
1825 server.db[j].io_keys = dictCreate(&keylistDictType,NULL);
3305306f 1826 server.db[j].id = j;
1827 }
ffc6b7f8 1828 server.pubsub_channels = dictCreate(&keylistDictType,NULL);
1829 server.pubsub_patterns = listCreate();
1830 listSetFreeMethod(server.pubsub_patterns,freePubsubPattern);
1831 listSetMatchMethod(server.pubsub_patterns,listMatchPubsubPattern);
ed9b544e 1832 server.cronloops = 0;
9f3c422c 1833 server.bgsavechildpid = -1;
9d65a1bb 1834 server.bgrewritechildpid = -1;
1835 server.bgrewritebuf = sdsempty();
28ed1f33 1836 server.aofbuf = sdsempty();
ed9b544e 1837 server.lastsave = time(NULL);
1838 server.dirty = 0;
ed9b544e 1839 server.stat_numcommands = 0;
1840 server.stat_numconnections = 0;
2a6a2ed1 1841 server.stat_expiredkeys = 0;
ed9b544e 1842 server.stat_starttime = time(NULL);
3a66edc7 1843 server.unixtime = time(NULL);
d8f8b666 1844 aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL);
996cb5f7 1845 if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,
1846 acceptHandler, NULL) == AE_ERR) oom("creating file event");
44b38ef4 1847
1848 if (server.appendonly) {
3bb225d6 1849 server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
44b38ef4 1850 if (server.appendfd == -1) {
1851 redisLog(REDIS_WARNING, "Can't open the append-only file: %s",
1852 strerror(errno));
1853 exit(1);
1854 }
1855 }
75680a3c 1856
1857 if (server.vm_enabled) vmInit();
ed9b544e 1858}
1859
1860/* Empty the whole database */
ca37e9cd 1861static long long emptyDb() {
ed9b544e 1862 int j;
ca37e9cd 1863 long long removed = 0;
ed9b544e 1864
3305306f 1865 for (j = 0; j < server.dbnum; j++) {
ca37e9cd 1866 removed += dictSize(server.db[j].dict);
3305306f 1867 dictEmpty(server.db[j].dict);
1868 dictEmpty(server.db[j].expires);
1869 }
ca37e9cd 1870 return removed;
ed9b544e 1871}
1872
85dd2f3a 1873static int yesnotoi(char *s) {
1874 if (!strcasecmp(s,"yes")) return 1;
1875 else if (!strcasecmp(s,"no")) return 0;
1876 else return -1;
1877}
1878
ed9b544e 1879/* I agree, this is a very rudimental way to load a configuration...
1880 will improve later if the config gets more complex */
1881static void loadServerConfig(char *filename) {
c9a111ac 1882 FILE *fp;
ed9b544e 1883 char buf[REDIS_CONFIGLINE_MAX+1], *err = NULL;
1884 int linenum = 0;
1885 sds line = NULL;
c9a111ac 1886
1887 if (filename[0] == '-' && filename[1] == '\0')
1888 fp = stdin;
1889 else {
1890 if ((fp = fopen(filename,"r")) == NULL) {
9a22de82 1891 redisLog(REDIS_WARNING, "Fatal error, can't open config file '%s'", filename);
c9a111ac 1892 exit(1);
1893 }
ed9b544e 1894 }
c9a111ac 1895
ed9b544e 1896 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL) {
1897 sds *argv;
1898 int argc, j;
1899
1900 linenum++;
1901 line = sdsnew(buf);
1902 line = sdstrim(line," \t\r\n");
1903
1904 /* Skip comments and blank lines*/
1905 if (line[0] == '#' || line[0] == '\0') {
1906 sdsfree(line);
1907 continue;
1908 }
1909
1910 /* Split into arguments */
1911 argv = sdssplitlen(line,sdslen(line)," ",1,&argc);
1912 sdstolower(argv[0]);
1913
1914 /* Execute config directives */
bb0b03a3 1915 if (!strcasecmp(argv[0],"timeout") && argc == 2) {
ed9b544e 1916 server.maxidletime = atoi(argv[1]);
0150db36 1917 if (server.maxidletime < 0) {
ed9b544e 1918 err = "Invalid timeout value"; goto loaderr;
1919 }
bb0b03a3 1920 } else if (!strcasecmp(argv[0],"port") && argc == 2) {
ed9b544e 1921 server.port = atoi(argv[1]);
1922 if (server.port < 1 || server.port > 65535) {
1923 err = "Invalid port"; goto loaderr;
1924 }
bb0b03a3 1925 } else if (!strcasecmp(argv[0],"bind") && argc == 2) {
ed9b544e 1926 server.bindaddr = zstrdup(argv[1]);
bb0b03a3 1927 } else if (!strcasecmp(argv[0],"save") && argc == 3) {
ed9b544e 1928 int seconds = atoi(argv[1]);
1929 int changes = atoi(argv[2]);
1930 if (seconds < 1 || changes < 0) {
1931 err = "Invalid save parameters"; goto loaderr;
1932 }
1933 appendServerSaveParams(seconds,changes);
bb0b03a3 1934 } else if (!strcasecmp(argv[0],"dir") && argc == 2) {
ed9b544e 1935 if (chdir(argv[1]) == -1) {
1936 redisLog(REDIS_WARNING,"Can't chdir to '%s': %s",
1937 argv[1], strerror(errno));
1938 exit(1);
1939 }
bb0b03a3 1940 } else if (!strcasecmp(argv[0],"loglevel") && argc == 2) {
1941 if (!strcasecmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG;
f870935d 1942 else if (!strcasecmp(argv[1],"verbose")) server.verbosity = REDIS_VERBOSE;
bb0b03a3 1943 else if (!strcasecmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE;
1944 else if (!strcasecmp(argv[1],"warning")) server.verbosity = REDIS_WARNING;
ed9b544e 1945 else {
1946 err = "Invalid log level. Must be one of debug, notice, warning";
1947 goto loaderr;
1948 }
bb0b03a3 1949 } else if (!strcasecmp(argv[0],"logfile") && argc == 2) {
c9a111ac 1950 FILE *logfp;
ed9b544e 1951
1952 server.logfile = zstrdup(argv[1]);
bb0b03a3 1953 if (!strcasecmp(server.logfile,"stdout")) {
ed9b544e 1954 zfree(server.logfile);
1955 server.logfile = NULL;
1956 }
1957 if (server.logfile) {
1958 /* Test if we are able to open the file. The server will not
1959 * be able to abort just for this problem later... */
c9a111ac 1960 logfp = fopen(server.logfile,"a");
1961 if (logfp == NULL) {
ed9b544e 1962 err = sdscatprintf(sdsempty(),
1963 "Can't open the log file: %s", strerror(errno));
1964 goto loaderr;
1965 }
c9a111ac 1966 fclose(logfp);
ed9b544e 1967 }
bb0b03a3 1968 } else if (!strcasecmp(argv[0],"databases") && argc == 2) {
ed9b544e 1969 server.dbnum = atoi(argv[1]);
1970 if (server.dbnum < 1) {
1971 err = "Invalid number of databases"; goto loaderr;
1972 }
b3f83f12
JZ
1973 } else if (!strcasecmp(argv[0],"include") && argc == 2) {
1974 loadServerConfig(argv[1]);
285add55 1975 } else if (!strcasecmp(argv[0],"maxclients") && argc == 2) {
1976 server.maxclients = atoi(argv[1]);
3fd78bcd 1977 } else if (!strcasecmp(argv[0],"maxmemory") && argc == 2) {
2b619329 1978 server.maxmemory = memtoll(argv[1],NULL);
bb0b03a3 1979 } else if (!strcasecmp(argv[0],"slaveof") && argc == 3) {
ed9b544e 1980 server.masterhost = sdsnew(argv[1]);
1981 server.masterport = atoi(argv[2]);
1982 server.replstate = REDIS_REPL_CONNECT;
d0ccebcf 1983 } else if (!strcasecmp(argv[0],"masterauth") && argc == 2) {
1984 server.masterauth = zstrdup(argv[1]);
bb0b03a3 1985 } else if (!strcasecmp(argv[0],"glueoutputbuf") && argc == 2) {
85dd2f3a 1986 if ((server.glueoutputbuf = yesnotoi(argv[1])) == -1) {
ed9b544e 1987 err = "argument must be 'yes' or 'no'"; goto loaderr;
1988 }
121f70cf 1989 } else if (!strcasecmp(argv[0],"rdbcompression") && argc == 2) {
1990 if ((server.rdbcompression = yesnotoi(argv[1])) == -1) {
8ca3e9d1 1991 err = "argument must be 'yes' or 'no'"; goto loaderr;
1992 }
1993 } else if (!strcasecmp(argv[0],"activerehashing") && argc == 2) {
1994 if ((server.activerehashing = yesnotoi(argv[1])) == -1) {
121f70cf 1995 err = "argument must be 'yes' or 'no'"; goto loaderr;
1996 }
bb0b03a3 1997 } else if (!strcasecmp(argv[0],"daemonize") && argc == 2) {
85dd2f3a 1998 if ((server.daemonize = yesnotoi(argv[1])) == -1) {
ed9b544e 1999 err = "argument must be 'yes' or 'no'"; goto loaderr;
2000 }
44b38ef4 2001 } else if (!strcasecmp(argv[0],"appendonly") && argc == 2) {
2002 if ((server.appendonly = yesnotoi(argv[1])) == -1) {
2003 err = "argument must be 'yes' or 'no'"; goto loaderr;
2004 }
f3b52411
PN
2005 } else if (!strcasecmp(argv[0],"appendfilename") && argc == 2) {
2006 zfree(server.appendfilename);
2007 server.appendfilename = zstrdup(argv[1]);
38db9171 2008 } else if (!strcasecmp(argv[0],"no-appendfsync-on-rewrite")
2009 && argc == 2) {
2010 if ((server.no_appendfsync_on_rewrite= yesnotoi(argv[1])) == -1) {
2011 err = "argument must be 'yes' or 'no'"; goto loaderr;
2012 }
48f0308a 2013 } else if (!strcasecmp(argv[0],"appendfsync") && argc == 2) {
1766c6da 2014 if (!strcasecmp(argv[1],"no")) {
48f0308a 2015 server.appendfsync = APPENDFSYNC_NO;
1766c6da 2016 } else if (!strcasecmp(argv[1],"always")) {
48f0308a 2017 server.appendfsync = APPENDFSYNC_ALWAYS;
1766c6da 2018 } else if (!strcasecmp(argv[1],"everysec")) {
48f0308a 2019 server.appendfsync = APPENDFSYNC_EVERYSEC;
2020 } else {
2021 err = "argument must be 'no', 'always' or 'everysec'";
2022 goto loaderr;
2023 }
bb0b03a3 2024 } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
054e426d 2025 server.requirepass = zstrdup(argv[1]);
bb0b03a3 2026 } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
500ece7c 2027 zfree(server.pidfile);
054e426d 2028 server.pidfile = zstrdup(argv[1]);
bb0b03a3 2029 } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) {
500ece7c 2030 zfree(server.dbfilename);
054e426d 2031 server.dbfilename = zstrdup(argv[1]);
75680a3c 2032 } else if (!strcasecmp(argv[0],"vm-enabled") && argc == 2) {
2033 if ((server.vm_enabled = yesnotoi(argv[1])) == -1) {
2034 err = "argument must be 'yes' or 'no'"; goto loaderr;
2035 }
054e426d 2036 } else if (!strcasecmp(argv[0],"vm-swap-file") && argc == 2) {
fefed597 2037 zfree(server.vm_swap_file);
054e426d 2038 server.vm_swap_file = zstrdup(argv[1]);
4ef8de8a 2039 } else if (!strcasecmp(argv[0],"vm-max-memory") && argc == 2) {
2b619329 2040 server.vm_max_memory = memtoll(argv[1],NULL);
4ef8de8a 2041 } else if (!strcasecmp(argv[0],"vm-page-size") && argc == 2) {
2b619329 2042 server.vm_page_size = memtoll(argv[1], NULL);
4ef8de8a 2043 } else if (!strcasecmp(argv[0],"vm-pages") && argc == 2) {
2b619329 2044 server.vm_pages = memtoll(argv[1], NULL);
92f8e882 2045 } else if (!strcasecmp(argv[0],"vm-max-threads") && argc == 2) {
2046 server.vm_max_threads = strtoll(argv[1], NULL, 10);
cbba7dd7 2047 } else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2){
2b619329 2048 server.hash_max_zipmap_entries = memtoll(argv[1], NULL);
cbba7dd7 2049 } else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2){
2b619329 2050 server.hash_max_zipmap_value = memtoll(argv[1], NULL);
d0686e07
PN
2051 } else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){
2052 server.list_max_ziplist_entries = memtoll(argv[1], NULL);
2053 } else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2){
2054 server.list_max_ziplist_value = memtoll(argv[1], NULL);
ed9b544e 2055 } else {
2056 err = "Bad directive or wrong number of arguments"; goto loaderr;
2057 }
2058 for (j = 0; j < argc; j++)
2059 sdsfree(argv[j]);
2060 zfree(argv);
2061 sdsfree(line);
2062 }
c9a111ac 2063 if (fp != stdin) fclose(fp);
ed9b544e 2064 return;
2065
2066loaderr:
2067 fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n");
2068 fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
2069 fprintf(stderr, ">>> '%s'\n", line);
2070 fprintf(stderr, "%s\n", err);
2071 exit(1);
2072}
2073
2074static void freeClientArgv(redisClient *c) {
2075 int j;
2076
2077 for (j = 0; j < c->argc; j++)
2078 decrRefCount(c->argv[j]);
e8a74421 2079 for (j = 0; j < c->mbargc; j++)
2080 decrRefCount(c->mbargv[j]);
ed9b544e 2081 c->argc = 0;
e8a74421 2082 c->mbargc = 0;
ed9b544e 2083}
2084
2085static void freeClient(redisClient *c) {
2086 listNode *ln;
2087
4409877e 2088 /* Note that if the client we are freeing is blocked into a blocking
b0d8747d 2089 * call, we have to set querybuf to NULL *before* to call
2090 * unblockClientWaitingData() to avoid processInputBuffer() will get
2091 * called. Also it is important to remove the file events after
2092 * this, because this call adds the READABLE event. */
4409877e 2093 sdsfree(c->querybuf);
2094 c->querybuf = NULL;
2095 if (c->flags & REDIS_BLOCKED)
b0d8747d 2096 unblockClientWaitingData(c);
4409877e 2097
37ab76c9 2098 /* UNWATCH all the keys */
2099 unwatchAllKeys(c);
2100 listRelease(c->watched_keys);
ffc6b7f8 2101 /* Unsubscribe from all the pubsub channels */
2102 pubsubUnsubscribeAllChannels(c,0);
2103 pubsubUnsubscribeAllPatterns(c,0);
2104 dictRelease(c->pubsub_channels);
2105 listRelease(c->pubsub_patterns);
befec3cd 2106 /* Obvious cleanup */
ed9b544e 2107 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
2108 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
ed9b544e 2109 listRelease(c->reply);
2110 freeClientArgv(c);
2111 close(c->fd);
92f8e882 2112 /* Remove from the list of clients */
ed9b544e 2113 ln = listSearchKey(server.clients,c);
dfc5e96c 2114 redisAssert(ln != NULL);
ed9b544e 2115 listDelNode(server.clients,ln);
37ab76c9 2116 /* Remove from the list of clients that are now ready to be restarted
2117 * after waiting for swapped keys */
d5d55fc3 2118 if (c->flags & REDIS_IO_WAIT && listLength(c->io_keys) == 0) {
2119 ln = listSearchKey(server.io_ready_clients,c);
2120 if (ln) {
2121 listDelNode(server.io_ready_clients,ln);
2122 server.vm_blocked_clients--;
2123 }
2124 }
37ab76c9 2125 /* Remove from the list of clients waiting for swapped keys */
d5d55fc3 2126 while (server.vm_enabled && listLength(c->io_keys)) {
2127 ln = listFirst(c->io_keys);
2128 dontWaitForSwappedKey(c,ln->value);
92f8e882 2129 }
b3e3d0d7 2130 listRelease(c->io_keys);
befec3cd 2131 /* Master/slave cleanup */
ed9b544e 2132 if (c->flags & REDIS_SLAVE) {
6208b3a7 2133 if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1)
2134 close(c->repldbfd);
87eca727 2135 list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
2136 ln = listSearchKey(l,c);
dfc5e96c 2137 redisAssert(ln != NULL);
87eca727 2138 listDelNode(l,ln);
ed9b544e 2139 }
2140 if (c->flags & REDIS_MASTER) {
2141 server.master = NULL;
2142 server.replstate = REDIS_REPL_CONNECT;
2143 }
befec3cd 2144 /* Release memory */
93ea3759 2145 zfree(c->argv);
e8a74421 2146 zfree(c->mbargv);
6e469882 2147 freeClientMultiState(c);
ed9b544e 2148 zfree(c);
2149}
2150
cc30e368 2151#define GLUEREPLY_UP_TO (1024)
ed9b544e 2152static void glueReplyBuffersIfNeeded(redisClient *c) {
c28b42ac 2153 int copylen = 0;
2154 char buf[GLUEREPLY_UP_TO];
6208b3a7 2155 listNode *ln;
c7df85a4 2156 listIter li;
ed9b544e 2157 robj *o;
2158
c7df85a4 2159 listRewind(c->reply,&li);
2160 while((ln = listNext(&li))) {
c28b42ac 2161 int objlen;
2162
ed9b544e 2163 o = ln->value;
c28b42ac 2164 objlen = sdslen(o->ptr);
2165 if (copylen + objlen <= GLUEREPLY_UP_TO) {
2166 memcpy(buf+copylen,o->ptr,objlen);
2167 copylen += objlen;
ed9b544e 2168 listDelNode(c->reply,ln);
c28b42ac 2169 } else {
2170 if (copylen == 0) return;
2171 break;
ed9b544e 2172 }
ed9b544e 2173 }
c28b42ac 2174 /* Now the output buffer is empty, add the new single element */
2175 o = createObject(REDIS_STRING,sdsnewlen(buf,copylen));
2176 listAddNodeHead(c->reply,o);
ed9b544e 2177}
2178
2179static void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
2180 redisClient *c = privdata;
2181 int nwritten = 0, totwritten = 0, objlen;
2182 robj *o;
2183 REDIS_NOTUSED(el);
2184 REDIS_NOTUSED(mask);
2185
2895e862 2186 /* Use writev() if we have enough buffers to send */
7ea870c0 2187 if (!server.glueoutputbuf &&
e0a62c7f 2188 listLength(c->reply) > REDIS_WRITEV_THRESHOLD &&
7ea870c0 2189 !(c->flags & REDIS_MASTER))
2895e862 2190 {
2191 sendReplyToClientWritev(el, fd, privdata, mask);
2192 return;
2193 }
2895e862 2194
ed9b544e 2195 while(listLength(c->reply)) {
c28b42ac 2196 if (server.glueoutputbuf && listLength(c->reply) > 1)
2197 glueReplyBuffersIfNeeded(c);
2198
ed9b544e 2199 o = listNodeValue(listFirst(c->reply));
2200 objlen = sdslen(o->ptr);
2201
2202 if (objlen == 0) {
2203 listDelNode(c->reply,listFirst(c->reply));
2204 continue;
2205 }
2206
2207 if (c->flags & REDIS_MASTER) {
6f376729 2208 /* Don't reply to a master */
ed9b544e 2209 nwritten = objlen - c->sentlen;
2210 } else {
a4d1ba9a 2211 nwritten = write(fd, ((char*)o->ptr)+c->sentlen, objlen - c->sentlen);
ed9b544e 2212 if (nwritten <= 0) break;
2213 }
2214 c->sentlen += nwritten;
2215 totwritten += nwritten;
2216 /* If we fully sent the object on head go to the next one */
2217 if (c->sentlen == objlen) {
2218 listDelNode(c->reply,listFirst(c->reply));
2219 c->sentlen = 0;
2220 }
6f376729 2221 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
12f9d551 2222 * bytes, in a single threaded server it's a good idea to serve
6f376729 2223 * other clients as well, even if a very large request comes from
2224 * super fast link that is always able to accept data (in real world
12f9d551 2225 * scenario think about 'KEYS *' against the loopback interfae) */
6f376729 2226 if (totwritten > REDIS_MAX_WRITE_PER_EVENT) break;
ed9b544e 2227 }
2228 if (nwritten == -1) {
2229 if (errno == EAGAIN) {
2230 nwritten = 0;
2231 } else {
f870935d 2232 redisLog(REDIS_VERBOSE,
ed9b544e 2233 "Error writing to client: %s", strerror(errno));
2234 freeClient(c);
2235 return;
2236 }
2237 }
2238 if (totwritten > 0) c->lastinteraction = time(NULL);
2239 if (listLength(c->reply) == 0) {
2240 c->sentlen = 0;
2241 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
2242 }
2243}
2244
2895e862 2245static void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask)
2246{
2247 redisClient *c = privdata;
2248 int nwritten = 0, totwritten = 0, objlen, willwrite;
2249 robj *o;
2250 struct iovec iov[REDIS_WRITEV_IOVEC_COUNT];
2251 int offset, ion = 0;
2252 REDIS_NOTUSED(el);
2253 REDIS_NOTUSED(mask);
2254
2255 listNode *node;
2256 while (listLength(c->reply)) {
2257 offset = c->sentlen;
2258 ion = 0;
2259 willwrite = 0;
2260
2261 /* fill-in the iov[] array */
2262 for(node = listFirst(c->reply); node; node = listNextNode(node)) {
2263 o = listNodeValue(node);
2264 objlen = sdslen(o->ptr);
2265
e0a62c7f 2266 if (totwritten + objlen - offset > REDIS_MAX_WRITE_PER_EVENT)
2895e862 2267 break;
2268
2269 if(ion == REDIS_WRITEV_IOVEC_COUNT)
2270 break; /* no more iovecs */
2271
2272 iov[ion].iov_base = ((char*)o->ptr) + offset;
2273 iov[ion].iov_len = objlen - offset;
2274 willwrite += objlen - offset;
2275 offset = 0; /* just for the first item */
2276 ion++;
2277 }
2278
2279 if(willwrite == 0)
2280 break;
2281
2282 /* write all collected blocks at once */
2283 if((nwritten = writev(fd, iov, ion)) < 0) {
2284 if (errno != EAGAIN) {
f870935d 2285 redisLog(REDIS_VERBOSE,
2895e862 2286 "Error writing to client: %s", strerror(errno));
2287 freeClient(c);
2288 return;
2289 }
2290 break;
2291 }
2292
2293 totwritten += nwritten;
2294 offset = c->sentlen;
2295
2296 /* remove written robjs from c->reply */
2297 while (nwritten && listLength(c->reply)) {
2298 o = listNodeValue(listFirst(c->reply));
2299 objlen = sdslen(o->ptr);
2300
2301 if(nwritten >= objlen - offset) {
2302 listDelNode(c->reply, listFirst(c->reply));
2303 nwritten -= objlen - offset;
2304 c->sentlen = 0;
2305 } else {
2306 /* partial write */
2307 c->sentlen += nwritten;
2308 break;
2309 }
2310 offset = 0;
2311 }
2312 }
2313
e0a62c7f 2314 if (totwritten > 0)
2895e862 2315 c->lastinteraction = time(NULL);
2316
2317 if (listLength(c->reply) == 0) {
2318 c->sentlen = 0;
2319 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
2320 }
2321}
2322
1a132bbc
PN
2323static int qsortRedisCommands(const void *r1, const void *r2) {
2324 return strcasecmp(
2325 ((struct redisCommand*)r1)->name,
2326 ((struct redisCommand*)r2)->name);
2327}
2328
2329static void sortCommandTable() {
1a132bbc
PN
2330 /* Copy and sort the read-only version of the command table */
2331 commandTable = (struct redisCommand*)malloc(sizeof(readonlyCommandTable));
2332 memcpy(commandTable,readonlyCommandTable,sizeof(readonlyCommandTable));
d55d5c5d 2333 qsort(commandTable,
2334 sizeof(readonlyCommandTable)/sizeof(struct redisCommand),
2335 sizeof(struct redisCommand),qsortRedisCommands);
1a132bbc
PN
2336}
2337
ed9b544e 2338static struct redisCommand *lookupCommand(char *name) {
1a132bbc
PN
2339 struct redisCommand tmp = {name,NULL,0,0,NULL,0,0,0};
2340 return bsearch(
2341 &tmp,
2342 commandTable,
d55d5c5d 2343 sizeof(readonlyCommandTable)/sizeof(struct redisCommand),
1a132bbc
PN
2344 sizeof(struct redisCommand),
2345 qsortRedisCommands);
ed9b544e 2346}
2347
2348/* resetClient prepare the client to process the next command */
2349static void resetClient(redisClient *c) {
2350 freeClientArgv(c);
2351 c->bulklen = -1;
e8a74421 2352 c->multibulk = 0;
ed9b544e 2353}
2354
6e469882 2355/* Call() is the core of Redis execution of a command */
2356static void call(redisClient *c, struct redisCommand *cmd) {
2357 long long dirty;
2358
2359 dirty = server.dirty;
2360 cmd->proc(c);
4005fef1 2361 dirty = server.dirty-dirty;
2362
2363 if (server.appendonly && dirty)
6e469882 2364 feedAppendOnlyFile(cmd,c->db->id,c->argv,c->argc);
4005fef1 2365 if ((dirty || cmd->flags & REDIS_CMD_FORCE_REPLICATION) &&
2366 listLength(server.slaves))
248ea310 2367 replicationFeedSlaves(server.slaves,c->db->id,c->argv,c->argc);
6e469882 2368 if (listLength(server.monitors))
dd142b9c 2369 replicationFeedMonitors(server.monitors,c->db->id,c->argv,c->argc);
6e469882 2370 server.stat_numcommands++;
2371}
2372
ed9b544e 2373/* If this function gets called we already read a whole
2374 * command, argments are in the client argv/argc fields.
2375 * processCommand() execute the command or prepare the
2376 * server for a bulk read from the client.
2377 *
2378 * If 1 is returned the client is still alive and valid and
2379 * and other operations can be performed by the caller. Otherwise
2380 * if 0 is returned the client was destroied (i.e. after QUIT). */
2381static int processCommand(redisClient *c) {
2382 struct redisCommand *cmd;
ed9b544e 2383
3fd78bcd 2384 /* Free some memory if needed (maxmemory setting) */
2385 if (server.maxmemory) freeMemoryIfNeeded();
2386
e8a74421 2387 /* Handle the multi bulk command type. This is an alternative protocol
2388 * supported by Redis in order to receive commands that are composed of
2389 * multiple binary-safe "bulk" arguments. The latency of processing is
2390 * a bit higher but this allows things like multi-sets, so if this
2391 * protocol is used only for MSET and similar commands this is a big win. */
2392 if (c->multibulk == 0 && c->argc == 1 && ((char*)(c->argv[0]->ptr))[0] == '*') {
2393 c->multibulk = atoi(((char*)c->argv[0]->ptr)+1);
2394 if (c->multibulk <= 0) {
2395 resetClient(c);
2396 return 1;
2397 } else {
2398 decrRefCount(c->argv[c->argc-1]);
2399 c->argc--;
2400 return 1;
2401 }
2402 } else if (c->multibulk) {
2403 if (c->bulklen == -1) {
2404 if (((char*)c->argv[0]->ptr)[0] != '$') {
2405 addReplySds(c,sdsnew("-ERR multi bulk protocol error\r\n"));
2406 resetClient(c);
2407 return 1;
2408 } else {
2409 int bulklen = atoi(((char*)c->argv[0]->ptr)+1);
2410 decrRefCount(c->argv[0]);
2411 if (bulklen < 0 || bulklen > 1024*1024*1024) {
2412 c->argc--;
2413 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
2414 resetClient(c);
2415 return 1;
2416 }
2417 c->argc--;
2418 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
2419 return 1;
2420 }
2421 } else {
2422 c->mbargv = zrealloc(c->mbargv,(sizeof(robj*))*(c->mbargc+1));
2423 c->mbargv[c->mbargc] = c->argv[0];
2424 c->mbargc++;
2425 c->argc--;
2426 c->multibulk--;
2427 if (c->multibulk == 0) {
2428 robj **auxargv;
2429 int auxargc;
2430
2431 /* Here we need to swap the multi-bulk argc/argv with the
2432 * normal argc/argv of the client structure. */
2433 auxargv = c->argv;
2434 c->argv = c->mbargv;
2435 c->mbargv = auxargv;
2436
2437 auxargc = c->argc;
2438 c->argc = c->mbargc;
2439 c->mbargc = auxargc;
2440
2441 /* We need to set bulklen to something different than -1
2442 * in order for the code below to process the command without
2443 * to try to read the last argument of a bulk command as
2444 * a special argument. */
2445 c->bulklen = 0;
2446 /* continue below and process the command */
2447 } else {
2448 c->bulklen = -1;
2449 return 1;
2450 }
2451 }
2452 }
2453 /* -- end of multi bulk commands processing -- */
2454
ed9b544e 2455 /* The QUIT command is handled as a special case. Normal command
2456 * procs are unable to close the client connection safely */
bb0b03a3 2457 if (!strcasecmp(c->argv[0]->ptr,"quit")) {
ed9b544e 2458 freeClient(c);
2459 return 0;
2460 }
d5d55fc3 2461
2462 /* Now lookup the command and check ASAP about trivial error conditions
2463 * such wrong arity, bad command name and so forth. */
ed9b544e 2464 cmd = lookupCommand(c->argv[0]->ptr);
2465 if (!cmd) {
2c14807b 2466 addReplySds(c,
2467 sdscatprintf(sdsempty(), "-ERR unknown command '%s'\r\n",
2468 (char*)c->argv[0]->ptr));
ed9b544e 2469 resetClient(c);
2470 return 1;
2471 } else if ((cmd->arity > 0 && cmd->arity != c->argc) ||
2472 (c->argc < -cmd->arity)) {
454d4e43 2473 addReplySds(c,
2474 sdscatprintf(sdsempty(),
2475 "-ERR wrong number of arguments for '%s' command\r\n",
2476 cmd->name));
ed9b544e 2477 resetClient(c);
2478 return 1;
2479 } else if (cmd->flags & REDIS_CMD_BULK && c->bulklen == -1) {
d5d55fc3 2480 /* This is a bulk command, we have to read the last argument yet. */
ed9b544e 2481 int bulklen = atoi(c->argv[c->argc-1]->ptr);
2482
2483 decrRefCount(c->argv[c->argc-1]);
2484 if (bulklen < 0 || bulklen > 1024*1024*1024) {
2485 c->argc--;
2486 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
2487 resetClient(c);
2488 return 1;
2489 }
2490 c->argc--;
2491 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
2492 /* It is possible that the bulk read is already in the
8d0490e7 2493 * buffer. Check this condition and handle it accordingly.
2494 * This is just a fast path, alternative to call processInputBuffer().
2495 * It's a good idea since the code is small and this condition
2496 * happens most of the times. */
ed9b544e 2497 if ((signed)sdslen(c->querybuf) >= c->bulklen) {
2498 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
2499 c->argc++;
2500 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
2501 } else {
d5d55fc3 2502 /* Otherwise return... there is to read the last argument
2503 * from the socket. */
ed9b544e 2504 return 1;
2505 }
2506 }
942a3961 2507 /* Let's try to encode the bulk object to save space. */
2508 if (cmd->flags & REDIS_CMD_BULK)
05df7621 2509 c->argv[c->argc-1] = tryObjectEncoding(c->argv[c->argc-1]);
942a3961 2510
e63943a4 2511 /* Check if the user is authenticated */
2512 if (server.requirepass && !c->authenticated && cmd->proc != authCommand) {
2513 addReplySds(c,sdsnew("-ERR operation not permitted\r\n"));
2514 resetClient(c);
2515 return 1;
2516 }
2517
b61a28fe 2518 /* Handle the maxmemory directive */
2519 if (server.maxmemory && (cmd->flags & REDIS_CMD_DENYOOM) &&
2520 zmalloc_used_memory() > server.maxmemory)
2521 {
2522 addReplySds(c,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
2523 resetClient(c);
2524 return 1;
2525 }
2526
d6cc8867 2527 /* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
e6cca5db 2528 if ((dictSize(c->pubsub_channels) > 0 || listLength(c->pubsub_patterns) > 0)
2529 &&
ffc6b7f8 2530 cmd->proc != subscribeCommand && cmd->proc != unsubscribeCommand &&
2531 cmd->proc != psubscribeCommand && cmd->proc != punsubscribeCommand) {
2532 addReplySds(c,sdsnew("-ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context\r\n"));
d6cc8867 2533 resetClient(c);
2534 return 1;
2535 }
2536
ed9b544e 2537 /* Exec the command */
6531c94d 2538 if (c->flags & REDIS_MULTI &&
2539 cmd->proc != execCommand && cmd->proc != discardCommand &&
2540 cmd->proc != multiCommand && cmd->proc != watchCommand)
2541 {
6e469882 2542 queueMultiCommand(c,cmd);
2543 addReply(c,shared.queued);
2544 } else {
d5d55fc3 2545 if (server.vm_enabled && server.vm_max_threads > 0 &&
0a6f3f0f 2546 blockClientOnSwappedKeys(c,cmd)) return 1;
6e469882 2547 call(c,cmd);
2548 }
ed9b544e 2549
2550 /* Prepare the client for the next command */
ed9b544e 2551 resetClient(c);
2552 return 1;
2553}
2554
248ea310 2555static void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc) {
6208b3a7 2556 listNode *ln;
c7df85a4 2557 listIter li;
ed9b544e 2558 int outc = 0, j;
93ea3759 2559 robj **outv;
248ea310 2560 /* We need 1+(ARGS*3) objects since commands are using the new protocol
2561 * and we one 1 object for the first "*<count>\r\n" multibulk count, then
2562 * for every additional object we have "$<count>\r\n" + object + "\r\n". */
2563 robj *static_outv[REDIS_STATIC_ARGS*3+1];
2564 robj *lenobj;
93ea3759 2565
2566 if (argc <= REDIS_STATIC_ARGS) {
2567 outv = static_outv;
2568 } else {
248ea310 2569 outv = zmalloc(sizeof(robj*)*(argc*3+1));
93ea3759 2570 }
248ea310 2571
2572 lenobj = createObject(REDIS_STRING,
2573 sdscatprintf(sdsempty(), "*%d\r\n", argc));
2574 lenobj->refcount = 0;
2575 outv[outc++] = lenobj;
ed9b544e 2576 for (j = 0; j < argc; j++) {
248ea310 2577 lenobj = createObject(REDIS_STRING,
2578 sdscatprintf(sdsempty(),"$%lu\r\n",
2579 (unsigned long) stringObjectLen(argv[j])));
2580 lenobj->refcount = 0;
2581 outv[outc++] = lenobj;
ed9b544e 2582 outv[outc++] = argv[j];
248ea310 2583 outv[outc++] = shared.crlf;
ed9b544e 2584 }
ed9b544e 2585
40d224a9 2586 /* Increment all the refcounts at start and decrement at end in order to
2587 * be sure to free objects if there is no slave in a replication state
2588 * able to be feed with commands */
2589 for (j = 0; j < outc; j++) incrRefCount(outv[j]);
c7df85a4 2590 listRewind(slaves,&li);
2591 while((ln = listNext(&li))) {
ed9b544e 2592 redisClient *slave = ln->value;
40d224a9 2593
2594 /* Don't feed slaves that are still waiting for BGSAVE to start */
6208b3a7 2595 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) continue;
40d224a9 2596
2597 /* Feed all the other slaves, MONITORs and so on */
ed9b544e 2598 if (slave->slaveseldb != dictid) {
2599 robj *selectcmd;
2600
2601 switch(dictid) {
2602 case 0: selectcmd = shared.select0; break;
2603 case 1: selectcmd = shared.select1; break;
2604 case 2: selectcmd = shared.select2; break;
2605 case 3: selectcmd = shared.select3; break;
2606 case 4: selectcmd = shared.select4; break;
2607 case 5: selectcmd = shared.select5; break;
2608 case 6: selectcmd = shared.select6; break;
2609 case 7: selectcmd = shared.select7; break;
2610 case 8: selectcmd = shared.select8; break;
2611 case 9: selectcmd = shared.select9; break;
2612 default:
2613 selectcmd = createObject(REDIS_STRING,
2614 sdscatprintf(sdsempty(),"select %d\r\n",dictid));
2615 selectcmd->refcount = 0;
2616 break;
2617 }
2618 addReply(slave,selectcmd);
2619 slave->slaveseldb = dictid;
2620 }
2621 for (j = 0; j < outc; j++) addReply(slave,outv[j]);
ed9b544e 2622 }
40d224a9 2623 for (j = 0; j < outc; j++) decrRefCount(outv[j]);
93ea3759 2624 if (outv != static_outv) zfree(outv);
ed9b544e 2625}
2626
dd142b9c 2627static sds sdscatrepr(sds s, char *p, size_t len) {
2628 s = sdscatlen(s,"\"",1);
2629 while(len--) {
2630 switch(*p) {
2631 case '\\':
2632 case '"':
2633 s = sdscatprintf(s,"\\%c",*p);
2634 break;
2635 case '\n': s = sdscatlen(s,"\\n",1); break;
2636 case '\r': s = sdscatlen(s,"\\r",1); break;
2637 case '\t': s = sdscatlen(s,"\\t",1); break;
2638 case '\a': s = sdscatlen(s,"\\a",1); break;
2639 case '\b': s = sdscatlen(s,"\\b",1); break;
2640 default:
2641 if (isprint(*p))
2642 s = sdscatprintf(s,"%c",*p);
2643 else
2644 s = sdscatprintf(s,"\\x%02x",(unsigned char)*p);
2645 break;
2646 }
2647 p++;
2648 }
2649 return sdscatlen(s,"\"",1);
2650}
2651
2652static void replicationFeedMonitors(list *monitors, int dictid, robj **argv, int argc) {
2653 listNode *ln;
2654 listIter li;
2655 int j;
2656 sds cmdrepr = sdsnew("+");
2657 robj *cmdobj;
2658 struct timeval tv;
2659
2660 gettimeofday(&tv,NULL);
2661 cmdrepr = sdscatprintf(cmdrepr,"%ld.%ld ",(long)tv.tv_sec,(long)tv.tv_usec);
2662 if (dictid != 0) cmdrepr = sdscatprintf(cmdrepr,"(db %d) ", dictid);
2663
2664 for (j = 0; j < argc; j++) {
2665 if (argv[j]->encoding == REDIS_ENCODING_INT) {
2666 cmdrepr = sdscatprintf(cmdrepr, "%ld", (long)argv[j]->ptr);
2667 } else {
2668 cmdrepr = sdscatrepr(cmdrepr,(char*)argv[j]->ptr,
2669 sdslen(argv[j]->ptr));
2670 }
2671 if (j != argc-1)
2672 cmdrepr = sdscatlen(cmdrepr," ",1);
2673 }
2674 cmdrepr = sdscatlen(cmdrepr,"\r\n",2);
2675 cmdobj = createObject(REDIS_STRING,cmdrepr);
2676
2677 listRewind(monitors,&li);
2678 while((ln = listNext(&li))) {
2679 redisClient *monitor = ln->value;
2680 addReply(monitor,cmdobj);
2681 }
2682 decrRefCount(cmdobj);
2683}
2684
638e42ac 2685static void processInputBuffer(redisClient *c) {
ed9b544e 2686again:
4409877e 2687 /* Before to process the input buffer, make sure the client is not
2688 * waitig for a blocking operation such as BLPOP. Note that the first
2689 * iteration the client is never blocked, otherwise the processInputBuffer
2690 * would not be called at all, but after the execution of the first commands
2691 * in the input buffer the client may be blocked, and the "goto again"
2692 * will try to reiterate. The following line will make it return asap. */
92f8e882 2693 if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return;
ed9b544e 2694 if (c->bulklen == -1) {
2695 /* Read the first line of the query */
2696 char *p = strchr(c->querybuf,'\n');
2697 size_t querylen;
644fafa3 2698
ed9b544e 2699 if (p) {
2700 sds query, *argv;
2701 int argc, j;
e0a62c7f 2702
ed9b544e 2703 query = c->querybuf;
2704 c->querybuf = sdsempty();
2705 querylen = 1+(p-(query));
2706 if (sdslen(query) > querylen) {
2707 /* leave data after the first line of the query in the buffer */
2708 c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
2709 }
2710 *p = '\0'; /* remove "\n" */
2711 if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
2712 sdsupdatelen(query);
2713
2714 /* Now we can split the query in arguments */
ed9b544e 2715 argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
93ea3759 2716 sdsfree(query);
2717
2718 if (c->argv) zfree(c->argv);
2719 c->argv = zmalloc(sizeof(robj*)*argc);
93ea3759 2720
2721 for (j = 0; j < argc; j++) {
ed9b544e 2722 if (sdslen(argv[j])) {
2723 c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
2724 c->argc++;
2725 } else {
2726 sdsfree(argv[j]);
2727 }
2728 }
2729 zfree(argv);
7c49733c 2730 if (c->argc) {
2731 /* Execute the command. If the client is still valid
2732 * after processCommand() return and there is something
2733 * on the query buffer try to process the next command. */
2734 if (processCommand(c) && sdslen(c->querybuf)) goto again;
2735 } else {
2736 /* Nothing to process, argc == 0. Just process the query
2737 * buffer if it's not empty or return to the caller */
2738 if (sdslen(c->querybuf)) goto again;
2739 }
ed9b544e 2740 return;
644fafa3 2741 } else if (sdslen(c->querybuf) >= REDIS_REQUEST_MAX_SIZE) {
f870935d 2742 redisLog(REDIS_VERBOSE, "Client protocol error");
ed9b544e 2743 freeClient(c);
2744 return;
2745 }
2746 } else {
2747 /* Bulk read handling. Note that if we are at this point
2748 the client already sent a command terminated with a newline,
2749 we are reading the bulk data that is actually the last
2750 argument of the command. */
2751 int qbl = sdslen(c->querybuf);
2752
2753 if (c->bulklen <= qbl) {
2754 /* Copy everything but the final CRLF as final argument */
2755 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
2756 c->argc++;
2757 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
638e42ac 2758 /* Process the command. If the client is still valid after
2759 * the processing and there is more data in the buffer
2760 * try to parse it. */
2761 if (processCommand(c) && sdslen(c->querybuf)) goto again;
ed9b544e 2762 return;
2763 }
2764 }
2765}
2766
638e42ac 2767static void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
2768 redisClient *c = (redisClient*) privdata;
2769 char buf[REDIS_IOBUF_LEN];
2770 int nread;
2771 REDIS_NOTUSED(el);
2772 REDIS_NOTUSED(mask);
2773
2774 nread = read(fd, buf, REDIS_IOBUF_LEN);
2775 if (nread == -1) {
2776 if (errno == EAGAIN) {
2777 nread = 0;
2778 } else {
f870935d 2779 redisLog(REDIS_VERBOSE, "Reading from client: %s",strerror(errno));
638e42ac 2780 freeClient(c);
2781 return;
2782 }
2783 } else if (nread == 0) {
f870935d 2784 redisLog(REDIS_VERBOSE, "Client closed connection");
638e42ac 2785 freeClient(c);
2786 return;
2787 }
2788 if (nread) {
2789 c->querybuf = sdscatlen(c->querybuf, buf, nread);
2790 c->lastinteraction = time(NULL);
2791 } else {
2792 return;
2793 }
168ac5c6 2794 processInputBuffer(c);
638e42ac 2795}
2796
ed9b544e 2797static int selectDb(redisClient *c, int id) {
2798 if (id < 0 || id >= server.dbnum)
2799 return REDIS_ERR;
3305306f 2800 c->db = &server.db[id];
ed9b544e 2801 return REDIS_OK;
2802}
2803
40d224a9 2804static void *dupClientReplyValue(void *o) {
2805 incrRefCount((robj*)o);
12d090d2 2806 return o;
40d224a9 2807}
2808
ffc6b7f8 2809static int listMatchObjects(void *a, void *b) {
bf028098 2810 return equalStringObjects(a,b);
ffc6b7f8 2811}
2812
ed9b544e 2813static redisClient *createClient(int fd) {
2814 redisClient *c = zmalloc(sizeof(*c));
2815
2816 anetNonBlock(NULL,fd);
2817 anetTcpNoDelay(NULL,fd);
2818 if (!c) return NULL;
2819 selectDb(c,0);
2820 c->fd = fd;
2821 c->querybuf = sdsempty();
2822 c->argc = 0;
93ea3759 2823 c->argv = NULL;
ed9b544e 2824 c->bulklen = -1;
e8a74421 2825 c->multibulk = 0;
2826 c->mbargc = 0;
2827 c->mbargv = NULL;
ed9b544e 2828 c->sentlen = 0;
2829 c->flags = 0;
2830 c->lastinteraction = time(NULL);
abcb223e 2831 c->authenticated = 0;
40d224a9 2832 c->replstate = REDIS_REPL_NONE;
6b47e12e 2833 c->reply = listCreate();
ed9b544e 2834 listSetFreeMethod(c->reply,decrRefCount);
40d224a9 2835 listSetDupMethod(c->reply,dupClientReplyValue);
37ab76c9 2836 c->blocking_keys = NULL;
2837 c->blocking_keys_num = 0;
92f8e882 2838 c->io_keys = listCreate();
87c68815 2839 c->watched_keys = listCreate();
92f8e882 2840 listSetFreeMethod(c->io_keys,decrRefCount);
ffc6b7f8 2841 c->pubsub_channels = dictCreate(&setDictType,NULL);
2842 c->pubsub_patterns = listCreate();
2843 listSetFreeMethod(c->pubsub_patterns,decrRefCount);
2844 listSetMatchMethod(c->pubsub_patterns,listMatchObjects);
ed9b544e 2845 if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
266373b2 2846 readQueryFromClient, c) == AE_ERR) {
ed9b544e 2847 freeClient(c);
2848 return NULL;
2849 }
6b47e12e 2850 listAddNodeTail(server.clients,c);
6e469882 2851 initClientMultiState(c);
ed9b544e 2852 return c;
2853}
2854
2855static void addReply(redisClient *c, robj *obj) {
2856 if (listLength(c->reply) == 0 &&
6208b3a7 2857 (c->replstate == REDIS_REPL_NONE ||
2858 c->replstate == REDIS_REPL_ONLINE) &&
ed9b544e 2859 aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
266373b2 2860 sendReplyToClient, c) == AE_ERR) return;
e3cadb8a 2861
2862 if (server.vm_enabled && obj->storage != REDIS_VM_MEMORY) {
2863 obj = dupStringObject(obj);
2864 obj->refcount = 0; /* getDecodedObject() will increment the refcount */
2865 }
9d65a1bb 2866 listAddNodeTail(c->reply,getDecodedObject(obj));
ed9b544e 2867}
2868
2869static void addReplySds(redisClient *c, sds s) {
2870 robj *o = createObject(REDIS_STRING,s);
2871 addReply(c,o);
2872 decrRefCount(o);
2873}
2874
e2665397 2875static void addReplyDouble(redisClient *c, double d) {
2876 char buf[128];
2877
2878 snprintf(buf,sizeof(buf),"%.17g",d);
682ac724 2879 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n%s\r\n",
83c6a618 2880 (unsigned long) strlen(buf),buf));
e2665397 2881}
2882
aa7c2934
PN
2883static void addReplyLongLong(redisClient *c, long long ll) {
2884 char buf[128];
2885 size_t len;
2886
2887 if (ll == 0) {
2888 addReply(c,shared.czero);
2889 return;
2890 } else if (ll == 1) {
2891 addReply(c,shared.cone);
2892 return;
2893 }
482b672d 2894 buf[0] = ':';
2895 len = ll2string(buf+1,sizeof(buf)-1,ll);
2896 buf[len+1] = '\r';
2897 buf[len+2] = '\n';
2898 addReplySds(c,sdsnewlen(buf,len+3));
aa7c2934
PN
2899}
2900
92b27fe9 2901static void addReplyUlong(redisClient *c, unsigned long ul) {
2902 char buf[128];
2903 size_t len;
2904
dd88747b 2905 if (ul == 0) {
2906 addReply(c,shared.czero);
2907 return;
2908 } else if (ul == 1) {
2909 addReply(c,shared.cone);
2910 return;
2911 }
92b27fe9 2912 len = snprintf(buf,sizeof(buf),":%lu\r\n",ul);
2913 addReplySds(c,sdsnewlen(buf,len));
2914}
2915
942a3961 2916static void addReplyBulkLen(redisClient *c, robj *obj) {
482b672d 2917 size_t len, intlen;
2918 char buf[128];
942a3961 2919
2920 if (obj->encoding == REDIS_ENCODING_RAW) {
2921 len = sdslen(obj->ptr);
2922 } else {
2923 long n = (long)obj->ptr;
2924
e054afda 2925 /* Compute how many bytes will take this integer as a radix 10 string */
942a3961 2926 len = 1;
2927 if (n < 0) {
2928 len++;
2929 n = -n;
2930 }
2931 while((n = n/10) != 0) {
2932 len++;
2933 }
2934 }
482b672d 2935 buf[0] = '$';
2936 intlen = ll2string(buf+1,sizeof(buf)-1,(long long)len);
2937 buf[intlen+1] = '\r';
2938 buf[intlen+2] = '\n';
2939 addReplySds(c,sdsnewlen(buf,intlen+3));
942a3961 2940}
2941
dd88747b 2942static void addReplyBulk(redisClient *c, robj *obj) {
2943 addReplyBulkLen(c,obj);
2944 addReply(c,obj);
2945 addReply(c,shared.crlf);
2946}
2947
09241813 2948static void addReplyBulkSds(redisClient *c, sds s) {
2949 robj *o = createStringObject(s, sdslen(s));
2950 addReplyBulk(c,o);
2951 decrRefCount(o);
2952}
2953
500ece7c 2954/* In the CONFIG command we need to add vanilla C string as bulk replies */
2955static void addReplyBulkCString(redisClient *c, char *s) {
2956 if (s == NULL) {
2957 addReply(c,shared.nullbulk);
2958 } else {
2959 robj *o = createStringObject(s,strlen(s));
2960 addReplyBulk(c,o);
2961 decrRefCount(o);
2962 }
2963}
2964
ed9b544e 2965static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
2966 int cport, cfd;
2967 char cip[128];
285add55 2968 redisClient *c;
ed9b544e 2969 REDIS_NOTUSED(el);
2970 REDIS_NOTUSED(mask);
2971 REDIS_NOTUSED(privdata);
2972
2973 cfd = anetAccept(server.neterr, fd, cip, &cport);
2974 if (cfd == AE_ERR) {
f870935d 2975 redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr);
ed9b544e 2976 return;
2977 }
f870935d 2978 redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport);
285add55 2979 if ((c = createClient(cfd)) == NULL) {
ed9b544e 2980 redisLog(REDIS_WARNING,"Error allocating resoures for the client");
2981 close(cfd); /* May be already closed, just ingore errors */
2982 return;
2983 }
285add55 2984 /* If maxclient directive is set and this is one client more... close the
2985 * connection. Note that we create the client instead to check before
2986 * for this condition, since now the socket is already set in nonblocking
2987 * mode and we can send an error for free using the Kernel I/O */
2988 if (server.maxclients && listLength(server.clients) > server.maxclients) {
2989 char *err = "-ERR max number of clients reached\r\n";
2990
2991 /* That's a best effort error message, don't check write errors */
fee803ba 2992 if (write(c->fd,err,strlen(err)) == -1) {
2993 /* Nothing to do, Just to avoid the warning... */
2994 }
285add55 2995 freeClient(c);
2996 return;
2997 }
ed9b544e 2998 server.stat_numconnections++;
2999}
3000
3001/* ======================= Redis objects implementation ===================== */
3002
3003static robj *createObject(int type, void *ptr) {
3004 robj *o;
3005
a5819310 3006 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
ed9b544e 3007 if (listLength(server.objfreelist)) {
3008 listNode *head = listFirst(server.objfreelist);
3009 o = listNodeValue(head);
3010 listDelNode(server.objfreelist,head);
a5819310 3011 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
ed9b544e 3012 } else {
560db612 3013 if (server.vm_enabled)
a5819310 3014 pthread_mutex_unlock(&server.obj_freelist_mutex);
560db612 3015 o = zmalloc(sizeof(*o));
ed9b544e 3016 }
ed9b544e 3017 o->type = type;
942a3961 3018 o->encoding = REDIS_ENCODING_RAW;
ed9b544e 3019 o->ptr = ptr;
3020 o->refcount = 1;
3a66edc7 3021 if (server.vm_enabled) {
1064ef87 3022 /* Note that this code may run in the context of an I/O thread
560db612 3023 * and accessing server.lruclock in theory is an error
1064ef87 3024 * (no locks). But in practice this is safe, and even if we read
560db612 3025 * garbage Redis will not fail. */
3026 o->lru = server.lruclock;
3a66edc7 3027 o->storage = REDIS_VM_MEMORY;
3028 }
ed9b544e 3029 return o;
3030}
3031
3032static robj *createStringObject(char *ptr, size_t len) {
3033 return createObject(REDIS_STRING,sdsnewlen(ptr,len));
3034}
3035
3f973463
PN
3036static robj *createStringObjectFromLongLong(long long value) {
3037 robj *o;
3038 if (value >= 0 && value < REDIS_SHARED_INTEGERS) {
3039 incrRefCount(shared.integers[value]);
3040 o = shared.integers[value];
3041 } else {
3f973463 3042 if (value >= LONG_MIN && value <= LONG_MAX) {
10dea8dc 3043 o = createObject(REDIS_STRING, NULL);
3f973463
PN
3044 o->encoding = REDIS_ENCODING_INT;
3045 o->ptr = (void*)((long)value);
3046 } else {
ee14da56 3047 o = createObject(REDIS_STRING,sdsfromlonglong(value));
3f973463
PN
3048 }
3049 }
3050 return o;
3051}
3052
4ef8de8a 3053static robj *dupStringObject(robj *o) {
b9bc0eef 3054 assert(o->encoding == REDIS_ENCODING_RAW);
4ef8de8a 3055 return createStringObject(o->ptr,sdslen(o->ptr));
3056}
3057
ed9b544e 3058static robj *createListObject(void) {
3059 list *l = listCreate();
1cd92e7f 3060 robj *o = createObject(REDIS_LIST,l);
ed9b544e 3061 listSetFreeMethod(l,decrRefCount);
7e79de54 3062 o->encoding = REDIS_ENCODING_LINKEDLIST;
1cd92e7f
PN
3063 return o;
3064}
3065
3066static robj *createZiplistObject(void) {
3067 unsigned char *zl = ziplistNew();
3068 robj *o = createObject(REDIS_LIST,zl);
3069 o->encoding = REDIS_ENCODING_ZIPLIST;
3070 return o;
ed9b544e 3071}
3072
3073static robj *createSetObject(void) {
3074 dict *d = dictCreate(&setDictType,NULL);
ed9b544e 3075 return createObject(REDIS_SET,d);
3076}
3077
5234952b 3078static robj *createHashObject(void) {
3079 /* All the Hashes start as zipmaps. Will be automatically converted
3080 * into hash tables if there are enough elements or big elements
3081 * inside. */
3082 unsigned char *zm = zipmapNew();
3083 robj *o = createObject(REDIS_HASH,zm);
3084 o->encoding = REDIS_ENCODING_ZIPMAP;
3085 return o;
3086}
3087
1812e024 3088static robj *createZsetObject(void) {
6b47e12e 3089 zset *zs = zmalloc(sizeof(*zs));
3090
3091 zs->dict = dictCreate(&zsetDictType,NULL);
3092 zs->zsl = zslCreate();
3093 return createObject(REDIS_ZSET,zs);
1812e024 3094}
3095
ed9b544e 3096static void freeStringObject(robj *o) {
942a3961 3097 if (o->encoding == REDIS_ENCODING_RAW) {
3098 sdsfree(o->ptr);
3099 }
ed9b544e 3100}
3101
3102static void freeListObject(robj *o) {
c7d9d662 3103 switch (o->encoding) {
7e79de54 3104 case REDIS_ENCODING_LINKEDLIST:
c7d9d662
PN
3105 listRelease((list*) o->ptr);
3106 break;
3107 case REDIS_ENCODING_ZIPLIST:
3108 zfree(o->ptr);
3109 break;
3110 default:
3111 redisPanic("Unknown list encoding type");
3112 }
ed9b544e 3113}
3114
3115static void freeSetObject(robj *o) {
3116 dictRelease((dict*) o->ptr);
3117}
3118
fd8ccf44 3119static void freeZsetObject(robj *o) {
3120 zset *zs = o->ptr;
3121
3122 dictRelease(zs->dict);
3123 zslFree(zs->zsl);
3124 zfree(zs);
3125}
3126
ed9b544e 3127static void freeHashObject(robj *o) {
cbba7dd7 3128 switch (o->encoding) {
3129 case REDIS_ENCODING_HT:
3130 dictRelease((dict*) o->ptr);
3131 break;
3132 case REDIS_ENCODING_ZIPMAP:
3133 zfree(o->ptr);
3134 break;
3135 default:
f83c6cb5 3136 redisPanic("Unknown hash encoding type");
cbba7dd7 3137 break;
3138 }
ed9b544e 3139}
3140
3141static void incrRefCount(robj *o) {
3142 o->refcount++;
3143}
3144
3145static void decrRefCount(void *obj) {
3146 robj *o = obj;
94754ccc 3147
560db612 3148 /* Object is a swapped out value, or in the process of being loaded. */
996cb5f7 3149 if (server.vm_enabled &&
3150 (o->storage == REDIS_VM_SWAPPED || o->storage == REDIS_VM_LOADING))
3151 {
560db612 3152 vmpointer *vp = obj;
3153 if (o->storage == REDIS_VM_LOADING) vmCancelThreadedIOJob(o);
3154 vmMarkPagesFree(vp->page,vp->usedpages);
7d98e08c 3155 server.vm_stats_swapped_objects--;
560db612 3156 zfree(vp);
a35ddf12 3157 return;
3158 }
560db612 3159
3160 if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0");
e4ed181d 3161 /* Object is in memory, or in the process of being swapped out.
3162 *
3163 * If the object is being swapped out, abort the operation on
3164 * decrRefCount even if the refcount does not drop to 0: the object
3165 * is referenced at least two times, as value of the key AND as
3166 * job->val in the iojob. So if we don't invalidate the iojob, when it is
3167 * done but the relevant key was removed in the meantime, the
3168 * complete jobs handler will not find the key about the job and the
3169 * assert will fail. */
3170 if (server.vm_enabled && o->storage == REDIS_VM_SWAPPING)
3171 vmCancelThreadedIOJob(o);
ed9b544e 3172 if (--(o->refcount) == 0) {
3173 switch(o->type) {
3174 case REDIS_STRING: freeStringObject(o); break;
3175 case REDIS_LIST: freeListObject(o); break;
3176 case REDIS_SET: freeSetObject(o); break;
fd8ccf44 3177 case REDIS_ZSET: freeZsetObject(o); break;
ed9b544e 3178 case REDIS_HASH: freeHashObject(o); break;
f83c6cb5 3179 default: redisPanic("Unknown object type"); break;
ed9b544e 3180 }
a5819310 3181 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
ed9b544e 3182 if (listLength(server.objfreelist) > REDIS_OBJFREELIST_MAX ||
3183 !listAddNodeHead(server.objfreelist,o))
3184 zfree(o);
a5819310 3185 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
ed9b544e 3186 }
3187}
3188
92b27fe9 3189static int checkType(redisClient *c, robj *o, int type) {
3190 if (o->type != type) {
3191 addReply(c,shared.wrongtypeerr);
3192 return 1;
3193 }
3194 return 0;
3195}
3196
724a51b1 3197/* Check if the nul-terminated string 's' can be represented by a long
3198 * (that is, is a number that fits into long without any other space or
3199 * character before or after the digits).
3200 *
3201 * If so, the function returns REDIS_OK and *longval is set to the value
3202 * of the number. Otherwise REDIS_ERR is returned */
f69f2cba 3203static int isStringRepresentableAsLong(sds s, long *longval) {
724a51b1 3204 char buf[32], *endptr;
3205 long value;
3206 int slen;
e0a62c7f 3207
724a51b1 3208 value = strtol(s, &endptr, 10);
3209 if (endptr[0] != '\0') return REDIS_ERR;
ee14da56 3210 slen = ll2string(buf,32,value);
724a51b1 3211
3212 /* If the number converted back into a string is not identical
3213 * then it's not possible to encode the string as integer */
f69f2cba 3214 if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR;
724a51b1 3215 if (longval) *longval = value;
3216 return REDIS_OK;
3217}
3218
942a3961 3219/* Try to encode a string object in order to save space */
05df7621 3220static robj *tryObjectEncoding(robj *o) {
942a3961 3221 long value;
942a3961 3222 sds s = o->ptr;
3305306f 3223
942a3961 3224 if (o->encoding != REDIS_ENCODING_RAW)
05df7621 3225 return o; /* Already encoded */
3305306f 3226
05df7621 3227 /* It's not safe to encode shared objects: shared objects can be shared
942a3961 3228 * everywhere in the "object space" of Redis. Encoded objects can only
3229 * appear as "values" (and not, for instance, as keys) */
05df7621 3230 if (o->refcount > 1) return o;
3305306f 3231
942a3961 3232 /* Currently we try to encode only strings */
dfc5e96c 3233 redisAssert(o->type == REDIS_STRING);
94754ccc 3234
724a51b1 3235 /* Check if we can represent this string as a long integer */
05df7621 3236 if (isStringRepresentableAsLong(s,&value) == REDIS_ERR) return o;
942a3961 3237
3238 /* Ok, this object can be encoded */
05df7621 3239 if (value >= 0 && value < REDIS_SHARED_INTEGERS) {
3240 decrRefCount(o);
3241 incrRefCount(shared.integers[value]);
3242 return shared.integers[value];
3243 } else {
3244 o->encoding = REDIS_ENCODING_INT;
3245 sdsfree(o->ptr);
3246 o->ptr = (void*) value;
3247 return o;
3248 }
942a3961 3249}
3250
9d65a1bb 3251/* Get a decoded version of an encoded object (returned as a new object).
3252 * If the object is already raw-encoded just increment the ref count. */
3253static robj *getDecodedObject(robj *o) {
942a3961 3254 robj *dec;
e0a62c7f 3255
9d65a1bb 3256 if (o->encoding == REDIS_ENCODING_RAW) {
3257 incrRefCount(o);
3258 return o;
3259 }
942a3961 3260 if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) {
3261 char buf[32];
3262
ee14da56 3263 ll2string(buf,32,(long)o->ptr);
942a3961 3264 dec = createStringObject(buf,strlen(buf));
3265 return dec;
3266 } else {
08ee9b57 3267 redisPanic("Unknown encoding type");
942a3961 3268 }
3305306f 3269}
3270
d7f43c08 3271/* Compare two string objects via strcmp() or alike.
3272 * Note that the objects may be integer-encoded. In such a case we
ee14da56 3273 * use ll2string() to get a string representation of the numbers on the stack
1fd9bc8a 3274 * and compare the strings, it's much faster than calling getDecodedObject().
3275 *
3276 * Important note: if objects are not integer encoded, but binary-safe strings,
3277 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
3278 * binary safe. */
724a51b1 3279static int compareStringObjects(robj *a, robj *b) {
dfc5e96c 3280 redisAssert(a->type == REDIS_STRING && b->type == REDIS_STRING);
d7f43c08 3281 char bufa[128], bufb[128], *astr, *bstr;
3282 int bothsds = 1;
724a51b1 3283
e197b441 3284 if (a == b) return 0;
d7f43c08 3285 if (a->encoding != REDIS_ENCODING_RAW) {
ee14da56 3286 ll2string(bufa,sizeof(bufa),(long) a->ptr);
d7f43c08 3287 astr = bufa;
3288 bothsds = 0;
724a51b1 3289 } else {
d7f43c08 3290 astr = a->ptr;
724a51b1 3291 }
d7f43c08 3292 if (b->encoding != REDIS_ENCODING_RAW) {
ee14da56 3293 ll2string(bufb,sizeof(bufb),(long) b->ptr);
d7f43c08 3294 bstr = bufb;
3295 bothsds = 0;
3296 } else {
3297 bstr = b->ptr;
3298 }
3299 return bothsds ? sdscmp(astr,bstr) : strcmp(astr,bstr);
724a51b1 3300}
3301
bf028098 3302/* Equal string objects return 1 if the two objects are the same from the
3303 * point of view of a string comparison, otherwise 0 is returned. Note that
3304 * this function is faster then checking for (compareStringObject(a,b) == 0)
3305 * because it can perform some more optimization. */
3306static int equalStringObjects(robj *a, robj *b) {
3307 if (a->encoding != REDIS_ENCODING_RAW && b->encoding != REDIS_ENCODING_RAW){
3308 return a->ptr == b->ptr;
3309 } else {
3310 return compareStringObjects(a,b) == 0;
3311 }
3312}
3313
0ea663ea 3314static size_t stringObjectLen(robj *o) {
dfc5e96c 3315 redisAssert(o->type == REDIS_STRING);
0ea663ea 3316 if (o->encoding == REDIS_ENCODING_RAW) {
3317 return sdslen(o->ptr);
3318 } else {
3319 char buf[32];
3320
ee14da56 3321 return ll2string(buf,32,(long)o->ptr);
0ea663ea 3322 }
3323}
3324
bd79a6bd
PN
3325static int getDoubleFromObject(robj *o, double *target) {
3326 double value;
682c73e8 3327 char *eptr;
bbe025e0 3328
bd79a6bd
PN
3329 if (o == NULL) {
3330 value = 0;
3331 } else {
3332 redisAssert(o->type == REDIS_STRING);
3333 if (o->encoding == REDIS_ENCODING_RAW) {
3334 value = strtod(o->ptr, &eptr);
682c73e8 3335 if (eptr[0] != '\0') return REDIS_ERR;
bd79a6bd
PN
3336 } else if (o->encoding == REDIS_ENCODING_INT) {
3337 value = (long)o->ptr;
3338 } else {
946342c1 3339 redisPanic("Unknown string encoding");
bd79a6bd
PN
3340 }
3341 }
3342
bd79a6bd
PN
3343 *target = value;
3344 return REDIS_OK;
3345}
bbe025e0 3346
bd79a6bd
PN
3347static int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg) {
3348 double value;
3349 if (getDoubleFromObject(o, &value) != REDIS_OK) {
3350 if (msg != NULL) {
3351 addReplySds(c, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg));
3352 } else {
3353 addReplySds(c, sdsnew("-ERR value is not a double\r\n"));
3354 }
bbe025e0
AM
3355 return REDIS_ERR;
3356 }
3357
bd79a6bd 3358 *target = value;
bbe025e0
AM
3359 return REDIS_OK;
3360}
3361
bd79a6bd
PN
3362static int getLongLongFromObject(robj *o, long long *target) {
3363 long long value;
682c73e8 3364 char *eptr;
bbe025e0 3365
bd79a6bd
PN
3366 if (o == NULL) {
3367 value = 0;
3368 } else {
3369 redisAssert(o->type == REDIS_STRING);
3370 if (o->encoding == REDIS_ENCODING_RAW) {
3371 value = strtoll(o->ptr, &eptr, 10);
682c73e8 3372 if (eptr[0] != '\0') return REDIS_ERR;
bd79a6bd
PN
3373 } else if (o->encoding == REDIS_ENCODING_INT) {
3374 value = (long)o->ptr;
3375 } else {
946342c1 3376 redisPanic("Unknown string encoding");
bd79a6bd
PN
3377 }
3378 }
3379
bd79a6bd
PN
3380 *target = value;
3381 return REDIS_OK;
3382}
bbe025e0 3383
bd79a6bd
PN
3384static int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, const char *msg) {
3385 long long value;
3386 if (getLongLongFromObject(o, &value) != REDIS_OK) {
3387 if (msg != NULL) {
3388 addReplySds(c, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg));
3389 } else {
3390 addReplySds(c, sdsnew("-ERR value is not an integer\r\n"));
3391 }
bbe025e0
AM
3392 return REDIS_ERR;
3393 }
3394
bd79a6bd 3395 *target = value;
bbe025e0
AM
3396 return REDIS_OK;
3397}
3398
bd79a6bd
PN
3399static int getLongFromObjectOrReply(redisClient *c, robj *o, long *target, const char *msg) {
3400 long long value;
bbe025e0 3401
bd79a6bd
PN
3402 if (getLongLongFromObjectOrReply(c, o, &value, msg) != REDIS_OK) return REDIS_ERR;
3403 if (value < LONG_MIN || value > LONG_MAX) {
3404 if (msg != NULL) {
3405 addReplySds(c, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg));
3406 } else {
3407 addReplySds(c, sdsnew("-ERR value is out of range\r\n"));
3408 }
bbe025e0
AM
3409 return REDIS_ERR;
3410 }
3411
bd79a6bd 3412 *target = value;
bbe025e0
AM
3413 return REDIS_OK;
3414}
3415
612e4de8 3416/* =========================== Keyspace access API ========================== */
3417
3418static robj *lookupKey(redisDb *db, robj *key) {
09241813 3419 dictEntry *de = dictFind(db->dict,key->ptr);
612e4de8 3420 if (de) {
612e4de8 3421 robj *val = dictGetEntryVal(de);
3422
3423 if (server.vm_enabled) {
3424 if (val->storage == REDIS_VM_MEMORY ||
3425 val->storage == REDIS_VM_SWAPPING)
3426 {
3427 /* If we were swapping the object out, cancel the operation */
3428 if (val->storage == REDIS_VM_SWAPPING)
3429 vmCancelThreadedIOJob(val);
09241813 3430 /* Update the access time for the aging algorithm. */
612e4de8 3431 val->lru = server.lruclock;
3432 } else {
3433 int notify = (val->storage == REDIS_VM_LOADING);
3434
3435 /* Our value was swapped on disk. Bring it at home. */
3436 redisAssert(val->type == REDIS_VMPOINTER);
3437 val = vmLoadObject(val);
3438 dictGetEntryVal(de) = val;
3439
3440 /* Clients blocked by the VM subsystem may be waiting for
3441 * this key... */
3442 if (notify) handleClientsBlockedOnSwappedKey(db,key);
3443 }
3444 }
3445 return val;
3446 } else {
3447 return NULL;
3448 }
3449}
3450
3451static robj *lookupKeyRead(redisDb *db, robj *key) {
3452 expireIfNeeded(db,key);
3453 return lookupKey(db,key);
3454}
3455
3456static robj *lookupKeyWrite(redisDb *db, robj *key) {
3457 deleteIfVolatile(db,key);
3458 touchWatchedKey(db,key);
3459 return lookupKey(db,key);
3460}
3461
3462static robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply) {
3463 robj *o = lookupKeyRead(c->db, key);
3464 if (!o) addReply(c,reply);
3465 return o;
3466}
3467
3468static robj *lookupKeyWriteOrReply(redisClient *c, robj *key, robj *reply) {
3469 robj *o = lookupKeyWrite(c->db, key);
3470 if (!o) addReply(c,reply);
3471 return o;
3472}
3473
09241813 3474/* Add the key to the DB. If the key already exists REDIS_ERR is returned,
3475 * otherwise REDIS_OK is returned, and the caller should increment the
3476 * refcount of 'val'. */
3477static int dbAdd(redisDb *db, robj *key, robj *val) {
3478 /* Perform a lookup before adding the key, as we need to copy the
3479 * key value. */
3480 if (dictFind(db->dict, key->ptr) != NULL) {
3481 return REDIS_ERR;
3482 } else {
3483 sds copy = sdsdup(key->ptr);
3484 dictAdd(db->dict, copy, val);
3485 return REDIS_OK;
3486 }
3487}
3488
3489/* If the key does not exist, this is just like dbAdd(). Otherwise
3490 * the value associated to the key is replaced with the new one.
3491 *
3492 * On update (key already existed) 0 is returned. Otherwise 1. */
3493static int dbReplace(redisDb *db, robj *key, robj *val) {
3494 if (dictFind(db->dict,key->ptr) == NULL) {
3495 sds copy = sdsdup(key->ptr);
3496 dictAdd(db->dict, copy, val);
3497 return 1;
3498 } else {
3499 dictReplace(db->dict, key->ptr, val);
3500 return 0;
3501 }
3502}
3503
3504static int dbExists(redisDb *db, robj *key) {
3505 return dictFind(db->dict,key->ptr) != NULL;
3506}
3507
3508/* Return a random key, in form of a Redis object.
3509 * If there are no keys, NULL is returned.
3510 *
3511 * The function makes sure to return keys not already expired. */
3512static robj *dbRandomKey(redisDb *db) {
3513 struct dictEntry *de;
3514
3515 while(1) {
3516 sds key;
3517 robj *keyobj;
3518
3519 de = dictGetRandomKey(db->dict);
3520 if (de == NULL) return NULL;
3521
3522 key = dictGetEntryKey(de);
3523 keyobj = createStringObject(key,sdslen(key));
3524 if (dictFind(db->expires,key)) {
3525 if (expireIfNeeded(db,keyobj)) {
3526 decrRefCount(keyobj);
3527 continue; /* search for another key. This expired. */
3528 }
3529 }
3530 return keyobj;
3531 }
3532}
3533
3534/* Delete a key, value, and associated expiration entry if any, from the DB */
3535static int dbDelete(redisDb *db, robj *key) {
829137b9
PN
3536 /* Deleting an entry from the expires dict will not free the sds of
3537 * the key, because it is shared with the main dictionary. */
3538 if (dictSize(db->expires) > 0) dictDelete(db->expires,key->ptr);
3539 return dictDelete(db->dict,key->ptr) == DICT_OK;
612e4de8 3540}
3541
06233c45 3542/*============================ RDB saving/loading =========================== */
ed9b544e 3543
f78fd11b 3544static int rdbSaveType(FILE *fp, unsigned char type) {
3545 if (fwrite(&type,1,1,fp) == 0) return -1;
3546 return 0;
3547}
3548
bb32ede5 3549static int rdbSaveTime(FILE *fp, time_t t) {
3550 int32_t t32 = (int32_t) t;
3551 if (fwrite(&t32,4,1,fp) == 0) return -1;
3552 return 0;
3553}
3554
e3566d4b 3555/* check rdbLoadLen() comments for more info */
f78fd11b 3556static int rdbSaveLen(FILE *fp, uint32_t len) {
3557 unsigned char buf[2];
3558
3559 if (len < (1<<6)) {
3560 /* Save a 6 bit len */
10c43610 3561 buf[0] = (len&0xFF)|(REDIS_RDB_6BITLEN<<6);
f78fd11b 3562 if (fwrite(buf,1,1,fp) == 0) return -1;
3563 } else if (len < (1<<14)) {
3564 /* Save a 14 bit len */
10c43610 3565 buf[0] = ((len>>8)&0xFF)|(REDIS_RDB_14BITLEN<<6);
f78fd11b 3566 buf[1] = len&0xFF;
17be1a4a 3567 if (fwrite(buf,2,1,fp) == 0) return -1;
f78fd11b 3568 } else {
3569 /* Save a 32 bit len */
10c43610 3570 buf[0] = (REDIS_RDB_32BITLEN<<6);
f78fd11b 3571 if (fwrite(buf,1,1,fp) == 0) return -1;
3572 len = htonl(len);
3573 if (fwrite(&len,4,1,fp) == 0) return -1;
3574 }
3575 return 0;
3576}
3577
32a66513 3578/* Encode 'value' as an integer if possible (if integer will fit the
3579 * supported range). If the function sucessful encoded the integer
3580 * then the (up to 5 bytes) encoded representation is written in the
3581 * string pointed by 'enc' and the length is returned. Otherwise
3582 * 0 is returned. */
3583static int rdbEncodeInteger(long long value, unsigned char *enc) {
e3566d4b 3584 /* Finally check if it fits in our ranges */
3585 if (value >= -(1<<7) && value <= (1<<7)-1) {
3586 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT8;
3587 enc[1] = value&0xFF;
3588 return 2;
3589 } else if (value >= -(1<<15) && value <= (1<<15)-1) {
3590 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT16;
3591 enc[1] = value&0xFF;
3592 enc[2] = (value>>8)&0xFF;
3593 return 3;
3594 } else if (value >= -((long long)1<<31) && value <= ((long long)1<<31)-1) {
3595 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT32;
3596 enc[1] = value&0xFF;
3597 enc[2] = (value>>8)&0xFF;
3598 enc[3] = (value>>16)&0xFF;
3599 enc[4] = (value>>24)&0xFF;
3600 return 5;
3601 } else {
3602 return 0;
3603 }
3604}
3605
32a66513 3606/* String objects in the form "2391" "-100" without any space and with a
3607 * range of values that can fit in an 8, 16 or 32 bit signed value can be
3608 * encoded as integers to save space */
3609static int rdbTryIntegerEncoding(char *s, size_t len, unsigned char *enc) {
3610 long long value;
3611 char *endptr, buf[32];
3612
3613 /* Check if it's possible to encode this value as a number */
3614 value = strtoll(s, &endptr, 10);
3615 if (endptr[0] != '\0') return 0;
3616 ll2string(buf,32,value);
3617
3618 /* If the number converted back into a string is not identical
3619 * then it's not possible to encode the string as integer */
3620 if (strlen(buf) != len || memcmp(buf,s,len)) return 0;
3621
3622 return rdbEncodeInteger(value,enc);
3623}
3624
b1befe6a 3625static int rdbSaveLzfStringObject(FILE *fp, unsigned char *s, size_t len) {
3626 size_t comprlen, outlen;
774e3047 3627 unsigned char byte;
3628 void *out;
3629
3630 /* We require at least four bytes compression for this to be worth it */
b1befe6a 3631 if (len <= 4) return 0;
3632 outlen = len-4;
3a2694c4 3633 if ((out = zmalloc(outlen+1)) == NULL) return 0;
b1befe6a 3634 comprlen = lzf_compress(s, len, out, outlen);
774e3047 3635 if (comprlen == 0) {
88e85998 3636 zfree(out);
774e3047 3637 return 0;
3638 }
3639 /* Data compressed! Let's save it on disk */
3640 byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF;
3641 if (fwrite(&byte,1,1,fp) == 0) goto writeerr;
3642 if (rdbSaveLen(fp,comprlen) == -1) goto writeerr;
b1befe6a 3643 if (rdbSaveLen(fp,len) == -1) goto writeerr;
774e3047 3644 if (fwrite(out,comprlen,1,fp) == 0) goto writeerr;
88e85998 3645 zfree(out);
774e3047 3646 return comprlen;
3647
3648writeerr:
88e85998 3649 zfree(out);
774e3047 3650 return -1;
3651}
3652
e3566d4b 3653/* Save a string objet as [len][data] on disk. If the object is a string
3654 * representation of an integer value we try to safe it in a special form */
b1befe6a 3655static int rdbSaveRawString(FILE *fp, unsigned char *s, size_t len) {
e3566d4b 3656 int enclen;
10c43610 3657
774e3047 3658 /* Try integer encoding */
e3566d4b 3659 if (len <= 11) {
3660 unsigned char buf[5];
b1befe6a 3661 if ((enclen = rdbTryIntegerEncoding((char*)s,len,buf)) > 0) {
e3566d4b 3662 if (fwrite(buf,enclen,1,fp) == 0) return -1;
3663 return 0;
3664 }
3665 }
774e3047 3666
3667 /* Try LZF compression - under 20 bytes it's unable to compress even
88e85998 3668 * aaaaaaaaaaaaaaaaaa so skip it */
121f70cf 3669 if (server.rdbcompression && len > 20) {
774e3047 3670 int retval;
3671
b1befe6a 3672 retval = rdbSaveLzfStringObject(fp,s,len);
774e3047 3673 if (retval == -1) return -1;
3674 if (retval > 0) return 0;
3675 /* retval == 0 means data can't be compressed, save the old way */
3676 }
3677
3678 /* Store verbatim */
10c43610 3679 if (rdbSaveLen(fp,len) == -1) return -1;
b1befe6a 3680 if (len && fwrite(s,len,1,fp) == 0) return -1;
10c43610 3681 return 0;
3682}
3683
2796f6da
PN
3684/* Save a long long value as either an encoded string or a string. */
3685static int rdbSaveLongLongAsStringObject(FILE *fp, long long value) {
3686 unsigned char buf[32];
3687 int enclen = rdbEncodeInteger(value,buf);
3688 if (enclen > 0) {
3689 if (fwrite(buf,enclen,1,fp) == 0) return -1;
3690 } else {
3691 /* Encode as string */
3692 enclen = ll2string((char*)buf,32,value);
3693 redisAssert(enclen < 32);
3694 if (rdbSaveLen(fp,enclen) == -1) return -1;
3695 if (fwrite(buf,enclen,1,fp) == 0) return -1;
3696 }
3697 return 0;
3698}
3699
942a3961 3700/* Like rdbSaveStringObjectRaw() but handle encoded objects */
3701static int rdbSaveStringObject(FILE *fp, robj *obj) {
32a66513 3702 /* Avoid to decode the object, then encode it again, if the
3703 * object is alrady integer encoded. */
3704 if (obj->encoding == REDIS_ENCODING_INT) {
2796f6da 3705 return rdbSaveLongLongAsStringObject(fp,(long)obj->ptr);
996cb5f7 3706 } else {
2796f6da
PN
3707 redisAssert(obj->encoding == REDIS_ENCODING_RAW);
3708 return rdbSaveRawString(fp,obj->ptr,sdslen(obj->ptr));
996cb5f7 3709 }
942a3961 3710}
3711
a7866db6 3712/* Save a double value. Doubles are saved as strings prefixed by an unsigned
3713 * 8 bit integer specifing the length of the representation.
3714 * This 8 bit integer has special values in order to specify the following
3715 * conditions:
3716 * 253: not a number
3717 * 254: + inf
3718 * 255: - inf
3719 */
3720static int rdbSaveDoubleValue(FILE *fp, double val) {
3721 unsigned char buf[128];
3722 int len;
3723
3724 if (isnan(val)) {
3725 buf[0] = 253;
3726 len = 1;
3727 } else if (!isfinite(val)) {
3728 len = 1;
3729 buf[0] = (val < 0) ? 255 : 254;
3730 } else {
88e8d89f 3731#if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)
fe244589 3732 /* Check if the float is in a safe range to be casted into a
3733 * long long. We are assuming that long long is 64 bit here.
3734 * Also we are assuming that there are no implementations around where
3735 * double has precision < 52 bit.
3736 *
3737 * Under this assumptions we test if a double is inside an interval
3738 * where casting to long long is safe. Then using two castings we
3739 * make sure the decimal part is zero. If all this is true we use
3740 * integer printing function that is much faster. */
fb82e75c 3741 double min = -4503599627370495; /* (2^52)-1 */
3742 double max = 4503599627370496; /* -(2^52) */
fe244589 3743 if (val > min && val < max && val == ((double)((long long)val)))
8c096b16 3744 ll2string((char*)buf+1,sizeof(buf),(long long)val);
3745 else
88e8d89f 3746#endif
8c096b16 3747 snprintf((char*)buf+1,sizeof(buf)-1,"%.17g",val);
6c446631 3748 buf[0] = strlen((char*)buf+1);
a7866db6 3749 len = buf[0]+1;
3750 }
3751 if (fwrite(buf,len,1,fp) == 0) return -1;
3752 return 0;
3753}
3754
06233c45 3755/* Save a Redis object. */
3756static int rdbSaveObject(FILE *fp, robj *o) {
3757 if (o->type == REDIS_STRING) {
3758 /* Save a string value */
3759 if (rdbSaveStringObject(fp,o) == -1) return -1;
3760 } else if (o->type == REDIS_LIST) {
3761 /* Save a list value */
23f96494
PN
3762 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
3763 unsigned char *p;
3764 unsigned char *vstr;
3765 unsigned int vlen;
3766 long long vlong;
3767
3768 if (rdbSaveLen(fp,ziplistLen(o->ptr)) == -1) return -1;
3769 p = ziplistIndex(o->ptr,0);
3770 while(ziplistGet(p,&vstr,&vlen,&vlong)) {
3771 if (vstr) {
3772 if (rdbSaveRawString(fp,vstr,vlen) == -1)
3773 return -1;
3774 } else {
3775 if (rdbSaveLongLongAsStringObject(fp,vlong) == -1)
3776 return -1;
3777 }
3778 p = ziplistNext(o->ptr,p);
3779 }
7e79de54 3780 } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
23f96494
PN
3781 list *list = o->ptr;
3782 listIter li;
3783 listNode *ln;
3784
3785 if (rdbSaveLen(fp,listLength(list)) == -1) return -1;
3786 listRewind(list,&li);
3787 while((ln = listNext(&li))) {
3788 robj *eleobj = listNodeValue(ln);
3789 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
3790 }
3791 } else {
3792 redisPanic("Unknown list encoding");
06233c45 3793 }
3794 } else if (o->type == REDIS_SET) {
3795 /* Save a set value */
3796 dict *set = o->ptr;
3797 dictIterator *di = dictGetIterator(set);
3798 dictEntry *de;
3799
3800 if (rdbSaveLen(fp,dictSize(set)) == -1) return -1;
3801 while((de = dictNext(di)) != NULL) {
3802 robj *eleobj = dictGetEntryKey(de);
3803
3804 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
3805 }
3806 dictReleaseIterator(di);
3807 } else if (o->type == REDIS_ZSET) {
3808 /* Save a set value */
3809 zset *zs = o->ptr;
3810 dictIterator *di = dictGetIterator(zs->dict);
3811 dictEntry *de;
3812
3813 if (rdbSaveLen(fp,dictSize(zs->dict)) == -1) return -1;
3814 while((de = dictNext(di)) != NULL) {
3815 robj *eleobj = dictGetEntryKey(de);
3816 double *score = dictGetEntryVal(de);
3817
3818 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
3819 if (rdbSaveDoubleValue(fp,*score) == -1) return -1;
3820 }
3821 dictReleaseIterator(di);
b1befe6a 3822 } else if (o->type == REDIS_HASH) {
3823 /* Save a hash value */
3824 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
3825 unsigned char *p = zipmapRewind(o->ptr);
3826 unsigned int count = zipmapLen(o->ptr);
3827 unsigned char *key, *val;
3828 unsigned int klen, vlen;
3829
3830 if (rdbSaveLen(fp,count) == -1) return -1;
3831 while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
3832 if (rdbSaveRawString(fp,key,klen) == -1) return -1;
3833 if (rdbSaveRawString(fp,val,vlen) == -1) return -1;
3834 }
3835 } else {
3836 dictIterator *di = dictGetIterator(o->ptr);
3837 dictEntry *de;
3838
3839 if (rdbSaveLen(fp,dictSize((dict*)o->ptr)) == -1) return -1;
3840 while((de = dictNext(di)) != NULL) {
3841 robj *key = dictGetEntryKey(de);
3842 robj *val = dictGetEntryVal(de);
3843
3844 if (rdbSaveStringObject(fp,key) == -1) return -1;
3845 if (rdbSaveStringObject(fp,val) == -1) return -1;
3846 }
3847 dictReleaseIterator(di);
3848 }
06233c45 3849 } else {
f83c6cb5 3850 redisPanic("Unknown object type");
06233c45 3851 }
3852 return 0;
3853}
3854
3855/* Return the length the object will have on disk if saved with
3856 * the rdbSaveObject() function. Currently we use a trick to get
3857 * this length with very little changes to the code. In the future
3858 * we could switch to a faster solution. */
b9bc0eef 3859static off_t rdbSavedObjectLen(robj *o, FILE *fp) {
3860 if (fp == NULL) fp = server.devnull;
06233c45 3861 rewind(fp);
3862 assert(rdbSaveObject(fp,o) != 1);
3863 return ftello(fp);
3864}
3865
06224fec 3866/* Return the number of pages required to save this object in the swap file */
b9bc0eef 3867static off_t rdbSavedObjectPages(robj *o, FILE *fp) {
3868 off_t bytes = rdbSavedObjectLen(o,fp);
e0a62c7f 3869
06224fec 3870 return (bytes+(server.vm_page_size-1))/server.vm_page_size;
3871}
3872
ed9b544e 3873/* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
f78fd11b 3874static int rdbSave(char *filename) {
ed9b544e 3875 dictIterator *di = NULL;
3876 dictEntry *de;
ed9b544e 3877 FILE *fp;
3878 char tmpfile[256];
3879 int j;
bb32ede5 3880 time_t now = time(NULL);
ed9b544e 3881
2316bb3b 3882 /* Wait for I/O therads to terminate, just in case this is a
3883 * foreground-saving, to avoid seeking the swap file descriptor at the
3884 * same time. */
3885 if (server.vm_enabled)
3886 waitEmptyIOJobsQueue();
3887
a3b21203 3888 snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
ed9b544e 3889 fp = fopen(tmpfile,"w");
3890 if (!fp) {
3891 redisLog(REDIS_WARNING, "Failed saving the DB: %s", strerror(errno));
3892 return REDIS_ERR;
3893 }
f78fd11b 3894 if (fwrite("REDIS0001",9,1,fp) == 0) goto werr;
ed9b544e 3895 for (j = 0; j < server.dbnum; j++) {
bb32ede5 3896 redisDb *db = server.db+j;
3897 dict *d = db->dict;
3305306f 3898 if (dictSize(d) == 0) continue;
ed9b544e 3899 di = dictGetIterator(d);
3900 if (!di) {
3901 fclose(fp);
3902 return REDIS_ERR;
3903 }
3904
3905 /* Write the SELECT DB opcode */
f78fd11b 3906 if (rdbSaveType(fp,REDIS_SELECTDB) == -1) goto werr;
3907 if (rdbSaveLen(fp,j) == -1) goto werr;
ed9b544e 3908
3909 /* Iterate this DB writing every entry */
3910 while((de = dictNext(di)) != NULL) {
09241813 3911 sds keystr = dictGetEntryKey(de);
3912 robj key, *o = dictGetEntryVal(de);
3913 time_t expiretime;
3914
3915 initStaticStringObject(key,keystr);
3916 expiretime = getExpire(db,&key);
bb32ede5 3917
3918 /* Save the expire time */
3919 if (expiretime != -1) {
3920 /* If this key is already expired skip it */
3921 if (expiretime < now) continue;
3922 if (rdbSaveType(fp,REDIS_EXPIRETIME) == -1) goto werr;
3923 if (rdbSaveTime(fp,expiretime) == -1) goto werr;
3924 }
7e69548d 3925 /* Save the key and associated value. This requires special
3926 * handling if the value is swapped out. */
560db612 3927 if (!server.vm_enabled || o->storage == REDIS_VM_MEMORY ||
3928 o->storage == REDIS_VM_SWAPPING) {
7e69548d 3929 /* Save type, key, value */
3930 if (rdbSaveType(fp,o->type) == -1) goto werr;
09241813 3931 if (rdbSaveStringObject(fp,&key) == -1) goto werr;
7e69548d 3932 if (rdbSaveObject(fp,o) == -1) goto werr;
3933 } else {
996cb5f7 3934 /* REDIS_VM_SWAPPED or REDIS_VM_LOADING */
b9bc0eef 3935 robj *po;
7e69548d 3936 /* Get a preview of the object in memory */
560db612 3937 po = vmPreviewObject(o);
7e69548d 3938 /* Save type, key, value */
560db612 3939 if (rdbSaveType(fp,po->type) == -1) goto werr;
09241813 3940 if (rdbSaveStringObject(fp,&key) == -1) goto werr;
7e69548d 3941 if (rdbSaveObject(fp,po) == -1) goto werr;
3942 /* Remove the loaded object from memory */
3943 decrRefCount(po);
7e69548d 3944 }
ed9b544e 3945 }
3946 dictReleaseIterator(di);
3947 }
3948 /* EOF opcode */
f78fd11b 3949 if (rdbSaveType(fp,REDIS_EOF) == -1) goto werr;
3950
3951 /* Make sure data will not remain on the OS's output buffers */
ed9b544e 3952 fflush(fp);
3953 fsync(fileno(fp));
3954 fclose(fp);
e0a62c7f 3955
ed9b544e 3956 /* Use RENAME to make sure the DB file is changed atomically only
3957 * if the generate DB file is ok. */
3958 if (rename(tmpfile,filename) == -1) {
325d1eb4 3959 redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
ed9b544e 3960 unlink(tmpfile);
3961 return REDIS_ERR;
3962 }
3963 redisLog(REDIS_NOTICE,"DB saved on disk");
3964 server.dirty = 0;
3965 server.lastsave = time(NULL);
3966 return REDIS_OK;
3967
3968werr:
3969 fclose(fp);
3970 unlink(tmpfile);
3971 redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
3972 if (di) dictReleaseIterator(di);
3973 return REDIS_ERR;
3974}
3975
f78fd11b 3976static int rdbSaveBackground(char *filename) {
ed9b544e 3977 pid_t childpid;
3978
9d65a1bb 3979 if (server.bgsavechildpid != -1) return REDIS_ERR;
054e426d 3980 if (server.vm_enabled) waitEmptyIOJobsQueue();
ed9b544e 3981 if ((childpid = fork()) == 0) {
3982 /* Child */
054e426d 3983 if (server.vm_enabled) vmReopenSwapFile();
ed9b544e 3984 close(server.fd);
f78fd11b 3985 if (rdbSave(filename) == REDIS_OK) {
478c2c6f 3986 _exit(0);
ed9b544e 3987 } else {
478c2c6f 3988 _exit(1);
ed9b544e 3989 }
3990 } else {
3991 /* Parent */
5a7c647e 3992 if (childpid == -1) {
3993 redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
3994 strerror(errno));
3995 return REDIS_ERR;
3996 }
ed9b544e 3997 redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
9f3c422c 3998 server.bgsavechildpid = childpid;
884d4b39 3999 updateDictResizePolicy();
ed9b544e 4000 return REDIS_OK;
4001 }
4002 return REDIS_OK; /* unreached */
4003}
4004
a3b21203 4005static void rdbRemoveTempFile(pid_t childpid) {
4006 char tmpfile[256];
4007
4008 snprintf(tmpfile,256,"temp-%d.rdb", (int) childpid);
4009 unlink(tmpfile);
4010}
4011
f78fd11b 4012static int rdbLoadType(FILE *fp) {
4013 unsigned char type;
7b45bfb2 4014 if (fread(&type,1,1,fp) == 0) return -1;
4015 return type;
4016}
4017
bb32ede5 4018static time_t rdbLoadTime(FILE *fp) {
4019 int32_t t32;
4020 if (fread(&t32,4,1,fp) == 0) return -1;
4021 return (time_t) t32;
4022}
4023
e3566d4b 4024/* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
4025 * of this file for a description of how this are stored on disk.
4026 *
4027 * isencoded is set to 1 if the readed length is not actually a length but
4028 * an "encoding type", check the above comments for more info */
c78a8ccc 4029static uint32_t rdbLoadLen(FILE *fp, int *isencoded) {
f78fd11b 4030 unsigned char buf[2];
4031 uint32_t len;
c78a8ccc 4032 int type;
f78fd11b 4033
e3566d4b 4034 if (isencoded) *isencoded = 0;
c78a8ccc 4035 if (fread(buf,1,1,fp) == 0) return REDIS_RDB_LENERR;
4036 type = (buf[0]&0xC0)>>6;
4037 if (type == REDIS_RDB_6BITLEN) {
4038 /* Read a 6 bit len */
4039 return buf[0]&0x3F;
4040 } else if (type == REDIS_RDB_ENCVAL) {
4041 /* Read a 6 bit len encoding type */
4042 if (isencoded) *isencoded = 1;
4043 return buf[0]&0x3F;
4044 } else if (type == REDIS_RDB_14BITLEN) {
4045 /* Read a 14 bit len */
4046 if (fread(buf+1,1,1,fp) == 0) return REDIS_RDB_LENERR;
4047 return ((buf[0]&0x3F)<<8)|buf[1];
4048 } else {
4049 /* Read a 32 bit len */
f78fd11b 4050 if (fread(&len,4,1,fp) == 0) return REDIS_RDB_LENERR;
4051 return ntohl(len);
f78fd11b 4052 }
f78fd11b 4053}
4054
ad30aa60 4055/* Load an integer-encoded object from file 'fp', with the specified
4056 * encoding type 'enctype'. If encode is true the function may return
4057 * an integer-encoded object as reply, otherwise the returned object
4058 * will always be encoded as a raw string. */
4059static robj *rdbLoadIntegerObject(FILE *fp, int enctype, int encode) {
e3566d4b 4060 unsigned char enc[4];
4061 long long val;
4062
4063 if (enctype == REDIS_RDB_ENC_INT8) {
4064 if (fread(enc,1,1,fp) == 0) return NULL;
4065 val = (signed char)enc[0];
4066 } else if (enctype == REDIS_RDB_ENC_INT16) {
4067 uint16_t v;
4068 if (fread(enc,2,1,fp) == 0) return NULL;
4069 v = enc[0]|(enc[1]<<8);
4070 val = (int16_t)v;
4071 } else if (enctype == REDIS_RDB_ENC_INT32) {
4072 uint32_t v;
4073 if (fread(enc,4,1,fp) == 0) return NULL;
4074 v = enc[0]|(enc[1]<<8)|(enc[2]<<16)|(enc[3]<<24);
4075 val = (int32_t)v;
4076 } else {
4077 val = 0; /* anti-warning */
f83c6cb5 4078 redisPanic("Unknown RDB integer encoding type");
e3566d4b 4079 }
ad30aa60 4080 if (encode)
4081 return createStringObjectFromLongLong(val);
4082 else
4083 return createObject(REDIS_STRING,sdsfromlonglong(val));
e3566d4b 4084}
4085
c78a8ccc 4086static robj *rdbLoadLzfStringObject(FILE*fp) {
88e85998 4087 unsigned int len, clen;
4088 unsigned char *c = NULL;
4089 sds val = NULL;
4090
c78a8ccc 4091 if ((clen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
4092 if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
88e85998 4093 if ((c = zmalloc(clen)) == NULL) goto err;
4094 if ((val = sdsnewlen(NULL,len)) == NULL) goto err;
4095 if (fread(c,clen,1,fp) == 0) goto err;
4096 if (lzf_decompress(c,clen,val,len) == 0) goto err;
5109cdff 4097 zfree(c);
88e85998 4098 return createObject(REDIS_STRING,val);
4099err:
4100 zfree(c);
4101 sdsfree(val);
4102 return NULL;
4103}
4104
ad30aa60 4105static robj *rdbGenericLoadStringObject(FILE*fp, int encode) {
e3566d4b 4106 int isencoded;
4107 uint32_t len;
f78fd11b 4108 sds val;
4109
c78a8ccc 4110 len = rdbLoadLen(fp,&isencoded);
e3566d4b 4111 if (isencoded) {
4112 switch(len) {
4113 case REDIS_RDB_ENC_INT8:
4114 case REDIS_RDB_ENC_INT16:
4115 case REDIS_RDB_ENC_INT32:
ad30aa60 4116 return rdbLoadIntegerObject(fp,len,encode);
88e85998 4117 case REDIS_RDB_ENC_LZF:
bdcb92f2 4118 return rdbLoadLzfStringObject(fp);
e3566d4b 4119 default:
f83c6cb5 4120 redisPanic("Unknown RDB encoding type");
e3566d4b 4121 }
4122 }
4123
f78fd11b 4124 if (len == REDIS_RDB_LENERR) return NULL;
4125 val = sdsnewlen(NULL,len);
4126 if (len && fread(val,len,1,fp) == 0) {
4127 sdsfree(val);
4128 return NULL;
4129 }
bdcb92f2 4130 return createObject(REDIS_STRING,val);
f78fd11b 4131}
4132
ad30aa60 4133static robj *rdbLoadStringObject(FILE *fp) {
4134 return rdbGenericLoadStringObject(fp,0);
4135}
4136
4137static robj *rdbLoadEncodedStringObject(FILE *fp) {
4138 return rdbGenericLoadStringObject(fp,1);
4139}
4140
a7866db6 4141/* For information about double serialization check rdbSaveDoubleValue() */
4142static int rdbLoadDoubleValue(FILE *fp, double *val) {
4143 char buf[128];
4144 unsigned char len;
4145
4146 if (fread(&len,1,1,fp) == 0) return -1;
4147 switch(len) {
4148 case 255: *val = R_NegInf; return 0;
4149 case 254: *val = R_PosInf; return 0;
4150 case 253: *val = R_Nan; return 0;
4151 default:
4152 if (fread(buf,len,1,fp) == 0) return -1;
231d758e 4153 buf[len] = '\0';
a7866db6 4154 sscanf(buf, "%lg", val);
4155 return 0;
4156 }
4157}
4158
c78a8ccc 4159/* Load a Redis object of the specified type from the specified file.
4160 * On success a newly allocated object is returned, otherwise NULL. */
4161static robj *rdbLoadObject(int type, FILE *fp) {
23f96494
PN
4162 robj *o, *ele, *dec;
4163 size_t len;
c78a8ccc 4164
bcd11906 4165 redisLog(REDIS_DEBUG,"LOADING OBJECT %d (at %d)\n",type,ftell(fp));
c78a8ccc 4166 if (type == REDIS_STRING) {
4167 /* Read string value */
ad30aa60 4168 if ((o = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
05df7621 4169 o = tryObjectEncoding(o);
23f96494
PN
4170 } else if (type == REDIS_LIST) {
4171 /* Read list value */
4172 if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
4173
d0686e07
PN
4174 /* Use a real list when there are too many entries */
4175 if (len > server.list_max_ziplist_entries) {
4176 o = createListObject();
4177 } else {
4178 o = createZiplistObject();
4179 }
c78a8ccc 4180
23f96494
PN
4181 /* Load every single element of the list */
4182 while(len--) {
4183 if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
4184
d0686e07
PN
4185 /* If we are using a ziplist and the value is too big, convert
4186 * the object to a real list. */
4187 if (o->encoding == REDIS_ENCODING_ZIPLIST &&
4188 ele->encoding == REDIS_ENCODING_RAW &&
4189 sdslen(ele->ptr) > server.list_max_ziplist_value)
7e79de54 4190 listTypeConvert(o,REDIS_ENCODING_LINKEDLIST);
d0686e07 4191
23f96494
PN
4192 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
4193 dec = getDecodedObject(ele);
4194 o->ptr = ziplistPush(o->ptr,dec->ptr,sdslen(dec->ptr),REDIS_TAIL);
4195 decrRefCount(dec);
4196 decrRefCount(ele);
4197 } else {
4198 ele = tryObjectEncoding(ele);
4199 listAddNodeTail(o->ptr,ele);
23f96494
PN
4200 }
4201 }
4202 } else if (type == REDIS_SET) {
4203 /* Read list/set value */
4204 if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
4205 o = createSetObject();
3c68de9b 4206 /* It's faster to expand the dict to the right size asap in order
4207 * to avoid rehashing */
23f96494
PN
4208 if (len > DICT_HT_INITIAL_SIZE)
4209 dictExpand(o->ptr,len);
c78a8ccc 4210 /* Load every single element of the list/set */
23f96494 4211 while(len--) {
ad30aa60 4212 if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
05df7621 4213 ele = tryObjectEncoding(ele);
23f96494 4214 dictAdd((dict*)o->ptr,ele,NULL);
c78a8ccc 4215 }
4216 } else if (type == REDIS_ZSET) {
4217 /* Read list/set value */
ada386b2 4218 size_t zsetlen;
c78a8ccc 4219 zset *zs;
4220
4221 if ((zsetlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
4222 o = createZsetObject();
4223 zs = o->ptr;
4224 /* Load every single element of the list/set */
4225 while(zsetlen--) {
4226 robj *ele;
4227 double *score = zmalloc(sizeof(double));
4228
ad30aa60 4229 if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
05df7621 4230 ele = tryObjectEncoding(ele);
c78a8ccc 4231 if (rdbLoadDoubleValue(fp,score) == -1) return NULL;
4232 dictAdd(zs->dict,ele,score);
4233 zslInsert(zs->zsl,*score,ele);
4234 incrRefCount(ele); /* added to skiplist */
4235 }
ada386b2 4236 } else if (type == REDIS_HASH) {
4237 size_t hashlen;
4238
4239 if ((hashlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
4240 o = createHashObject();
4241 /* Too many entries? Use an hash table. */
4242 if (hashlen > server.hash_max_zipmap_entries)
4243 convertToRealHash(o);
4244 /* Load every key/value, then set it into the zipmap or hash
4245 * table, as needed. */
4246 while(hashlen--) {
4247 robj *key, *val;
4248
b785b2bf 4249 if ((key = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
4250 if ((val = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
ada386b2 4251 /* If we are using a zipmap and there are too big values
4252 * the object is converted to real hash table encoding. */
4253 if (o->encoding != REDIS_ENCODING_HT &&
bb039e85 4254 ((key->encoding == REDIS_ENCODING_RAW &&
4255 sdslen(key->ptr) > server.hash_max_zipmap_value) ||
4256 (val->encoding == REDIS_ENCODING_RAW &&
4257 sdslen(val->ptr) > server.hash_max_zipmap_value)))
ada386b2 4258 {
4259 convertToRealHash(o);
4260 }
4261
4262 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
4263 unsigned char *zm = o->ptr;
a8dca69b 4264 robj *deckey, *decval;
ada386b2 4265
a8dca69b
PN
4266 /* We need raw string objects to add them to the zipmap */
4267 deckey = getDecodedObject(key);
4268 decval = getDecodedObject(val);
4269 zm = zipmapSet(zm,deckey->ptr,sdslen(deckey->ptr),
4270 decval->ptr,sdslen(decval->ptr),NULL);
ada386b2 4271 o->ptr = zm;
a8dca69b
PN
4272 decrRefCount(deckey);
4273 decrRefCount(decval);
ada386b2 4274 decrRefCount(key);
4275 decrRefCount(val);
4276 } else {
05df7621 4277 key = tryObjectEncoding(key);
4278 val = tryObjectEncoding(val);
ada386b2 4279 dictAdd((dict*)o->ptr,key,val);
ada386b2 4280 }
4281 }
c78a8ccc 4282 } else {
f83c6cb5 4283 redisPanic("Unknown object type");
c78a8ccc 4284 }
4285 return o;
4286}
4287
f78fd11b 4288static int rdbLoad(char *filename) {
ed9b544e 4289 FILE *fp;
f78fd11b 4290 uint32_t dbid;
bb32ede5 4291 int type, retval, rdbver;
585af7e2 4292 int swap_all_values = 0;
bb32ede5 4293 redisDb *db = server.db+0;
f78fd11b 4294 char buf[1024];
242a64f3 4295 time_t expiretime, now = time(NULL);
bb32ede5 4296
ed9b544e 4297 fp = fopen(filename,"r");
4298 if (!fp) return REDIS_ERR;
4299 if (fread(buf,9,1,fp) == 0) goto eoferr;
f78fd11b 4300 buf[9] = '\0';
4301 if (memcmp(buf,"REDIS",5) != 0) {
ed9b544e 4302 fclose(fp);
4303 redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
4304 return REDIS_ERR;
4305 }
f78fd11b 4306 rdbver = atoi(buf+5);
c78a8ccc 4307 if (rdbver != 1) {
f78fd11b 4308 fclose(fp);
4309 redisLog(REDIS_WARNING,"Can't handle RDB format version %d",rdbver);
4310 return REDIS_ERR;
4311 }
ed9b544e 4312 while(1) {
585af7e2 4313 robj *key, *val;
7e02fe32 4314 int force_swapout;
ed9b544e 4315
585af7e2 4316 expiretime = -1;
ed9b544e 4317 /* Read type. */
f78fd11b 4318 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
bb32ede5 4319 if (type == REDIS_EXPIRETIME) {
4320 if ((expiretime = rdbLoadTime(fp)) == -1) goto eoferr;
4321 /* We read the time so we need to read the object type again */
4322 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
4323 }
ed9b544e 4324 if (type == REDIS_EOF) break;
4325 /* Handle SELECT DB opcode as a special case */
4326 if (type == REDIS_SELECTDB) {
c78a8ccc 4327 if ((dbid = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR)
e3566d4b 4328 goto eoferr;
ed9b544e 4329 if (dbid >= (unsigned)server.dbnum) {
f78fd11b 4330 redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum);
ed9b544e 4331 exit(1);
4332 }
bb32ede5 4333 db = server.db+dbid;
ed9b544e 4334 continue;
4335 }
4336 /* Read key */
585af7e2 4337 if ((key = rdbLoadStringObject(fp)) == NULL) goto eoferr;
c78a8ccc 4338 /* Read value */
585af7e2 4339 if ((val = rdbLoadObject(type,fp)) == NULL) goto eoferr;
89e689c5 4340 /* Check if the key already expired */
4341 if (expiretime != -1 && expiretime < now) {
4342 decrRefCount(key);
4343 decrRefCount(val);
4344 continue;
4345 }
ed9b544e 4346 /* Add the new object in the hash table */
09241813 4347 retval = dbAdd(db,key,val);
4348 if (retval == REDIS_ERR) {
585af7e2 4349 redisLog(REDIS_WARNING,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", key->ptr);
ed9b544e 4350 exit(1);
4351 }
bb32ede5 4352 /* Set the expire time if needed */
89e689c5 4353 if (expiretime != -1) setExpire(db,key,expiretime);
242a64f3 4354
b492cf00 4355 /* Handle swapping while loading big datasets when VM is on */
242a64f3 4356
4357 /* If we detecter we are hopeless about fitting something in memory
4358 * we just swap every new key on disk. Directly...
4359 * Note that's important to check for this condition before resorting
4360 * to random sampling, otherwise we may try to swap already
4361 * swapped keys. */
585af7e2 4362 if (swap_all_values) {
09241813 4363 dictEntry *de = dictFind(db->dict,key->ptr);
242a64f3 4364
4365 /* de may be NULL since the key already expired */
4366 if (de) {
560db612 4367 vmpointer *vp;
585af7e2 4368 val = dictGetEntryVal(de);
242a64f3 4369
560db612 4370 if (val->refcount == 1 &&
4371 (vp = vmSwapObjectBlocking(val)) != NULL)
4372 dictGetEntryVal(de) = vp;
242a64f3 4373 }
09241813 4374 decrRefCount(key);
242a64f3 4375 continue;
4376 }
09241813 4377 decrRefCount(key);
242a64f3 4378
a89b7013 4379 /* Flush data on disk once 32 MB of additional RAM are used... */
7e02fe32 4380 force_swapout = 0;
4381 if ((zmalloc_used_memory() - server.vm_max_memory) > 1024*1024*32)
4382 force_swapout = 1;
242a64f3 4383
4384 /* If we have still some hope of having some value fitting memory
4385 * then we try random sampling. */
7e02fe32 4386 if (!swap_all_values && server.vm_enabled && force_swapout) {
b492cf00 4387 while (zmalloc_used_memory() > server.vm_max_memory) {
a69a0c9c 4388 if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
b492cf00 4389 }
242a64f3 4390 if (zmalloc_used_memory() > server.vm_max_memory)
585af7e2 4391 swap_all_values = 1; /* We are already using too much mem */
b492cf00 4392 }
ed9b544e 4393 }
4394 fclose(fp);
4395 return REDIS_OK;
4396
4397eoferr: /* unexpected end of file is handled here with a fatal exit */
f80dff62 4398 redisLog(REDIS_WARNING,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
ed9b544e 4399 exit(1);
4400 return REDIS_ERR; /* Just to avoid warning */
4401}
4402
b58ba105 4403/*================================== Shutdown =============================== */
fab43727 4404static int prepareForShutdown() {
b58ba105
AM
4405 redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
4406 /* Kill the saving child if there is a background saving in progress.
4407 We want to avoid race conditions, for instance our saving child may
4408 overwrite the synchronous saving did by SHUTDOWN. */
4409 if (server.bgsavechildpid != -1) {
4410 redisLog(REDIS_WARNING,"There is a live saving child. Killing it!");
4411 kill(server.bgsavechildpid,SIGKILL);
4412 rdbRemoveTempFile(server.bgsavechildpid);
4413 }
4414 if (server.appendonly) {
4415 /* Append only file: fsync() the AOF and exit */
b0bd87f6 4416 aof_fsync(server.appendfd);
b58ba105 4417 if (server.vm_enabled) unlink(server.vm_swap_file);
b58ba105
AM
4418 } else {
4419 /* Snapshotting. Perform a SYNC SAVE and exit */
4420 if (rdbSave(server.dbfilename) == REDIS_OK) {
4421 if (server.daemonize)
4422 unlink(server.pidfile);
4423 redisLog(REDIS_WARNING,"%zu bytes used at exit",zmalloc_used_memory());
b58ba105
AM
4424 } else {
4425 /* Ooops.. error saving! The best we can do is to continue
4426 * operating. Note that if there was a background saving process,
4427 * in the next cron() Redis will be notified that the background
4428 * saving aborted, handling special stuff like slaves pending for
4429 * synchronization... */
4430 redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
fab43727 4431 return REDIS_ERR;
b58ba105
AM
4432 }
4433 }
8513a757 4434 redisLog(REDIS_WARNING,"Server exit now, bye bye...");
fab43727 4435 return REDIS_OK;
b58ba105
AM
4436}
4437
ed9b544e 4438/*================================== Commands =============================== */
4439
abcb223e 4440static void authCommand(redisClient *c) {
2e77c2ee 4441 if (!server.requirepass || !strcmp(c->argv[1]->ptr, server.requirepass)) {
abcb223e
BH
4442 c->authenticated = 1;
4443 addReply(c,shared.ok);
4444 } else {
4445 c->authenticated = 0;
fa4c0aba 4446 addReplySds(c,sdscatprintf(sdsempty(),"-ERR invalid password\r\n"));
abcb223e
BH
4447 }
4448}
4449
ed9b544e 4450static void pingCommand(redisClient *c) {
4451 addReply(c,shared.pong);
4452}
4453
4454static void echoCommand(redisClient *c) {
dd88747b 4455 addReplyBulk(c,c->argv[1]);
ed9b544e 4456}
4457
4458/*=================================== Strings =============================== */
4459
526d00a5 4460static void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire) {
ed9b544e 4461 int retval;
10ce1276 4462 long seconds = 0; /* initialized to avoid an harmness warning */
ed9b544e 4463
526d00a5 4464 if (expire) {
4465 if (getLongFromObjectOrReply(c, expire, &seconds, NULL) != REDIS_OK)
4466 return;
4467 if (seconds <= 0) {
4468 addReplySds(c,sdsnew("-ERR invalid expire time in SETEX\r\n"));
4469 return;
4470 }
4471 }
4472
37ab76c9 4473 touchWatchedKey(c->db,key);
526d00a5 4474 if (nx) deleteIfVolatile(c->db,key);
09241813 4475 retval = dbAdd(c->db,key,val);
4476 if (retval == REDIS_ERR) {
ed9b544e 4477 if (!nx) {
09241813 4478 dbReplace(c->db,key,val);
526d00a5 4479 incrRefCount(val);
ed9b544e 4480 } else {
c937aa89 4481 addReply(c,shared.czero);
ed9b544e 4482 return;
4483 }
4484 } else {
526d00a5 4485 incrRefCount(val);
ed9b544e 4486 }
4487 server.dirty++;
526d00a5 4488 removeExpire(c->db,key);
4489 if (expire) setExpire(c->db,key,time(NULL)+seconds);
c937aa89 4490 addReply(c, nx ? shared.cone : shared.ok);
ed9b544e 4491}
4492
4493static void setCommand(redisClient *c) {
526d00a5 4494 setGenericCommand(c,0,c->argv[1],c->argv[2],NULL);
ed9b544e 4495}
4496
4497static void setnxCommand(redisClient *c) {
526d00a5 4498 setGenericCommand(c,1,c->argv[1],c->argv[2],NULL);
4499}
4500
4501static void setexCommand(redisClient *c) {
4502 setGenericCommand(c,0,c->argv[1],c->argv[3],c->argv[2]);
ed9b544e 4503}
4504
322fc7d8 4505static int getGenericCommand(redisClient *c) {
dd88747b 4506 robj *o;
e0a62c7f 4507
dd88747b 4508 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)
322fc7d8 4509 return REDIS_OK;
dd88747b 4510
4511 if (o->type != REDIS_STRING) {
4512 addReply(c,shared.wrongtypeerr);
4513 return REDIS_ERR;
ed9b544e 4514 } else {
dd88747b 4515 addReplyBulk(c,o);
4516 return REDIS_OK;
ed9b544e 4517 }
4518}
4519
322fc7d8 4520static void getCommand(redisClient *c) {
4521 getGenericCommand(c);
4522}
4523
f6b141c5 4524static void getsetCommand(redisClient *c) {
322fc7d8 4525 if (getGenericCommand(c) == REDIS_ERR) return;
09241813 4526 dbReplace(c->db,c->argv[1],c->argv[2]);
a431eb74 4527 incrRefCount(c->argv[2]);
4528 server.dirty++;
4529 removeExpire(c->db,c->argv[1]);
4530}
4531
70003d28 4532static void mgetCommand(redisClient *c) {
70003d28 4533 int j;
e0a62c7f 4534
c937aa89 4535 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-1));
70003d28 4536 for (j = 1; j < c->argc; j++) {
3305306f 4537 robj *o = lookupKeyRead(c->db,c->argv[j]);
4538 if (o == NULL) {
c937aa89 4539 addReply(c,shared.nullbulk);
70003d28 4540 } else {
70003d28 4541 if (o->type != REDIS_STRING) {
c937aa89 4542 addReply(c,shared.nullbulk);
70003d28 4543 } else {
dd88747b 4544 addReplyBulk(c,o);
70003d28 4545 }
4546 }
4547 }
4548}
4549
6c446631 4550static void msetGenericCommand(redisClient *c, int nx) {
906573e7 4551 int j, busykeys = 0;
6c446631 4552
4553 if ((c->argc % 2) == 0) {
454d4e43 4554 addReplySds(c,sdsnew("-ERR wrong number of arguments for MSET\r\n"));
6c446631 4555 return;
4556 }
4557 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
4558 * set nothing at all if at least one already key exists. */
4559 if (nx) {
4560 for (j = 1; j < c->argc; j += 2) {
906573e7 4561 if (lookupKeyWrite(c->db,c->argv[j]) != NULL) {
4562 busykeys++;
6c446631 4563 }
4564 }
4565 }
906573e7 4566 if (busykeys) {
4567 addReply(c, shared.czero);
4568 return;
4569 }
6c446631 4570
4571 for (j = 1; j < c->argc; j += 2) {
05df7621 4572 c->argv[j+1] = tryObjectEncoding(c->argv[j+1]);
09241813 4573 dbReplace(c->db,c->argv[j],c->argv[j+1]);
4574 incrRefCount(c->argv[j+1]);
6c446631 4575 removeExpire(c->db,c->argv[j]);
4576 }
4577 server.dirty += (c->argc-1)/2;
4578 addReply(c, nx ? shared.cone : shared.ok);
4579}
4580
4581static void msetCommand(redisClient *c) {
4582 msetGenericCommand(c,0);
4583}
4584
4585static void msetnxCommand(redisClient *c) {
4586 msetGenericCommand(c,1);
4587}
4588
d68ed120 4589static void incrDecrCommand(redisClient *c, long long incr) {
ed9b544e 4590 long long value;
ed9b544e 4591 robj *o;
e0a62c7f 4592
3305306f 4593 o = lookupKeyWrite(c->db,c->argv[1]);
6485f293
PN
4594 if (o != NULL && checkType(c,o,REDIS_STRING)) return;
4595 if (getLongLongFromObjectOrReply(c,o,&value,NULL) != REDIS_OK) return;
ed9b544e 4596
4597 value += incr;
d6f4c262 4598 o = createStringObjectFromLongLong(value);
09241813 4599 dbReplace(c->db,c->argv[1],o);
ed9b544e 4600 server.dirty++;
c937aa89 4601 addReply(c,shared.colon);
ed9b544e 4602 addReply(c,o);
4603 addReply(c,shared.crlf);
4604}
4605
4606static void incrCommand(redisClient *c) {
a4d1ba9a 4607 incrDecrCommand(c,1);
ed9b544e 4608}
4609
4610static void decrCommand(redisClient *c) {
a4d1ba9a 4611 incrDecrCommand(c,-1);
ed9b544e 4612}
4613
4614static void incrbyCommand(redisClient *c) {
bbe025e0
AM
4615 long long incr;
4616
bd79a6bd 4617 if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != REDIS_OK) return;
a4d1ba9a 4618 incrDecrCommand(c,incr);
ed9b544e 4619}
4620
4621static void decrbyCommand(redisClient *c) {
bbe025e0
AM
4622 long long incr;
4623
bd79a6bd 4624 if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != REDIS_OK) return;
a4d1ba9a 4625 incrDecrCommand(c,-incr);
ed9b544e 4626}
4627
4b00bebd 4628static void appendCommand(redisClient *c) {
4629 int retval;
4630 size_t totlen;
4631 robj *o;
4632
4633 o = lookupKeyWrite(c->db,c->argv[1]);
4634 if (o == NULL) {
4635 /* Create the key */
09241813 4636 retval = dbAdd(c->db,c->argv[1],c->argv[2]);
4b00bebd 4637 incrRefCount(c->argv[2]);
4638 totlen = stringObjectLen(c->argv[2]);
4639 } else {
4b00bebd 4640 if (o->type != REDIS_STRING) {
4641 addReply(c,shared.wrongtypeerr);
4642 return;
4643 }
4644 /* If the object is specially encoded or shared we have to make
4645 * a copy */
4646 if (o->refcount != 1 || o->encoding != REDIS_ENCODING_RAW) {
4647 robj *decoded = getDecodedObject(o);
4648
4649 o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
4650 decrRefCount(decoded);
09241813 4651 dbReplace(c->db,c->argv[1],o);
4b00bebd 4652 }
4653 /* APPEND! */
4654 if (c->argv[2]->encoding == REDIS_ENCODING_RAW) {
4655 o->ptr = sdscatlen(o->ptr,
4656 c->argv[2]->ptr, sdslen(c->argv[2]->ptr));
4657 } else {
4658 o->ptr = sdscatprintf(o->ptr, "%ld",
4659 (unsigned long) c->argv[2]->ptr);
4660 }
4661 totlen = sdslen(o->ptr);
4662 }
4663 server.dirty++;
4664 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",(unsigned long)totlen));
4665}
4666
39191553 4667static void substrCommand(redisClient *c) {
4668 robj *o;
4669 long start = atoi(c->argv[2]->ptr);
4670 long end = atoi(c->argv[3]->ptr);
dd88747b 4671 size_t rangelen, strlen;
4672 sds range;
39191553 4673
dd88747b 4674 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
4675 checkType(c,o,REDIS_STRING)) return;
39191553 4676
dd88747b 4677 o = getDecodedObject(o);
4678 strlen = sdslen(o->ptr);
8fe7fad7 4679
dd88747b 4680 /* convert negative indexes */
4681 if (start < 0) start = strlen+start;
4682 if (end < 0) end = strlen+end;
4683 if (start < 0) start = 0;
4684 if (end < 0) end = 0;
39191553 4685
dd88747b 4686 /* indexes sanity checks */
4687 if (start > end || (size_t)start >= strlen) {
4688 /* Out of range start or start > end result in null reply */
4689 addReply(c,shared.nullbulk);
4690 decrRefCount(o);
4691 return;
39191553 4692 }
dd88747b 4693 if ((size_t)end >= strlen) end = strlen-1;
4694 rangelen = (end-start)+1;
4695
4696 /* Return the result */
4697 addReplySds(c,sdscatprintf(sdsempty(),"$%zu\r\n",rangelen));
4698 range = sdsnewlen((char*)o->ptr+start,rangelen);
4699 addReplySds(c,range);
4700 addReply(c,shared.crlf);
4701 decrRefCount(o);
39191553 4702}
4703
ed9b544e 4704/* ========================= Type agnostic commands ========================= */
4705
4706static void delCommand(redisClient *c) {
5109cdff 4707 int deleted = 0, j;
4708
4709 for (j = 1; j < c->argc; j++) {
09241813 4710 if (dbDelete(c->db,c->argv[j])) {
37ab76c9 4711 touchWatchedKey(c->db,c->argv[j]);
5109cdff 4712 server.dirty++;
4713 deleted++;
4714 }
4715 }
482b672d 4716 addReplyLongLong(c,deleted);
ed9b544e 4717}
4718
4719static void existsCommand(redisClient *c) {
f4f06efc 4720 expireIfNeeded(c->db,c->argv[1]);
09241813 4721 if (dbExists(c->db,c->argv[1])) {
f4f06efc
PN
4722 addReply(c, shared.cone);
4723 } else {
4724 addReply(c, shared.czero);
4725 }
ed9b544e 4726}
4727
4728static void selectCommand(redisClient *c) {
4729 int id = atoi(c->argv[1]->ptr);
e0a62c7f 4730
ed9b544e 4731 if (selectDb(c,id) == REDIS_ERR) {
774e3047 4732 addReplySds(c,sdsnew("-ERR invalid DB index\r\n"));
ed9b544e 4733 } else {
4734 addReply(c,shared.ok);
4735 }
4736}
4737
4738static void randomkeyCommand(redisClient *c) {
dc4be23e 4739 robj *key;
e0a62c7f 4740
09241813 4741 if ((key = dbRandomKey(c->db)) == NULL) {
dc4be23e 4742 addReply(c,shared.nullbulk);
4743 return;
4744 }
4745
09241813 4746 addReplyBulk(c,key);
4747 decrRefCount(key);
ed9b544e 4748}
4749
4750static void keysCommand(redisClient *c) {
4751 dictIterator *di;
4752 dictEntry *de;
4753 sds pattern = c->argv[1]->ptr;
4754 int plen = sdslen(pattern);
a3f9eec2 4755 unsigned long numkeys = 0;
ed9b544e 4756 robj *lenobj = createObject(REDIS_STRING,NULL);
4757
3305306f 4758 di = dictGetIterator(c->db->dict);
ed9b544e 4759 addReply(c,lenobj);
4760 decrRefCount(lenobj);
4761 while((de = dictNext(di)) != NULL) {
09241813 4762 sds key = dictGetEntryKey(de);
4763 robj *keyobj;
3305306f 4764
ed9b544e 4765 if ((pattern[0] == '*' && pattern[1] == '\0') ||
4766 stringmatchlen(pattern,plen,key,sdslen(key),0)) {
09241813 4767 keyobj = createStringObject(key,sdslen(key));
3305306f 4768 if (expireIfNeeded(c->db,keyobj) == 0) {
dd88747b 4769 addReplyBulk(c,keyobj);
3305306f 4770 numkeys++;
3305306f 4771 }
09241813 4772 decrRefCount(keyobj);
ed9b544e 4773 }
4774 }
4775 dictReleaseIterator(di);
a3f9eec2 4776 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",numkeys);
ed9b544e 4777}
4778
4779static void dbsizeCommand(redisClient *c) {
4780 addReplySds(c,
3305306f 4781 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c->db->dict)));
ed9b544e 4782}
4783
4784static void lastsaveCommand(redisClient *c) {
4785 addReplySds(c,
c937aa89 4786 sdscatprintf(sdsempty(),":%lu\r\n",server.lastsave));
ed9b544e 4787}
4788
4789static void typeCommand(redisClient *c) {
3305306f 4790 robj *o;
ed9b544e 4791 char *type;
3305306f 4792
4793 o = lookupKeyRead(c->db,c->argv[1]);
4794 if (o == NULL) {
c937aa89 4795 type = "+none";
ed9b544e 4796 } else {
ed9b544e 4797 switch(o->type) {
c937aa89 4798 case REDIS_STRING: type = "+string"; break;
4799 case REDIS_LIST: type = "+list"; break;
4800 case REDIS_SET: type = "+set"; break;
412a8bce 4801 case REDIS_ZSET: type = "+zset"; break;
ada386b2 4802 case REDIS_HASH: type = "+hash"; break;
4803 default: type = "+unknown"; break;
ed9b544e 4804 }
4805 }
4806 addReplySds(c,sdsnew(type));
4807 addReply(c,shared.crlf);
4808}
4809
4810static void saveCommand(redisClient *c) {
9d65a1bb 4811 if (server.bgsavechildpid != -1) {
05557f6d 4812 addReplySds(c,sdsnew("-ERR background save in progress\r\n"));
4813 return;
4814 }
f78fd11b 4815 if (rdbSave(server.dbfilename) == REDIS_OK) {
ed9b544e 4816 addReply(c,shared.ok);
4817 } else {
4818 addReply(c,shared.err);
4819 }
4820}
4821
4822static void bgsaveCommand(redisClient *c) {
9d65a1bb 4823 if (server.bgsavechildpid != -1) {
ed9b544e 4824 addReplySds(c,sdsnew("-ERR background save already in progress\r\n"));
4825 return;
4826 }
f78fd11b 4827 if (rdbSaveBackground(server.dbfilename) == REDIS_OK) {
49b99ab4 4828 char *status = "+Background saving started\r\n";
4829 addReplySds(c,sdsnew(status));
ed9b544e 4830 } else {
4831 addReply(c,shared.err);
4832 }
4833}
4834
4835static void shutdownCommand(redisClient *c) {
fab43727 4836 if (prepareForShutdown() == REDIS_OK)
4837 exit(0);
4838 addReplySds(c, sdsnew("-ERR Errors trying to SHUTDOWN. Check logs.\r\n"));
ed9b544e 4839}
4840
4841static void renameGenericCommand(redisClient *c, int nx) {
ed9b544e 4842 robj *o;
4843
4844 /* To use the same key as src and dst is probably an error */
4845 if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) {
c937aa89 4846 addReply(c,shared.sameobjecterr);
ed9b544e 4847 return;
4848 }
4849
dd88747b 4850 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr)) == NULL)
ed9b544e 4851 return;
dd88747b 4852
ed9b544e 4853 incrRefCount(o);
3305306f 4854 deleteIfVolatile(c->db,c->argv[2]);
09241813 4855 if (dbAdd(c->db,c->argv[2],o) == REDIS_ERR) {
ed9b544e 4856 if (nx) {
4857 decrRefCount(o);
c937aa89 4858 addReply(c,shared.czero);
ed9b544e 4859 return;
4860 }
09241813 4861 dbReplace(c->db,c->argv[2],o);
ed9b544e 4862 }
09241813 4863 dbDelete(c->db,c->argv[1]);
b167f877 4864 touchWatchedKey(c->db,c->argv[2]);
ed9b544e 4865 server.dirty++;
c937aa89 4866 addReply(c,nx ? shared.cone : shared.ok);
ed9b544e 4867}
4868
4869static void renameCommand(redisClient *c) {
4870 renameGenericCommand(c,0);
4871}
4872
4873static void renamenxCommand(redisClient *c) {
4874 renameGenericCommand(c,1);
4875}
4876
4877static void moveCommand(redisClient *c) {
3305306f 4878 robj *o;
4879 redisDb *src, *dst;
ed9b544e 4880 int srcid;
4881
4882 /* Obtain source and target DB pointers */
3305306f 4883 src = c->db;
4884 srcid = c->db->id;
ed9b544e 4885 if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) {
c937aa89 4886 addReply(c,shared.outofrangeerr);
ed9b544e 4887 return;
4888 }
3305306f 4889 dst = c->db;
4890 selectDb(c,srcid); /* Back to the source DB */
ed9b544e 4891
4892 /* If the user is moving using as target the same
4893 * DB as the source DB it is probably an error. */
4894 if (src == dst) {
c937aa89 4895 addReply(c,shared.sameobjecterr);
ed9b544e 4896 return;
4897 }
4898
4899 /* Check if the element exists and get a reference */
3305306f 4900 o = lookupKeyWrite(c->db,c->argv[1]);
4901 if (!o) {
c937aa89 4902 addReply(c,shared.czero);
ed9b544e 4903 return;
4904 }
4905
4906 /* Try to add the element to the target DB */
3305306f 4907 deleteIfVolatile(dst,c->argv[1]);
09241813 4908 if (dbAdd(dst,c->argv[1],o) == REDIS_ERR) {
c937aa89 4909 addReply(c,shared.czero);
ed9b544e 4910 return;
4911 }
ed9b544e 4912 incrRefCount(o);
4913
4914 /* OK! key moved, free the entry in the source DB */
09241813 4915 dbDelete(src,c->argv[1]);
ed9b544e 4916 server.dirty++;
c937aa89 4917 addReply(c,shared.cone);
ed9b544e 4918}
4919
4920/* =================================== Lists ================================ */
d0686e07
PN
4921
4922
4923/* Check the argument length to see if it requires us to convert the ziplist
4924 * to a real list. Only check raw-encoded objects because integer encoded
4925 * objects are never too long. */
003f0840 4926static void listTypeTryConversion(robj *subject, robj *value) {
d0686e07
PN
4927 if (subject->encoding != REDIS_ENCODING_ZIPLIST) return;
4928 if (value->encoding == REDIS_ENCODING_RAW &&
4929 sdslen(value->ptr) > server.list_max_ziplist_value)
7e79de54 4930 listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST);
d0686e07
PN
4931}
4932
003f0840 4933static void listTypePush(robj *subject, robj *value, int where) {
d0686e07 4934 /* Check if we need to convert the ziplist */
003f0840 4935 listTypeTryConversion(subject,value);
d0686e07 4936 if (subject->encoding == REDIS_ENCODING_ZIPLIST &&
70b4b320 4937 ziplistLen(subject->ptr) >= server.list_max_ziplist_entries)
7e79de54 4938 listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST);
d0686e07 4939
c7d9d662
PN
4940 if (subject->encoding == REDIS_ENCODING_ZIPLIST) {
4941 int pos = (where == REDIS_HEAD) ? ZIPLIST_HEAD : ZIPLIST_TAIL;
4942 value = getDecodedObject(value);
4943 subject->ptr = ziplistPush(subject->ptr,value->ptr,sdslen(value->ptr),pos);
4944 decrRefCount(value);
7e79de54 4945 } else if (subject->encoding == REDIS_ENCODING_LINKEDLIST) {
c7d9d662
PN
4946 if (where == REDIS_HEAD) {
4947 listAddNodeHead(subject->ptr,value);
4948 } else {
4949 listAddNodeTail(subject->ptr,value);
4950 }
4951 incrRefCount(value);
4952 } else {
4953 redisPanic("Unknown list encoding");
4954 }
4955}
4956
003f0840 4957static robj *listTypePop(robj *subject, int where) {
d72562f7
PN
4958 robj *value = NULL;
4959 if (subject->encoding == REDIS_ENCODING_ZIPLIST) {
4960 unsigned char *p;
b6eb9703 4961 unsigned char *vstr;
d72562f7 4962 unsigned int vlen;
b6eb9703 4963 long long vlong;
d72562f7
PN
4964 int pos = (where == REDIS_HEAD) ? 0 : -1;
4965 p = ziplistIndex(subject->ptr,pos);
b6eb9703
PN
4966 if (ziplistGet(p,&vstr,&vlen,&vlong)) {
4967 if (vstr) {
4968 value = createStringObject((char*)vstr,vlen);
d72562f7 4969 } else {
b6eb9703 4970 value = createStringObjectFromLongLong(vlong);
d72562f7 4971 }
0f62e177
PN
4972 /* We only need to delete an element when it exists */
4973 subject->ptr = ziplistDelete(subject->ptr,&p);
d72562f7 4974 }
7e79de54 4975 } else if (subject->encoding == REDIS_ENCODING_LINKEDLIST) {
d72562f7
PN
4976 list *list = subject->ptr;
4977 listNode *ln;
4978 if (where == REDIS_HEAD) {
4979 ln = listFirst(list);
4980 } else {
4981 ln = listLast(list);
4982 }
4983 if (ln != NULL) {
4984 value = listNodeValue(ln);
4985 incrRefCount(value);
4986 listDelNode(list,ln);
4987 }
4988 } else {
4989 redisPanic("Unknown list encoding");
4990 }
4991 return value;
4992}
4993
003f0840 4994static unsigned long listTypeLength(robj *subject) {
d72562f7
PN
4995 if (subject->encoding == REDIS_ENCODING_ZIPLIST) {
4996 return ziplistLen(subject->ptr);
7e79de54 4997 } else if (subject->encoding == REDIS_ENCODING_LINKEDLIST) {
d72562f7
PN
4998 return listLength((list*)subject->ptr);
4999 } else {
5000 redisPanic("Unknown list encoding");
5001 }
5002}
5003
a6dd455b
PN
5004/* Structure to hold set iteration abstraction. */
5005typedef struct {
5006 robj *subject;
5007 unsigned char encoding;
be02a7c0 5008 unsigned char direction; /* Iteration direction */
a6dd455b
PN
5009 unsigned char *zi;
5010 listNode *ln;
003f0840 5011} listTypeIterator;
a6dd455b 5012
be02a7c0
PN
5013/* Structure for an entry while iterating over a list. */
5014typedef struct {
003f0840 5015 listTypeIterator *li;
be02a7c0
PN
5016 unsigned char *zi; /* Entry in ziplist */
5017 listNode *ln; /* Entry in linked list */
003f0840 5018} listTypeEntry;
be02a7c0 5019
a6dd455b 5020/* Initialize an iterator at the specified index. */
003f0840
PN
5021static listTypeIterator *listTypeInitIterator(robj *subject, int index, unsigned char direction) {
5022 listTypeIterator *li = zmalloc(sizeof(listTypeIterator));
a6dd455b
PN
5023 li->subject = subject;
5024 li->encoding = subject->encoding;
be02a7c0 5025 li->direction = direction;
a6dd455b
PN
5026 if (li->encoding == REDIS_ENCODING_ZIPLIST) {
5027 li->zi = ziplistIndex(subject->ptr,index);
7e79de54 5028 } else if (li->encoding == REDIS_ENCODING_LINKEDLIST) {
a6dd455b
PN
5029 li->ln = listIndex(subject->ptr,index);
5030 } else {
5031 redisPanic("Unknown list encoding");
5032 }
5033 return li;
5034}
5035
5036/* Clean up the iterator. */
003f0840 5037static void listTypeReleaseIterator(listTypeIterator *li) {
a6dd455b
PN
5038 zfree(li);
5039}
5040
be02a7c0
PN
5041/* Stores pointer to current the entry in the provided entry structure
5042 * and advances the position of the iterator. Returns 1 when the current
5043 * entry is in fact an entry, 0 otherwise. */
003f0840 5044static int listTypeNext(listTypeIterator *li, listTypeEntry *entry) {
dda20542
PN
5045 /* Protect from converting when iterating */
5046 redisAssert(li->subject->encoding == li->encoding);
5047
be02a7c0 5048 entry->li = li;
d2ee16ab 5049 if (li->encoding == REDIS_ENCODING_ZIPLIST) {
be02a7c0
PN
5050 entry->zi = li->zi;
5051 if (entry->zi != NULL) {
5052 if (li->direction == REDIS_TAIL)
5053 li->zi = ziplistNext(li->subject->ptr,li->zi);
5054 else
5055 li->zi = ziplistPrev(li->subject->ptr,li->zi);
5056 return 1;
5057 }
7e79de54 5058 } else if (li->encoding == REDIS_ENCODING_LINKEDLIST) {
be02a7c0
PN
5059 entry->ln = li->ln;
5060 if (entry->ln != NULL) {
5061 if (li->direction == REDIS_TAIL)
5062 li->ln = li->ln->next;
5063 else
5064 li->ln = li->ln->prev;
5065 return 1;
5066 }
d2ee16ab
PN
5067 } else {
5068 redisPanic("Unknown list encoding");
5069 }
be02a7c0 5070 return 0;
d2ee16ab
PN
5071}
5072
a6dd455b 5073/* Return entry or NULL at the current position of the iterator. */
003f0840
PN
5074static robj *listTypeGet(listTypeEntry *entry) {
5075 listTypeIterator *li = entry->li;
a6dd455b
PN
5076 robj *value = NULL;
5077 if (li->encoding == REDIS_ENCODING_ZIPLIST) {
b6eb9703 5078 unsigned char *vstr;
a6dd455b 5079 unsigned int vlen;
b6eb9703 5080 long long vlong;
be02a7c0 5081 redisAssert(entry->zi != NULL);
b6eb9703
PN
5082 if (ziplistGet(entry->zi,&vstr,&vlen,&vlong)) {
5083 if (vstr) {
5084 value = createStringObject((char*)vstr,vlen);
a6dd455b 5085 } else {
b6eb9703 5086 value = createStringObjectFromLongLong(vlong);
a6dd455b
PN
5087 }
5088 }
7e79de54 5089 } else if (li->encoding == REDIS_ENCODING_LINKEDLIST) {
be02a7c0
PN
5090 redisAssert(entry->ln != NULL);
5091 value = listNodeValue(entry->ln);
a6dd455b
PN
5092 incrRefCount(value);
5093 } else {
5094 redisPanic("Unknown list encoding");
5095 }
5096 return value;
5097}
5098
bcfb3876
PN
5099static void listTypeInsert(listTypeEntry *entry, robj *value, int where) {
5100 robj *subject = entry->li->subject;
5101 if (entry->li->encoding == REDIS_ENCODING_ZIPLIST) {
244b873b 5102 value = getDecodedObject(value);
279d7e67 5103 if (where == REDIS_TAIL) {
bcfb3876
PN
5104 unsigned char *next = ziplistNext(subject->ptr,entry->zi);
5105
5106 /* When we insert after the current element, but the current element
5107 * is the tail of the list, we need to do a push. */
0e1684bc 5108 if (next == NULL) {
bcfb3876 5109 subject->ptr = ziplistPush(subject->ptr,value->ptr,sdslen(value->ptr),REDIS_TAIL);
0e1684bc 5110 } else {
bcfb3876 5111 subject->ptr = ziplistInsert(subject->ptr,next,value->ptr,sdslen(value->ptr));
0e1684bc
PN
5112 }
5113 } else {
bcfb3876 5114 subject->ptr = ziplistInsert(subject->ptr,entry->zi,value->ptr,sdslen(value->ptr));
0e1684bc 5115 }
244b873b 5116 decrRefCount(value);
7e79de54 5117 } else if (entry->li->encoding == REDIS_ENCODING_LINKEDLIST) {
279d7e67 5118 if (where == REDIS_TAIL) {
bcfb3876 5119 listInsertNode(subject->ptr,entry->ln,value,AL_START_TAIL);
0e1684bc 5120 } else {
bcfb3876 5121 listInsertNode(subject->ptr,entry->ln,value,AL_START_HEAD);
0e1684bc 5122 }
bcfb3876 5123 incrRefCount(value);
0e1684bc
PN
5124 } else {
5125 redisPanic("Unknown list encoding");
5126 }
5127}
5128
d2ee16ab 5129/* Compare the given object with the entry at the current position. */
003f0840
PN
5130static int listTypeEqual(listTypeEntry *entry, robj *o) {
5131 listTypeIterator *li = entry->li;
d2ee16ab
PN
5132 if (li->encoding == REDIS_ENCODING_ZIPLIST) {
5133 redisAssert(o->encoding == REDIS_ENCODING_RAW);
be02a7c0 5134 return ziplistCompare(entry->zi,o->ptr,sdslen(o->ptr));
7e79de54 5135 } else if (li->encoding == REDIS_ENCODING_LINKEDLIST) {
be02a7c0 5136 return equalStringObjects(o,listNodeValue(entry->ln));
d2ee16ab
PN
5137 } else {
5138 redisPanic("Unknown list encoding");
5139 }
5140}
5141
be02a7c0 5142/* Delete the element pointed to. */
003f0840
PN
5143static void listTypeDelete(listTypeEntry *entry) {
5144 listTypeIterator *li = entry->li;
a6dd455b 5145 if (li->encoding == REDIS_ENCODING_ZIPLIST) {
be02a7c0
PN
5146 unsigned char *p = entry->zi;
5147 li->subject->ptr = ziplistDelete(li->subject->ptr,&p);
5148
5149 /* Update position of the iterator depending on the direction */
5150 if (li->direction == REDIS_TAIL)
5151 li->zi = p;
a6dd455b 5152 else
be02a7c0 5153 li->zi = ziplistPrev(li->subject->ptr,p);
7e79de54 5154 } else if (entry->li->encoding == REDIS_ENCODING_LINKEDLIST) {
be02a7c0
PN
5155 listNode *next;
5156 if (li->direction == REDIS_TAIL)
5157 next = entry->ln->next;
a6dd455b 5158 else
be02a7c0
PN
5159 next = entry->ln->prev;
5160 listDelNode(li->subject->ptr,entry->ln);
5161 li->ln = next;
a6dd455b
PN
5162 } else {
5163 redisPanic("Unknown list encoding");
5164 }
5165}
3305306f 5166
003f0840
PN
5167static void listTypeConvert(robj *subject, int enc) {
5168 listTypeIterator *li;
5169 listTypeEntry entry;
d0686e07
PN
5170 redisAssert(subject->type == REDIS_LIST);
5171
7e79de54 5172 if (enc == REDIS_ENCODING_LINKEDLIST) {
d0686e07 5173 list *l = listCreate();
cd627d4e 5174 listSetFreeMethod(l,decrRefCount);
d0686e07 5175
003f0840
PN
5176 /* listTypeGet returns a robj with incremented refcount */
5177 li = listTypeInitIterator(subject,0,REDIS_TAIL);
5178 while (listTypeNext(li,&entry)) listAddNodeTail(l,listTypeGet(&entry));
5179 listTypeReleaseIterator(li);
d0686e07 5180
7e79de54 5181 subject->encoding = REDIS_ENCODING_LINKEDLIST;
d0686e07
PN
5182 zfree(subject->ptr);
5183 subject->ptr = l;
5184 } else {
5185 redisPanic("Unsupported list conversion");
5186 }
5187}
5188
c7d9d662
PN
5189static void pushGenericCommand(redisClient *c, int where) {
5190 robj *lobj = lookupKeyWrite(c->db,c->argv[1]);
3305306f 5191 if (lobj == NULL) {
95242ab5 5192 if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) {
520b5a33 5193 addReply(c,shared.cone);
95242ab5 5194 return;
5195 }
1cd92e7f 5196 lobj = createZiplistObject();
09241813 5197 dbAdd(c->db,c->argv[1],lobj);
ed9b544e 5198 } else {
ed9b544e 5199 if (lobj->type != REDIS_LIST) {
5200 addReply(c,shared.wrongtypeerr);
5201 return;
5202 }
95242ab5 5203 if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) {
520b5a33 5204 addReply(c,shared.cone);
95242ab5 5205 return;
5206 }
ed9b544e 5207 }
003f0840
PN
5208 listTypePush(lobj,c->argv[2],where);
5209 addReplyLongLong(c,listTypeLength(lobj));
ed9b544e 5210 server.dirty++;
ed9b544e 5211}
5212
5213static void lpushCommand(redisClient *c) {
5214 pushGenericCommand(c,REDIS_HEAD);
5215}
5216
5217static void rpushCommand(redisClient *c) {
5218 pushGenericCommand(c,REDIS_TAIL);
5219}
5220
bcfb3876 5221static void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int where) {
dedff272
RP
5222 robj *subject;
5223 listTypeIterator *iter;
5224 listTypeEntry entry;
70b4b320 5225 int inserted = 0;
dedff272
RP
5226
5227 if ((subject = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
5228 checkType(c,subject,REDIS_LIST)) return;
dedff272 5229
bcfb3876
PN
5230 if (refval != NULL) {
5231 /* Note: we expect refval to be string-encoded because it is *not* the
5232 * last argument of the multi-bulk LINSERT. */
5233 redisAssert(refval->encoding == REDIS_ENCODING_RAW);
5234
70b4b320
PN
5235 /* We're not sure if this value can be inserted yet, but we cannot
5236 * convert the list inside the iterator. We don't want to loop over
5237 * the list twice (once to see if the value can be inserted and once
5238 * to do the actual insert), so we assume this value can be inserted
5239 * and convert the ziplist to a regular list if necessary. */
5240 listTypeTryConversion(subject,val);
5241
bcfb3876 5242 /* Seek refval from head to tail */
1240552d 5243 iter = listTypeInitIterator(subject,0,REDIS_TAIL);
dedff272 5244 while (listTypeNext(iter,&entry)) {
bcfb3876
PN
5245 if (listTypeEqual(&entry,refval)) {
5246 listTypeInsert(&entry,val,where);
70b4b320 5247 inserted = 1;
dedff272
RP
5248 break;
5249 }
5250 }
5251 listTypeReleaseIterator(iter);
70b4b320
PN
5252
5253 if (inserted) {
5254 /* Check if the length exceeds the ziplist length threshold. */
5255 if (subject->encoding == REDIS_ENCODING_ZIPLIST &&
5256 ziplistLen(subject->ptr) > server.list_max_ziplist_entries)
7e79de54 5257 listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST);
70b4b320 5258 server.dirty++;
23d3a5fe
PN
5259 } else {
5260 /* Notify client of a failed insert */
5261 addReply(c,shared.cnegone);
5262 return;
70b4b320 5263 }
dedff272 5264 } else {
bcfb3876 5265 listTypePush(subject,val,where);
70b4b320 5266 server.dirty++;
dedff272
RP
5267 }
5268
dedff272
RP
5269 addReplyUlong(c,listTypeLength(subject));
5270}
5271
5272static void lpushxCommand(redisClient *c) {
bcfb3876 5273 pushxGenericCommand(c,NULL,c->argv[2],REDIS_HEAD);
dedff272
RP
5274}
5275
5276static void rpushxCommand(redisClient *c) {
bcfb3876 5277 pushxGenericCommand(c,NULL,c->argv[2],REDIS_TAIL);
dedff272
RP
5278}
5279
5280static void linsertCommand(redisClient *c) {
5281 if (strcasecmp(c->argv[2]->ptr,"after") == 0) {
bcfb3876 5282 pushxGenericCommand(c,c->argv[3],c->argv[4],REDIS_TAIL);
279d7e67 5283 } else if (strcasecmp(c->argv[2]->ptr,"before") == 0) {
bcfb3876 5284 pushxGenericCommand(c,c->argv[3],c->argv[4],REDIS_HEAD);
dedff272
RP
5285 } else {
5286 addReply(c,shared.syntaxerr);
5287 }
5288}
5289
ed9b544e 5290static void llenCommand(redisClient *c) {
d72562f7
PN
5291 robj *o = lookupKeyReadOrReply(c,c->argv[1],shared.czero);
5292 if (o == NULL || checkType(c,o,REDIS_LIST)) return;
003f0840 5293 addReplyUlong(c,listTypeLength(o));
ed9b544e 5294}
5295
5296static void lindexCommand(redisClient *c) {
697bd567
PN
5297 robj *o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk);
5298 if (o == NULL || checkType(c,o,REDIS_LIST)) return;
ed9b544e 5299 int index = atoi(c->argv[2]->ptr);
bd8db0ad 5300 robj *value = NULL;
dd88747b 5301
697bd567
PN
5302 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
5303 unsigned char *p;
b6eb9703 5304 unsigned char *vstr;
697bd567 5305 unsigned int vlen;
b6eb9703 5306 long long vlong;
697bd567 5307 p = ziplistIndex(o->ptr,index);
b6eb9703
PN
5308 if (ziplistGet(p,&vstr,&vlen,&vlong)) {
5309 if (vstr) {
5310 value = createStringObject((char*)vstr,vlen);
697bd567 5311 } else {
b6eb9703 5312 value = createStringObjectFromLongLong(vlong);
697bd567 5313 }
bd8db0ad
PN
5314 addReplyBulk(c,value);
5315 decrRefCount(value);
697bd567
PN
5316 } else {
5317 addReply(c,shared.nullbulk);
5318 }
7e79de54 5319 } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
697bd567
PN
5320 listNode *ln = listIndex(o->ptr,index);
5321 if (ln != NULL) {
bd8db0ad
PN
5322 value = listNodeValue(ln);
5323 addReplyBulk(c,value);
697bd567
PN
5324 } else {
5325 addReply(c,shared.nullbulk);
5326 }
ed9b544e 5327 } else {
697bd567 5328 redisPanic("Unknown list encoding");
ed9b544e 5329 }
5330}
5331
5332static void lsetCommand(redisClient *c) {
697bd567
PN
5333 robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr);
5334 if (o == NULL || checkType(c,o,REDIS_LIST)) return;
ed9b544e 5335 int index = atoi(c->argv[2]->ptr);
697bd567 5336 robj *value = c->argv[3];
dd88747b 5337
003f0840 5338 listTypeTryConversion(o,value);
697bd567
PN
5339 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
5340 unsigned char *p, *zl = o->ptr;
5341 p = ziplistIndex(zl,index);
5342 if (p == NULL) {
5343 addReply(c,shared.outofrangeerr);
5344 } else {
be02a7c0 5345 o->ptr = ziplistDelete(o->ptr,&p);
697bd567
PN
5346 value = getDecodedObject(value);
5347 o->ptr = ziplistInsert(o->ptr,p,value->ptr,sdslen(value->ptr));
5348 decrRefCount(value);
5349 addReply(c,shared.ok);
5350 server.dirty++;
5351 }
7e79de54 5352 } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
697bd567
PN
5353 listNode *ln = listIndex(o->ptr,index);
5354 if (ln == NULL) {
5355 addReply(c,shared.outofrangeerr);
5356 } else {
5357 decrRefCount((robj*)listNodeValue(ln));
5358 listNodeValue(ln) = value;
5359 incrRefCount(value);
5360 addReply(c,shared.ok);
5361 server.dirty++;
5362 }
ed9b544e 5363 } else {
697bd567 5364 redisPanic("Unknown list encoding");
ed9b544e 5365 }
5366}
5367
5368static void popGenericCommand(redisClient *c, int where) {
d72562f7
PN
5369 robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk);
5370 if (o == NULL || checkType(c,o,REDIS_LIST)) return;
3305306f 5371
003f0840 5372 robj *value = listTypePop(o,where);
d72562f7 5373 if (value == NULL) {
dd88747b 5374 addReply(c,shared.nullbulk);
5375 } else {
d72562f7
PN
5376 addReplyBulk(c,value);
5377 decrRefCount(value);
003f0840 5378 if (listTypeLength(o) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5379 server.dirty++;
ed9b544e 5380 }
5381}
5382
5383static void lpopCommand(redisClient *c) {
5384 popGenericCommand(c,REDIS_HEAD);
5385}
5386
5387static void rpopCommand(redisClient *c) {
5388 popGenericCommand(c,REDIS_TAIL);
5389}
5390
5391static void lrangeCommand(redisClient *c) {
a6dd455b 5392 robj *o, *value;
ed9b544e 5393 int start = atoi(c->argv[2]->ptr);
5394 int end = atoi(c->argv[3]->ptr);
dd88747b 5395 int llen;
5396 int rangelen, j;
003f0840 5397 listTypeEntry entry;
dd88747b 5398
4e27f268 5399 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
5400 || checkType(c,o,REDIS_LIST)) return;
003f0840 5401 llen = listTypeLength(o);
dd88747b 5402
5403 /* convert negative indexes */
5404 if (start < 0) start = llen+start;
5405 if (end < 0) end = llen+end;
5406 if (start < 0) start = 0;
5407 if (end < 0) end = 0;
5408
5409 /* indexes sanity checks */
5410 if (start > end || start >= llen) {
5411 /* Out of range start or start > end result in empty list */
5412 addReply(c,shared.emptymultibulk);
5413 return;
5414 }
5415 if (end >= llen) end = llen-1;
5416 rangelen = (end-start)+1;
3305306f 5417
dd88747b 5418 /* Return the result in form of a multi-bulk reply */
dd88747b 5419 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen));
003f0840 5420 listTypeIterator *li = listTypeInitIterator(o,start,REDIS_TAIL);
dd88747b 5421 for (j = 0; j < rangelen; j++) {
003f0840
PN
5422 redisAssert(listTypeNext(li,&entry));
5423 value = listTypeGet(&entry);
a6dd455b 5424 addReplyBulk(c,value);
be02a7c0 5425 decrRefCount(value);
ed9b544e 5426 }
003f0840 5427 listTypeReleaseIterator(li);
ed9b544e 5428}
5429
5430static void ltrimCommand(redisClient *c) {
3305306f 5431 robj *o;
ed9b544e 5432 int start = atoi(c->argv[2]->ptr);
5433 int end = atoi(c->argv[3]->ptr);
dd88747b 5434 int llen;
5435 int j, ltrim, rtrim;
5436 list *list;
5437 listNode *ln;
5438
5439 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.ok)) == NULL ||
5440 checkType(c,o,REDIS_LIST)) return;
003f0840 5441 llen = listTypeLength(o);
dd88747b 5442
5443 /* convert negative indexes */
5444 if (start < 0) start = llen+start;
5445 if (end < 0) end = llen+end;
5446 if (start < 0) start = 0;
5447 if (end < 0) end = 0;
5448
5449 /* indexes sanity checks */
5450 if (start > end || start >= llen) {
5451 /* Out of range start or start > end result in empty list */
5452 ltrim = llen;
5453 rtrim = 0;
ed9b544e 5454 } else {
dd88747b 5455 if (end >= llen) end = llen-1;
5456 ltrim = start;
5457 rtrim = llen-end-1;
5458 }
ed9b544e 5459
dd88747b 5460 /* Remove list elements to perform the trim */
9ae6b0be
PN
5461 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
5462 o->ptr = ziplistDeleteRange(o->ptr,0,ltrim);
5463 o->ptr = ziplistDeleteRange(o->ptr,-rtrim,rtrim);
7e79de54 5464 } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
9ae6b0be
PN
5465 list = o->ptr;
5466 for (j = 0; j < ltrim; j++) {
5467 ln = listFirst(list);
5468 listDelNode(list,ln);
5469 }
5470 for (j = 0; j < rtrim; j++) {
5471 ln = listLast(list);
5472 listDelNode(list,ln);
5473 }
5474 } else {
5475 redisPanic("Unknown list encoding");
ed9b544e 5476 }
003f0840 5477 if (listTypeLength(o) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5478 server.dirty++;
5479 addReply(c,shared.ok);
ed9b544e 5480}
5481
5482static void lremCommand(redisClient *c) {
d2ee16ab 5483 robj *subject, *obj = c->argv[3];
dd88747b 5484 int toremove = atoi(c->argv[2]->ptr);
5485 int removed = 0;
003f0840 5486 listTypeEntry entry;
a4d1ba9a 5487
d2ee16ab
PN
5488 subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero);
5489 if (subject == NULL || checkType(c,subject,REDIS_LIST)) return;
dd88747b 5490
d2ee16ab
PN
5491 /* Make sure obj is raw when we're dealing with a ziplist */
5492 if (subject->encoding == REDIS_ENCODING_ZIPLIST)
5493 obj = getDecodedObject(obj);
5494
003f0840 5495 listTypeIterator *li;
dd88747b 5496 if (toremove < 0) {
5497 toremove = -toremove;
003f0840 5498 li = listTypeInitIterator(subject,-1,REDIS_HEAD);
d2ee16ab 5499 } else {
003f0840 5500 li = listTypeInitIterator(subject,0,REDIS_TAIL);
dd88747b 5501 }
dd88747b 5502
003f0840
PN
5503 while (listTypeNext(li,&entry)) {
5504 if (listTypeEqual(&entry,obj)) {
5505 listTypeDelete(&entry);
dd88747b 5506 server.dirty++;
5507 removed++;
3fbf9001 5508 if (toremove && removed == toremove) break;
ed9b544e 5509 }
5510 }
003f0840 5511 listTypeReleaseIterator(li);
d2ee16ab
PN
5512
5513 /* Clean up raw encoded object */
5514 if (subject->encoding == REDIS_ENCODING_ZIPLIST)
5515 decrRefCount(obj);
5516
003f0840 5517 if (listTypeLength(subject) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5518 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",removed));
ed9b544e 5519}
5520
12f9d551 5521/* This is the semantic of this command:
0f5f7e9a 5522 * RPOPLPUSH srclist dstlist:
12f9d551 5523 * IF LLEN(srclist) > 0
5524 * element = RPOP srclist
5525 * LPUSH dstlist element
5526 * RETURN element
5527 * ELSE
5528 * RETURN nil
5529 * END
5530 * END
5531 *
5532 * The idea is to be able to get an element from a list in a reliable way
5533 * since the element is not just returned but pushed against another list
5534 * as well. This command was originally proposed by Ezra Zygmuntowicz.
5535 */
0f5f7e9a 5536static void rpoplpushcommand(redisClient *c) {
0f62e177 5537 robj *sobj, *value;
dd88747b 5538 if ((sobj = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
5539 checkType(c,sobj,REDIS_LIST)) return;
12f9d551 5540
003f0840 5541 if (listTypeLength(sobj) == 0) {
12f9d551 5542 addReply(c,shared.nullbulk);
5543 } else {
dd88747b 5544 robj *dobj = lookupKeyWrite(c->db,c->argv[2]);
0f62e177 5545 if (dobj && checkType(c,dobj,REDIS_LIST)) return;
003f0840 5546 value = listTypePop(sobj,REDIS_TAIL);
12f9d551 5547
dd88747b 5548 /* Add the element to the target list (unless it's directly
5549 * passed to some BLPOP-ing client */
0f62e177
PN
5550 if (!handleClientsWaitingListPush(c,c->argv[2],value)) {
5551 /* Create the list if the key does not exist */
5552 if (!dobj) {
1cd92e7f 5553 dobj = createZiplistObject();
09241813 5554 dbAdd(c->db,c->argv[2],dobj);
12f9d551 5555 }
003f0840 5556 listTypePush(dobj,value,REDIS_HEAD);
12f9d551 5557 }
dd88747b 5558
5559 /* Send the element to the client as reply as well */
0f62e177
PN
5560 addReplyBulk(c,value);
5561
003f0840 5562 /* listTypePop returns an object with its refcount incremented */
0f62e177 5563 decrRefCount(value);
dd88747b 5564
0f62e177 5565 /* Delete the source list when it is empty */
003f0840 5566 if (listTypeLength(sobj) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5567 server.dirty++;
12f9d551 5568 }
5569}
5570
ed9b544e 5571/* ==================================== Sets ================================ */
5572
5573static void saddCommand(redisClient *c) {
ed9b544e 5574 robj *set;
5575
3305306f 5576 set = lookupKeyWrite(c->db,c->argv[1]);
5577 if (set == NULL) {
ed9b544e 5578 set = createSetObject();
09241813 5579 dbAdd(c->db,c->argv[1],set);
ed9b544e 5580 } else {
ed9b544e 5581 if (set->type != REDIS_SET) {
c937aa89 5582 addReply(c,shared.wrongtypeerr);
ed9b544e 5583 return;
5584 }
5585 }
5586 if (dictAdd(set->ptr,c->argv[2],NULL) == DICT_OK) {
5587 incrRefCount(c->argv[2]);
5588 server.dirty++;
c937aa89 5589 addReply(c,shared.cone);
ed9b544e 5590 } else {
c937aa89 5591 addReply(c,shared.czero);
ed9b544e 5592 }
5593}
5594
5595static void sremCommand(redisClient *c) {
3305306f 5596 robj *set;
ed9b544e 5597
dd88747b 5598 if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
5599 checkType(c,set,REDIS_SET)) return;
5600
5601 if (dictDelete(set->ptr,c->argv[2]) == DICT_OK) {
5602 server.dirty++;
5603 if (htNeedsResize(set->ptr)) dictResize(set->ptr);
09241813 5604 if (dictSize((dict*)set->ptr) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5605 addReply(c,shared.cone);
ed9b544e 5606 } else {
dd88747b 5607 addReply(c,shared.czero);
ed9b544e 5608 }
5609}
5610
a4460ef4 5611static void smoveCommand(redisClient *c) {
5612 robj *srcset, *dstset;
5613
5614 srcset = lookupKeyWrite(c->db,c->argv[1]);
5615 dstset = lookupKeyWrite(c->db,c->argv[2]);
5616
5617 /* If the source key does not exist return 0, if it's of the wrong type
5618 * raise an error */
5619 if (srcset == NULL || srcset->type != REDIS_SET) {
5620 addReply(c, srcset ? shared.wrongtypeerr : shared.czero);
5621 return;
5622 }
5623 /* Error if the destination key is not a set as well */
5624 if (dstset && dstset->type != REDIS_SET) {
5625 addReply(c,shared.wrongtypeerr);
5626 return;
5627 }
5628 /* Remove the element from the source set */
5629 if (dictDelete(srcset->ptr,c->argv[3]) == DICT_ERR) {
5630 /* Key not found in the src set! return zero */
5631 addReply(c,shared.czero);
5632 return;
5633 }
3ea27d37 5634 if (dictSize((dict*)srcset->ptr) == 0 && srcset != dstset)
09241813 5635 dbDelete(c->db,c->argv[1]);
a4460ef4 5636 server.dirty++;
5637 /* Add the element to the destination set */
5638 if (!dstset) {
5639 dstset = createSetObject();
09241813 5640 dbAdd(c->db,c->argv[2],dstset);
a4460ef4 5641 }
5642 if (dictAdd(dstset->ptr,c->argv[3],NULL) == DICT_OK)
5643 incrRefCount(c->argv[3]);
5644 addReply(c,shared.cone);
5645}
5646
ed9b544e 5647static void sismemberCommand(redisClient *c) {
3305306f 5648 robj *set;
ed9b544e 5649
dd88747b 5650 if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
5651 checkType(c,set,REDIS_SET)) return;
5652
5653 if (dictFind(set->ptr,c->argv[2]))
5654 addReply(c,shared.cone);
5655 else
c937aa89 5656 addReply(c,shared.czero);
ed9b544e 5657}
5658
5659static void scardCommand(redisClient *c) {
3305306f 5660 robj *o;
ed9b544e 5661 dict *s;
dd88747b 5662
5663 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
5664 checkType(c,o,REDIS_SET)) return;
e0a62c7f 5665
dd88747b 5666 s = o->ptr;
5667 addReplyUlong(c,dictSize(s));
ed9b544e 5668}
5669
12fea928 5670static void spopCommand(redisClient *c) {
5671 robj *set;
5672 dictEntry *de;
5673
dd88747b 5674 if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
5675 checkType(c,set,REDIS_SET)) return;
5676
5677 de = dictGetRandomKey(set->ptr);
5678 if (de == NULL) {
12fea928 5679 addReply(c,shared.nullbulk);
5680 } else {
dd88747b 5681 robj *ele = dictGetEntryKey(de);
12fea928 5682
dd88747b 5683 addReplyBulk(c,ele);
5684 dictDelete(set->ptr,ele);
5685 if (htNeedsResize(set->ptr)) dictResize(set->ptr);
09241813 5686 if (dictSize((dict*)set->ptr) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 5687 server.dirty++;
12fea928 5688 }
5689}
5690
2abb95a9 5691static void srandmemberCommand(redisClient *c) {
5692 robj *set;
5693 dictEntry *de;
5694
dd88747b 5695 if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
5696 checkType(c,set,REDIS_SET)) return;
5697
5698 de = dictGetRandomKey(set->ptr);
5699 if (de == NULL) {
2abb95a9 5700 addReply(c,shared.nullbulk);
5701 } else {
dd88747b 5702 robj *ele = dictGetEntryKey(de);
2abb95a9 5703
dd88747b 5704 addReplyBulk(c,ele);
2abb95a9 5705 }
5706}
5707
ed9b544e 5708static int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
5709 dict **d1 = (void*) s1, **d2 = (void*) s2;
5710
3305306f 5711 return dictSize(*d1)-dictSize(*d2);
ed9b544e 5712}
5713
682ac724 5714static void sinterGenericCommand(redisClient *c, robj **setskeys, unsigned long setsnum, robj *dstkey) {
ed9b544e 5715 dict **dv = zmalloc(sizeof(dict*)*setsnum);
5716 dictIterator *di;
5717 dictEntry *de;
5718 robj *lenobj = NULL, *dstset = NULL;
682ac724 5719 unsigned long j, cardinality = 0;
ed9b544e 5720
ed9b544e 5721 for (j = 0; j < setsnum; j++) {
5722 robj *setobj;
3305306f 5723
5724 setobj = dstkey ?
5725 lookupKeyWrite(c->db,setskeys[j]) :
5726 lookupKeyRead(c->db,setskeys[j]);
5727 if (!setobj) {
ed9b544e 5728 zfree(dv);
5faa6025 5729 if (dstkey) {
09241813 5730 if (dbDelete(c->db,dstkey))
fdcaae84 5731 server.dirty++;
0d36ded0 5732 addReply(c,shared.czero);
5faa6025 5733 } else {
4e27f268 5734 addReply(c,shared.emptymultibulk);
5faa6025 5735 }
ed9b544e 5736 return;
5737 }
ed9b544e 5738 if (setobj->type != REDIS_SET) {
5739 zfree(dv);
c937aa89 5740 addReply(c,shared.wrongtypeerr);
ed9b544e 5741 return;
5742 }
5743 dv[j] = setobj->ptr;
5744 }
5745 /* Sort sets from the smallest to largest, this will improve our
5746 * algorithm's performace */
5747 qsort(dv,setsnum,sizeof(dict*),qsortCompareSetsByCardinality);
5748
5749 /* The first thing we should output is the total number of elements...
5750 * since this is a multi-bulk write, but at this stage we don't know
5751 * the intersection set size, so we use a trick, append an empty object
5752 * to the output list and save the pointer to later modify it with the
5753 * right length */
5754 if (!dstkey) {
5755 lenobj = createObject(REDIS_STRING,NULL);
5756 addReply(c,lenobj);
5757 decrRefCount(lenobj);
5758 } else {
5759 /* If we have a target key where to store the resulting set
5760 * create this key with an empty set inside */
5761 dstset = createSetObject();
ed9b544e 5762 }
5763
5764 /* Iterate all the elements of the first (smallest) set, and test
5765 * the element against all the other sets, if at least one set does
5766 * not include the element it is discarded */
5767 di = dictGetIterator(dv[0]);
ed9b544e 5768
5769 while((de = dictNext(di)) != NULL) {
5770 robj *ele;
5771
5772 for (j = 1; j < setsnum; j++)
5773 if (dictFind(dv[j],dictGetEntryKey(de)) == NULL) break;
5774 if (j != setsnum)
5775 continue; /* at least one set does not contain the member */
5776 ele = dictGetEntryKey(de);
5777 if (!dstkey) {
dd88747b 5778 addReplyBulk(c,ele);
ed9b544e 5779 cardinality++;
5780 } else {
5781 dictAdd(dstset->ptr,ele,NULL);
5782 incrRefCount(ele);
5783 }
5784 }
5785 dictReleaseIterator(di);
5786
83cdfe18 5787 if (dstkey) {
3ea27d37 5788 /* Store the resulting set into the target, if the intersection
5789 * is not an empty set. */
09241813 5790 dbDelete(c->db,dstkey);
3ea27d37 5791 if (dictSize((dict*)dstset->ptr) > 0) {
09241813 5792 dbAdd(c->db,dstkey,dstset);
482b672d 5793 addReplyLongLong(c,dictSize((dict*)dstset->ptr));
3ea27d37 5794 } else {
5795 decrRefCount(dstset);
d36c4e97 5796 addReply(c,shared.czero);
3ea27d37 5797 }
40d224a9 5798 server.dirty++;
d36c4e97 5799 } else {
5800 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",cardinality);
40d224a9 5801 }
ed9b544e 5802 zfree(dv);
5803}
5804
5805static void sinterCommand(redisClient *c) {
5806 sinterGenericCommand(c,c->argv+1,c->argc-1,NULL);
5807}
5808
5809static void sinterstoreCommand(redisClient *c) {
5810 sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
5811}
5812
f4f56e1d 5813#define REDIS_OP_UNION 0
5814#define REDIS_OP_DIFF 1
2830ca53 5815#define REDIS_OP_INTER 2
f4f56e1d 5816
5817static void sunionDiffGenericCommand(redisClient *c, robj **setskeys, int setsnum, robj *dstkey, int op) {
40d224a9 5818 dict **dv = zmalloc(sizeof(dict*)*setsnum);
5819 dictIterator *di;
5820 dictEntry *de;
f4f56e1d 5821 robj *dstset = NULL;
40d224a9 5822 int j, cardinality = 0;
5823
40d224a9 5824 for (j = 0; j < setsnum; j++) {
5825 robj *setobj;
5826
5827 setobj = dstkey ?
5828 lookupKeyWrite(c->db,setskeys[j]) :
5829 lookupKeyRead(c->db,setskeys[j]);
5830 if (!setobj) {
5831 dv[j] = NULL;
5832 continue;
5833 }
5834 if (setobj->type != REDIS_SET) {
5835 zfree(dv);
5836 addReply(c,shared.wrongtypeerr);
5837 return;
5838 }
5839 dv[j] = setobj->ptr;
5840 }
5841
5842 /* We need a temp set object to store our union. If the dstkey
5843 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
5844 * this set object will be the resulting object to set into the target key*/
5845 dstset = createSetObject();
5846
40d224a9 5847 /* Iterate all the elements of all the sets, add every element a single
5848 * time to the result set */
5849 for (j = 0; j < setsnum; j++) {
51829ed3 5850 if (op == REDIS_OP_DIFF && j == 0 && !dv[j]) break; /* result set is empty */
40d224a9 5851 if (!dv[j]) continue; /* non existing keys are like empty sets */
5852
5853 di = dictGetIterator(dv[j]);
40d224a9 5854
5855 while((de = dictNext(di)) != NULL) {
5856 robj *ele;
5857
5858 /* dictAdd will not add the same element multiple times */
5859 ele = dictGetEntryKey(de);
f4f56e1d 5860 if (op == REDIS_OP_UNION || j == 0) {
5861 if (dictAdd(dstset->ptr,ele,NULL) == DICT_OK) {
5862 incrRefCount(ele);
40d224a9 5863 cardinality++;
5864 }
f4f56e1d 5865 } else if (op == REDIS_OP_DIFF) {
5866 if (dictDelete(dstset->ptr,ele) == DICT_OK) {
5867 cardinality--;
5868 }
40d224a9 5869 }
5870 }
5871 dictReleaseIterator(di);
51829ed3 5872
d36c4e97 5873 /* result set is empty? Exit asap. */
5874 if (op == REDIS_OP_DIFF && cardinality == 0) break;
40d224a9 5875 }
5876
f4f56e1d 5877 /* Output the content of the resulting set, if not in STORE mode */
5878 if (!dstkey) {
5879 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",cardinality));
5880 di = dictGetIterator(dstset->ptr);
f4f56e1d 5881 while((de = dictNext(di)) != NULL) {
5882 robj *ele;
5883
5884 ele = dictGetEntryKey(de);
dd88747b 5885 addReplyBulk(c,ele);
f4f56e1d 5886 }
5887 dictReleaseIterator(di);
d36c4e97 5888 decrRefCount(dstset);
83cdfe18
AG
5889 } else {
5890 /* If we have a target key where to store the resulting set
5891 * create this key with the result set inside */
09241813 5892 dbDelete(c->db,dstkey);
3ea27d37 5893 if (dictSize((dict*)dstset->ptr) > 0) {
09241813 5894 dbAdd(c->db,dstkey,dstset);
482b672d 5895 addReplyLongLong(c,dictSize((dict*)dstset->ptr));
3ea27d37 5896 } else {
5897 decrRefCount(dstset);
d36c4e97 5898 addReply(c,shared.czero);
3ea27d37 5899 }
40d224a9 5900 server.dirty++;
5901 }
5902 zfree(dv);
5903}
5904
5905static void sunionCommand(redisClient *c) {
f4f56e1d 5906 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_UNION);
40d224a9 5907}
5908
5909static void sunionstoreCommand(redisClient *c) {
f4f56e1d 5910 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_UNION);
5911}
5912
5913static void sdiffCommand(redisClient *c) {
5914 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_DIFF);
5915}
5916
5917static void sdiffstoreCommand(redisClient *c) {
5918 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_DIFF);
40d224a9 5919}
5920
6b47e12e 5921/* ==================================== ZSets =============================== */
5922
5923/* ZSETs are ordered sets using two data structures to hold the same elements
5924 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
5925 * data structure.
5926 *
5927 * The elements are added to an hash table mapping Redis objects to scores.
5928 * At the same time the elements are added to a skip list mapping scores
5929 * to Redis objects (so objects are sorted by scores in this "view"). */
5930
5931/* This skiplist implementation is almost a C translation of the original
5932 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
5933 * Alternative to Balanced Trees", modified in three ways:
5934 * a) this implementation allows for repeated values.
5935 * b) the comparison is not just by key (our 'score') but by satellite data.
5936 * c) there is a back pointer, so it's a doubly linked list with the back
5937 * pointers being only at "level 1". This allows to traverse the list
5938 * from tail to head, useful for ZREVRANGE. */
5939
5940static zskiplistNode *zslCreateNode(int level, double score, robj *obj) {
5941 zskiplistNode *zn = zmalloc(sizeof(*zn));
5942
5943 zn->forward = zmalloc(sizeof(zskiplistNode*) * level);
2f4dd7e0 5944 if (level > 1)
2b37892e 5945 zn->span = zmalloc(sizeof(unsigned int) * (level - 1));
2f4dd7e0 5946 else
5947 zn->span = NULL;
6b47e12e 5948 zn->score = score;
5949 zn->obj = obj;
5950 return zn;
5951}
5952
5953static zskiplist *zslCreate(void) {
5954 int j;
5955 zskiplist *zsl;
e0a62c7f 5956
6b47e12e 5957 zsl = zmalloc(sizeof(*zsl));
5958 zsl->level = 1;
cc812361 5959 zsl->length = 0;
6b47e12e 5960 zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
69d95c3e 5961 for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
6b47e12e 5962 zsl->header->forward[j] = NULL;
94e543b5 5963
5964 /* span has space for ZSKIPLIST_MAXLEVEL-1 elements */
5965 if (j < ZSKIPLIST_MAXLEVEL-1)
5966 zsl->header->span[j] = 0;
69d95c3e 5967 }
e3870fab 5968 zsl->header->backward = NULL;
5969 zsl->tail = NULL;
6b47e12e 5970 return zsl;
5971}
5972
fd8ccf44 5973static void zslFreeNode(zskiplistNode *node) {
5974 decrRefCount(node->obj);
ad807e6f 5975 zfree(node->forward);
69d95c3e 5976 zfree(node->span);
fd8ccf44 5977 zfree(node);
5978}
5979
5980static void zslFree(zskiplist *zsl) {
ad807e6f 5981 zskiplistNode *node = zsl->header->forward[0], *next;
fd8ccf44 5982
ad807e6f 5983 zfree(zsl->header->forward);
69d95c3e 5984 zfree(zsl->header->span);
ad807e6f 5985 zfree(zsl->header);
fd8ccf44 5986 while(node) {
599379dd 5987 next = node->forward[0];
fd8ccf44 5988 zslFreeNode(node);
5989 node = next;
5990 }
ad807e6f 5991 zfree(zsl);
fd8ccf44 5992}
5993
6b47e12e 5994static int zslRandomLevel(void) {
5995 int level = 1;
5996 while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
5997 level += 1;
10c2baa5 5998 return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
6b47e12e 5999}
6000
6001static void zslInsert(zskiplist *zsl, double score, robj *obj) {
6002 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
2b37892e 6003 unsigned int rank[ZSKIPLIST_MAXLEVEL];
6b47e12e 6004 int i, level;
6005
6006 x = zsl->header;
6007 for (i = zsl->level-1; i >= 0; i--) {
2b37892e
PN
6008 /* store rank that is crossed to reach the insert position */
6009 rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
69d95c3e 6010
9d60e6e4 6011 while (x->forward[i] &&
6012 (x->forward[i]->score < score ||
6013 (x->forward[i]->score == score &&
69d95c3e 6014 compareStringObjects(x->forward[i]->obj,obj) < 0))) {
a50ea45c 6015 rank[i] += i > 0 ? x->span[i-1] : 1;
6b47e12e 6016 x = x->forward[i];
69d95c3e 6017 }
6b47e12e 6018 update[i] = x;
6019 }
6b47e12e 6020 /* we assume the key is not already inside, since we allow duplicated
6021 * scores, and the re-insertion of score and redis object should never
6022 * happpen since the caller of zslInsert() should test in the hash table
6023 * if the element is already inside or not. */
6024 level = zslRandomLevel();
6025 if (level > zsl->level) {
69d95c3e 6026 for (i = zsl->level; i < level; i++) {
2b37892e 6027 rank[i] = 0;
6b47e12e 6028 update[i] = zsl->header;
2b37892e 6029 update[i]->span[i-1] = zsl->length;
69d95c3e 6030 }
6b47e12e 6031 zsl->level = level;
6032 }
6033 x = zslCreateNode(level,score,obj);
6034 for (i = 0; i < level; i++) {
6035 x->forward[i] = update[i]->forward[i];
6036 update[i]->forward[i] = x;
69d95c3e
PN
6037
6038 /* update span covered by update[i] as x is inserted here */
2b37892e
PN
6039 if (i > 0) {
6040 x->span[i-1] = update[i]->span[i-1] - (rank[0] - rank[i]);
6041 update[i]->span[i-1] = (rank[0] - rank[i]) + 1;
6042 }
6b47e12e 6043 }
69d95c3e
PN
6044
6045 /* increment span for untouched levels */
6046 for (i = level; i < zsl->level; i++) {
2b37892e 6047 update[i]->span[i-1]++;
69d95c3e
PN
6048 }
6049
bb975144 6050 x->backward = (update[0] == zsl->header) ? NULL : update[0];
e3870fab 6051 if (x->forward[0])
6052 x->forward[0]->backward = x;
6053 else
6054 zsl->tail = x;
cc812361 6055 zsl->length++;
6b47e12e 6056}
6057
84105336
PN
6058/* Internal function used by zslDelete, zslDeleteByScore and zslDeleteByRank */
6059void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) {
6060 int i;
6061 for (i = 0; i < zsl->level; i++) {
6062 if (update[i]->forward[i] == x) {
6063 if (i > 0) {
6064 update[i]->span[i-1] += x->span[i-1] - 1;
6065 }
6066 update[i]->forward[i] = x->forward[i];
6067 } else {
6068 /* invariant: i > 0, because update[0]->forward[0]
6069 * is always equal to x */
6070 update[i]->span[i-1] -= 1;
6071 }
6072 }
6073 if (x->forward[0]) {
6074 x->forward[0]->backward = x->backward;
6075 } else {
6076 zsl->tail = x->backward;
6077 }
6078 while(zsl->level > 1 && zsl->header->forward[zsl->level-1] == NULL)
6079 zsl->level--;
6080 zsl->length--;
6081}
6082
50c55df5 6083/* Delete an element with matching score/object from the skiplist. */
fd8ccf44 6084static int zslDelete(zskiplist *zsl, double score, robj *obj) {
e197b441 6085 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
6086 int i;
6087
6088 x = zsl->header;
6089 for (i = zsl->level-1; i >= 0; i--) {
9d60e6e4 6090 while (x->forward[i] &&
6091 (x->forward[i]->score < score ||
6092 (x->forward[i]->score == score &&
6093 compareStringObjects(x->forward[i]->obj,obj) < 0)))
e197b441 6094 x = x->forward[i];
6095 update[i] = x;
6096 }
6097 /* We may have multiple elements with the same score, what we need
6098 * is to find the element with both the right score and object. */
6099 x = x->forward[0];
bf028098 6100 if (x && score == x->score && equalStringObjects(x->obj,obj)) {
84105336 6101 zslDeleteNode(zsl, x, update);
9d60e6e4 6102 zslFreeNode(x);
9d60e6e4 6103 return 1;
6104 } else {
6105 return 0; /* not found */
e197b441 6106 }
6107 return 0; /* not found */
fd8ccf44 6108}
6109
1807985b 6110/* Delete all the elements with score between min and max from the skiplist.
6111 * Min and mx are inclusive, so a score >= min || score <= max is deleted.
6112 * Note that this function takes the reference to the hash table view of the
6113 * sorted set, in order to remove the elements from the hash table too. */
f84d3933 6114static unsigned long zslDeleteRangeByScore(zskiplist *zsl, double min, double max, dict *dict) {
1807985b 6115 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
6116 unsigned long removed = 0;
6117 int i;
6118
6119 x = zsl->header;
6120 for (i = zsl->level-1; i >= 0; i--) {
6121 while (x->forward[i] && x->forward[i]->score < min)
6122 x = x->forward[i];
6123 update[i] = x;
6124 }
6125 /* We may have multiple elements with the same score, what we need
6126 * is to find the element with both the right score and object. */
6127 x = x->forward[0];
6128 while (x && x->score <= max) {
84105336
PN
6129 zskiplistNode *next = x->forward[0];
6130 zslDeleteNode(zsl, x, update);
1807985b 6131 dictDelete(dict,x->obj);
6132 zslFreeNode(x);
1807985b 6133 removed++;
6134 x = next;
6135 }
6136 return removed; /* not found */
6137}
1807985b 6138
9212eafd 6139/* Delete all the elements with rank between start and end from the skiplist.
2424490f 6140 * Start and end are inclusive. Note that start and end need to be 1-based */
9212eafd
PN
6141static unsigned long zslDeleteRangeByRank(zskiplist *zsl, unsigned int start, unsigned int end, dict *dict) {
6142 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
6143 unsigned long traversed = 0, removed = 0;
6144 int i;
6145
9212eafd
PN
6146 x = zsl->header;
6147 for (i = zsl->level-1; i >= 0; i--) {
6148 while (x->forward[i] && (traversed + (i > 0 ? x->span[i-1] : 1)) < start) {
6149 traversed += i > 0 ? x->span[i-1] : 1;
6150 x = x->forward[i];
1807985b 6151 }
9212eafd
PN
6152 update[i] = x;
6153 }
6154
6155 traversed++;
6156 x = x->forward[0];
6157 while (x && traversed <= end) {
84105336
PN
6158 zskiplistNode *next = x->forward[0];
6159 zslDeleteNode(zsl, x, update);
1807985b 6160 dictDelete(dict,x->obj);
6161 zslFreeNode(x);
1807985b 6162 removed++;
9212eafd 6163 traversed++;
1807985b 6164 x = next;
6165 }
9212eafd 6166 return removed;
1807985b 6167}
6168
50c55df5 6169/* Find the first node having a score equal or greater than the specified one.
6170 * Returns NULL if there is no match. */
6171static zskiplistNode *zslFirstWithScore(zskiplist *zsl, double score) {
6172 zskiplistNode *x;
6173 int i;
6174
6175 x = zsl->header;
6176 for (i = zsl->level-1; i >= 0; i--) {
6177 while (x->forward[i] && x->forward[i]->score < score)
6178 x = x->forward[i];
6179 }
6180 /* We may have multiple elements with the same score, what we need
6181 * is to find the element with both the right score and object. */
6182 return x->forward[0];
6183}
6184
27b0ccca
PN
6185/* Find the rank for an element by both score and key.
6186 * Returns 0 when the element cannot be found, rank otherwise.
6187 * Note that the rank is 1-based due to the span of zsl->header to the
6188 * first element. */
003f0840 6189static unsigned long zslistTypeGetRank(zskiplist *zsl, double score, robj *o) {
27b0ccca
PN
6190 zskiplistNode *x;
6191 unsigned long rank = 0;
6192 int i;
6193
6194 x = zsl->header;
6195 for (i = zsl->level-1; i >= 0; i--) {
6196 while (x->forward[i] &&
6197 (x->forward[i]->score < score ||
6198 (x->forward[i]->score == score &&
6199 compareStringObjects(x->forward[i]->obj,o) <= 0))) {
a50ea45c 6200 rank += i > 0 ? x->span[i-1] : 1;
27b0ccca
PN
6201 x = x->forward[i];
6202 }
6203
6204 /* x might be equal to zsl->header, so test if obj is non-NULL */
bf028098 6205 if (x->obj && equalStringObjects(x->obj,o)) {
27b0ccca
PN
6206 return rank;
6207 }
6208 }
6209 return 0;
6210}
6211
e74825c2 6212/* Finds an element by its rank. The rank argument needs to be 1-based. */
003f0840 6213zskiplistNode* zslistTypeGetElementByRank(zskiplist *zsl, unsigned long rank) {
e74825c2
PN
6214 zskiplistNode *x;
6215 unsigned long traversed = 0;
6216 int i;
6217
6218 x = zsl->header;
6219 for (i = zsl->level-1; i >= 0; i--) {
dd88747b 6220 while (x->forward[i] && (traversed + (i>0 ? x->span[i-1] : 1)) <= rank)
6221 {
a50ea45c 6222 traversed += i > 0 ? x->span[i-1] : 1;
e74825c2
PN
6223 x = x->forward[i];
6224 }
e74825c2
PN
6225 if (traversed == rank) {
6226 return x;
6227 }
6228 }
6229 return NULL;
6230}
6231
fd8ccf44 6232/* The actual Z-commands implementations */
6233
7db723ad 6234/* This generic command implements both ZADD and ZINCRBY.
e2665397 6235 * scoreval is the score if the operation is a ZADD (doincrement == 0) or
7db723ad 6236 * the increment if the operation is a ZINCRBY (doincrement == 1). */
e2665397 6237static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, int doincrement) {
fd8ccf44 6238 robj *zsetobj;
6239 zset *zs;
6240 double *score;
6241
5fc9229c 6242 if (isnan(scoreval)) {
6243 addReplySds(c,sdsnew("-ERR provide score is Not A Number (nan)\r\n"));
6244 return;
6245 }
6246
e2665397 6247 zsetobj = lookupKeyWrite(c->db,key);
fd8ccf44 6248 if (zsetobj == NULL) {
6249 zsetobj = createZsetObject();
09241813 6250 dbAdd(c->db,key,zsetobj);
fd8ccf44 6251 } else {
6252 if (zsetobj->type != REDIS_ZSET) {
6253 addReply(c,shared.wrongtypeerr);
6254 return;
6255 }
6256 }
fd8ccf44 6257 zs = zsetobj->ptr;
e2665397 6258
7db723ad 6259 /* Ok now since we implement both ZADD and ZINCRBY here the code
e2665397 6260 * needs to handle the two different conditions. It's all about setting
6261 * '*score', that is, the new score to set, to the right value. */
6262 score = zmalloc(sizeof(double));
6263 if (doincrement) {
6264 dictEntry *de;
6265
6266 /* Read the old score. If the element was not present starts from 0 */
6267 de = dictFind(zs->dict,ele);
6268 if (de) {
6269 double *oldscore = dictGetEntryVal(de);
6270 *score = *oldscore + scoreval;
6271 } else {
6272 *score = scoreval;
6273 }
5fc9229c 6274 if (isnan(*score)) {
6275 addReplySds(c,
6276 sdsnew("-ERR resulting score is Not A Number (nan)\r\n"));
6277 zfree(score);
6278 /* Note that we don't need to check if the zset may be empty and
6279 * should be removed here, as we can only obtain Nan as score if
6280 * there was already an element in the sorted set. */
6281 return;
6282 }
e2665397 6283 } else {
6284 *score = scoreval;
6285 }
6286
6287 /* What follows is a simple remove and re-insert operation that is common
7db723ad 6288 * to both ZADD and ZINCRBY... */
e2665397 6289 if (dictAdd(zs->dict,ele,score) == DICT_OK) {
fd8ccf44 6290 /* case 1: New element */
e2665397 6291 incrRefCount(ele); /* added to hash */
6292 zslInsert(zs->zsl,*score,ele);
6293 incrRefCount(ele); /* added to skiplist */
fd8ccf44 6294 server.dirty++;
e2665397 6295 if (doincrement)
e2665397 6296 addReplyDouble(c,*score);
91d71bfc 6297 else
6298 addReply(c,shared.cone);
fd8ccf44 6299 } else {
6300 dictEntry *de;
6301 double *oldscore;
e0a62c7f 6302
fd8ccf44 6303 /* case 2: Score update operation */
e2665397 6304 de = dictFind(zs->dict,ele);
dfc5e96c 6305 redisAssert(de != NULL);
fd8ccf44 6306 oldscore = dictGetEntryVal(de);
6307 if (*score != *oldscore) {
6308 int deleted;
6309
e2665397 6310 /* Remove and insert the element in the skip list with new score */
6311 deleted = zslDelete(zs->zsl,*oldscore,ele);
dfc5e96c 6312 redisAssert(deleted != 0);
e2665397 6313 zslInsert(zs->zsl,*score,ele);
6314 incrRefCount(ele);
6315 /* Update the score in the hash table */
6316 dictReplace(zs->dict,ele,score);
fd8ccf44 6317 server.dirty++;
2161a965 6318 } else {
6319 zfree(score);
fd8ccf44 6320 }
e2665397 6321 if (doincrement)
6322 addReplyDouble(c,*score);
6323 else
6324 addReply(c,shared.czero);
fd8ccf44 6325 }
6326}
6327
e2665397 6328static void zaddCommand(redisClient *c) {
6329 double scoreval;
6330
bd79a6bd 6331 if (getDoubleFromObjectOrReply(c, c->argv[2], &scoreval, NULL) != REDIS_OK) return;
e2665397 6332 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,0);
6333}
6334
7db723ad 6335static void zincrbyCommand(redisClient *c) {
e2665397 6336 double scoreval;
6337
bd79a6bd 6338 if (getDoubleFromObjectOrReply(c, c->argv[2], &scoreval, NULL) != REDIS_OK) return;
e2665397 6339 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1);
6340}
6341
1b7106e7 6342static void zremCommand(redisClient *c) {
6343 robj *zsetobj;
6344 zset *zs;
dd88747b 6345 dictEntry *de;
6346 double *oldscore;
6347 int deleted;
1b7106e7 6348
dd88747b 6349 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
6350 checkType(c,zsetobj,REDIS_ZSET)) return;
1b7106e7 6351
dd88747b 6352 zs = zsetobj->ptr;
6353 de = dictFind(zs->dict,c->argv[2]);
6354 if (de == NULL) {
6355 addReply(c,shared.czero);
6356 return;
1b7106e7 6357 }
dd88747b 6358 /* Delete from the skiplist */
6359 oldscore = dictGetEntryVal(de);
6360 deleted = zslDelete(zs->zsl,*oldscore,c->argv[2]);
6361 redisAssert(deleted != 0);
6362
6363 /* Delete from the hash table */
6364 dictDelete(zs->dict,c->argv[2]);
6365 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
09241813 6366 if (dictSize(zs->dict) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 6367 server.dirty++;
6368 addReply(c,shared.cone);
1b7106e7 6369}
6370
1807985b 6371static void zremrangebyscoreCommand(redisClient *c) {
bbe025e0
AM
6372 double min;
6373 double max;
dd88747b 6374 long deleted;
1807985b 6375 robj *zsetobj;
6376 zset *zs;
6377
bd79a6bd
PN
6378 if ((getDoubleFromObjectOrReply(c, c->argv[2], &min, NULL) != REDIS_OK) ||
6379 (getDoubleFromObjectOrReply(c, c->argv[3], &max, NULL) != REDIS_OK)) return;
bbe025e0 6380
dd88747b 6381 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
6382 checkType(c,zsetobj,REDIS_ZSET)) return;
1807985b 6383
dd88747b 6384 zs = zsetobj->ptr;
6385 deleted = zslDeleteRangeByScore(zs->zsl,min,max,zs->dict);
6386 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
09241813 6387 if (dictSize(zs->dict) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 6388 server.dirty += deleted;
482b672d 6389 addReplyLongLong(c,deleted);
1807985b 6390}
6391
9212eafd 6392static void zremrangebyrankCommand(redisClient *c) {
bbe025e0
AM
6393 long start;
6394 long end;
dd88747b 6395 int llen;
6396 long deleted;
9212eafd
PN
6397 robj *zsetobj;
6398 zset *zs;
6399
bd79a6bd
PN
6400 if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
6401 (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
bbe025e0 6402
dd88747b 6403 if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
6404 checkType(c,zsetobj,REDIS_ZSET)) return;
6405 zs = zsetobj->ptr;
6406 llen = zs->zsl->length;
9212eafd 6407
dd88747b 6408 /* convert negative indexes */
6409 if (start < 0) start = llen+start;
6410 if (end < 0) end = llen+end;
6411 if (start < 0) start = 0;
9212eafd 6412
4774a53b
PN
6413 /* Invariant: start >= 0, so this test will be true when end < 0.
6414 * The range is empty when start > end or start >= length. */
dd88747b 6415 if (start > end || start >= llen) {
6416 addReply(c,shared.czero);
6417 return;
9212eafd 6418 }
dd88747b 6419 if (end >= llen) end = llen-1;
6420
6421 /* increment start and end because zsl*Rank functions
6422 * use 1-based rank */
6423 deleted = zslDeleteRangeByRank(zs->zsl,start+1,end+1,zs->dict);
6424 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
09241813 6425 if (dictSize(zs->dict) == 0) dbDelete(c->db,c->argv[1]);
dd88747b 6426 server.dirty += deleted;
482b672d 6427 addReplyLongLong(c, deleted);
9212eafd
PN
6428}
6429
8f92e768
PN
6430typedef struct {
6431 dict *dict;
6432 double weight;
6433} zsetopsrc;
6434
6435static int qsortCompareZsetopsrcByCardinality(const void *s1, const void *s2) {
6436 zsetopsrc *d1 = (void*) s1, *d2 = (void*) s2;
6437 unsigned long size1, size2;
6438 size1 = d1->dict ? dictSize(d1->dict) : 0;
6439 size2 = d2->dict ? dictSize(d2->dict) : 0;
6440 return size1 - size2;
6441}
6442
d2764cd6
PN
6443#define REDIS_AGGR_SUM 1
6444#define REDIS_AGGR_MIN 2
6445#define REDIS_AGGR_MAX 3
bc000c1d 6446#define zunionInterDictValue(_e) (dictGetEntryVal(_e) == NULL ? 1.0 : *(double*)dictGetEntryVal(_e))
d2764cd6
PN
6447
6448inline static void zunionInterAggregate(double *target, double val, int aggregate) {
6449 if (aggregate == REDIS_AGGR_SUM) {
6450 *target = *target + val;
6451 } else if (aggregate == REDIS_AGGR_MIN) {
6452 *target = val < *target ? val : *target;
6453 } else if (aggregate == REDIS_AGGR_MAX) {
6454 *target = val > *target ? val : *target;
6455 } else {
6456 /* safety net */
f83c6cb5 6457 redisPanic("Unknown ZUNION/INTER aggregate type");
d2764cd6
PN
6458 }
6459}
6460
2830ca53 6461static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
bc000c1d 6462 int i, j, setnum;
d2764cd6 6463 int aggregate = REDIS_AGGR_SUM;
8f92e768 6464 zsetopsrc *src;
2830ca53
PN
6465 robj *dstobj;
6466 zset *dstzset;
b287c9bb
PN
6467 dictIterator *di;
6468 dictEntry *de;
6469
bc000c1d
JC
6470 /* expect setnum input keys to be given */
6471 setnum = atoi(c->argv[2]->ptr);
6472 if (setnum < 1) {
5d373da9 6473 addReplySds(c,sdsnew("-ERR at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE\r\n"));
2830ca53 6474 return;
b287c9bb 6475 }
2830ca53
PN
6476
6477 /* test if the expected number of keys would overflow */
bc000c1d 6478 if (3+setnum > c->argc) {
b287c9bb
PN
6479 addReply(c,shared.syntaxerr);
6480 return;
6481 }
6482
2830ca53 6483 /* read keys to be used for input */
bc000c1d
JC
6484 src = zmalloc(sizeof(zsetopsrc) * setnum);
6485 for (i = 0, j = 3; i < setnum; i++, j++) {
6486 robj *obj = lookupKeyWrite(c->db,c->argv[j]);
6487 if (!obj) {
8f92e768 6488 src[i].dict = NULL;
b287c9bb 6489 } else {
bc000c1d
JC
6490 if (obj->type == REDIS_ZSET) {
6491 src[i].dict = ((zset*)obj->ptr)->dict;
6492 } else if (obj->type == REDIS_SET) {
6493 src[i].dict = (obj->ptr);
6494 } else {
8f92e768 6495 zfree(src);
b287c9bb
PN
6496 addReply(c,shared.wrongtypeerr);
6497 return;
6498 }
b287c9bb 6499 }
2830ca53
PN
6500
6501 /* default all weights to 1 */
8f92e768 6502 src[i].weight = 1.0;
b287c9bb
PN
6503 }
6504
2830ca53
PN
6505 /* parse optional extra arguments */
6506 if (j < c->argc) {
d2764cd6 6507 int remaining = c->argc - j;
b287c9bb 6508
2830ca53 6509 while (remaining) {
bc000c1d 6510 if (remaining >= (setnum + 1) && !strcasecmp(c->argv[j]->ptr,"weights")) {
2830ca53 6511 j++; remaining--;
bc000c1d 6512 for (i = 0; i < setnum; i++, j++, remaining--) {
bd79a6bd 6513 if (getDoubleFromObjectOrReply(c, c->argv[j], &src[i].weight, NULL) != REDIS_OK)
bbe025e0 6514 return;
2830ca53 6515 }
d2764cd6
PN
6516 } else if (remaining >= 2 && !strcasecmp(c->argv[j]->ptr,"aggregate")) {
6517 j++; remaining--;
6518 if (!strcasecmp(c->argv[j]->ptr,"sum")) {
6519 aggregate = REDIS_AGGR_SUM;
6520 } else if (!strcasecmp(c->argv[j]->ptr,"min")) {
6521 aggregate = REDIS_AGGR_MIN;
6522 } else if (!strcasecmp(c->argv[j]->ptr,"max")) {
6523 aggregate = REDIS_AGGR_MAX;
6524 } else {
6525 zfree(src);
6526 addReply(c,shared.syntaxerr);
6527 return;
6528 }
6529 j++; remaining--;
2830ca53 6530 } else {
8f92e768 6531 zfree(src);
2830ca53
PN
6532 addReply(c,shared.syntaxerr);
6533 return;
6534 }
6535 }
6536 }
b287c9bb 6537
d2764cd6
PN
6538 /* sort sets from the smallest to largest, this will improve our
6539 * algorithm's performance */
bc000c1d 6540 qsort(src,setnum,sizeof(zsetopsrc),qsortCompareZsetopsrcByCardinality);
d2764cd6 6541
2830ca53
PN
6542 dstobj = createZsetObject();
6543 dstzset = dstobj->ptr;
6544
6545 if (op == REDIS_OP_INTER) {
8f92e768
PN
6546 /* skip going over all entries if the smallest zset is NULL or empty */
6547 if (src[0].dict && dictSize(src[0].dict) > 0) {
6548 /* precondition: as src[0].dict is non-empty and the zsets are ordered
6549 * from small to large, all src[i > 0].dict are non-empty too */
6550 di = dictGetIterator(src[0].dict);
2830ca53 6551 while((de = dictNext(di)) != NULL) {
d2764cd6 6552 double *score = zmalloc(sizeof(double)), value;
bc000c1d 6553 *score = src[0].weight * zunionInterDictValue(de);
2830ca53 6554
bc000c1d 6555 for (j = 1; j < setnum; j++) {
d2764cd6 6556 dictEntry *other = dictFind(src[j].dict,dictGetEntryKey(de));
2830ca53 6557 if (other) {
bc000c1d 6558 value = src[j].weight * zunionInterDictValue(other);
d2764cd6 6559 zunionInterAggregate(score, value, aggregate);
2830ca53
PN
6560 } else {
6561 break;
6562 }
6563 }
b287c9bb 6564
2830ca53 6565 /* skip entry when not present in every source dict */
bc000c1d 6566 if (j != setnum) {
2830ca53
PN
6567 zfree(score);
6568 } else {
6569 robj *o = dictGetEntryKey(de);
6570 dictAdd(dstzset->dict,o,score);
6571 incrRefCount(o); /* added to dictionary */
6572 zslInsert(dstzset->zsl,*score,o);
6573 incrRefCount(o); /* added to skiplist */
b287c9bb
PN
6574 }
6575 }
2830ca53
PN
6576 dictReleaseIterator(di);
6577 }
6578 } else if (op == REDIS_OP_UNION) {
bc000c1d 6579 for (i = 0; i < setnum; i++) {
8f92e768 6580 if (!src[i].dict) continue;
2830ca53 6581
8f92e768 6582 di = dictGetIterator(src[i].dict);
2830ca53
PN
6583 while((de = dictNext(di)) != NULL) {
6584 /* skip key when already processed */
6585 if (dictFind(dstzset->dict,dictGetEntryKey(de)) != NULL) continue;
6586
d2764cd6 6587 double *score = zmalloc(sizeof(double)), value;
bc000c1d 6588 *score = src[i].weight * zunionInterDictValue(de);
2830ca53 6589
d2764cd6
PN
6590 /* because the zsets are sorted by size, its only possible
6591 * for sets at larger indices to hold this entry */
bc000c1d 6592 for (j = (i+1); j < setnum; j++) {
d2764cd6 6593 dictEntry *other = dictFind(src[j].dict,dictGetEntryKey(de));
2830ca53 6594 if (other) {
bc000c1d 6595 value = src[j].weight * zunionInterDictValue(other);
d2764cd6 6596 zunionInterAggregate(score, value, aggregate);
2830ca53
PN
6597 }
6598 }
b287c9bb 6599
2830ca53
PN
6600 robj *o = dictGetEntryKey(de);
6601 dictAdd(dstzset->dict,o,score);
6602 incrRefCount(o); /* added to dictionary */
6603 zslInsert(dstzset->zsl,*score,o);
6604 incrRefCount(o); /* added to skiplist */
6605 }
6606 dictReleaseIterator(di);
b287c9bb 6607 }
2830ca53
PN
6608 } else {
6609 /* unknown operator */
6610 redisAssert(op == REDIS_OP_INTER || op == REDIS_OP_UNION);
b287c9bb
PN
6611 }
6612
09241813 6613 dbDelete(c->db,dstkey);
3ea27d37 6614 if (dstzset->zsl->length) {
09241813 6615 dbAdd(c->db,dstkey,dstobj);
482b672d 6616 addReplyLongLong(c, dstzset->zsl->length);
3ea27d37 6617 server.dirty++;
6618 } else {
8bca8773 6619 decrRefCount(dstobj);
3ea27d37 6620 addReply(c, shared.czero);
6621 }
8f92e768 6622 zfree(src);
b287c9bb
PN
6623}
6624
5d373da9 6625static void zunionstoreCommand(redisClient *c) {
2830ca53 6626 zunionInterGenericCommand(c,c->argv[1], REDIS_OP_UNION);
b287c9bb
PN
6627}
6628
5d373da9 6629static void zinterstoreCommand(redisClient *c) {
2830ca53 6630 zunionInterGenericCommand(c,c->argv[1], REDIS_OP_INTER);
b287c9bb
PN
6631}
6632
e3870fab 6633static void zrangeGenericCommand(redisClient *c, int reverse) {
cc812361 6634 robj *o;
bbe025e0
AM
6635 long start;
6636 long end;
752da584 6637 int withscores = 0;
dd88747b 6638 int llen;
6639 int rangelen, j;
6640 zset *zsetobj;
6641 zskiplist *zsl;
6642 zskiplistNode *ln;
6643 robj *ele;
752da584 6644
bd79a6bd
PN
6645 if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
6646 (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
bbe025e0 6647
752da584 6648 if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) {
6649 withscores = 1;
6650 } else if (c->argc >= 5) {
6651 addReply(c,shared.syntaxerr);
6652 return;
6653 }
cc812361 6654
4e27f268 6655 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
6656 || checkType(c,o,REDIS_ZSET)) return;
dd88747b 6657 zsetobj = o->ptr;
6658 zsl = zsetobj->zsl;
6659 llen = zsl->length;
cc812361 6660
dd88747b 6661 /* convert negative indexes */
6662 if (start < 0) start = llen+start;
6663 if (end < 0) end = llen+end;
6664 if (start < 0) start = 0;
cc812361 6665
184d74ab
PN
6666 /* Invariant: start >= 0, so this test will be true when end < 0.
6667 * The range is empty when start > end or start >= length. */
dd88747b 6668 if (start > end || start >= llen) {
dd88747b 6669 addReply(c,shared.emptymultibulk);
6670 return;
6671 }
6672 if (end >= llen) end = llen-1;
6673 rangelen = (end-start)+1;
cc812361 6674
dd88747b 6675 /* check if starting point is trivial, before searching
6676 * the element in log(N) time */
6677 if (reverse) {
003f0840 6678 ln = start == 0 ? zsl->tail : zslistTypeGetElementByRank(zsl, llen-start);
dd88747b 6679 } else {
6680 ln = start == 0 ?
003f0840 6681 zsl->header->forward[0] : zslistTypeGetElementByRank(zsl, start+1);
dd88747b 6682 }
cc812361 6683
dd88747b 6684 /* Return the result in form of a multi-bulk reply */
6685 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",
6686 withscores ? (rangelen*2) : rangelen));
6687 for (j = 0; j < rangelen; j++) {
6688 ele = ln->obj;
6689 addReplyBulk(c,ele);
6690 if (withscores)
6691 addReplyDouble(c,ln->score);
6692 ln = reverse ? ln->backward : ln->forward[0];
cc812361 6693 }
6694}
6695
e3870fab 6696static void zrangeCommand(redisClient *c) {
6697 zrangeGenericCommand(c,0);
6698}
6699
6700static void zrevrangeCommand(redisClient *c) {
6701 zrangeGenericCommand(c,1);
6702}
6703
f44dd428 6704/* This command implements both ZRANGEBYSCORE and ZCOUNT.
6705 * If justcount is non-zero, just the count is returned. */
6706static void genericZrangebyscoreCommand(redisClient *c, int justcount) {
50c55df5 6707 robj *o;
f44dd428 6708 double min, max;
6709 int minex = 0, maxex = 0; /* are min or max exclusive? */
80181f78 6710 int offset = 0, limit = -1;
0500ef27
SH
6711 int withscores = 0;
6712 int badsyntax = 0;
6713
f44dd428 6714 /* Parse the min-max interval. If one of the values is prefixed
6715 * by the "(" character, it's considered "open". For instance
6716 * ZRANGEBYSCORE zset (1.5 (2.5 will match min < x < max
6717 * ZRANGEBYSCORE zset 1.5 2.5 will instead match min <= x <= max */
6718 if (((char*)c->argv[2]->ptr)[0] == '(') {
6719 min = strtod((char*)c->argv[2]->ptr+1,NULL);
6720 minex = 1;
6721 } else {
6722 min = strtod(c->argv[2]->ptr,NULL);
6723 }
6724 if (((char*)c->argv[3]->ptr)[0] == '(') {
6725 max = strtod((char*)c->argv[3]->ptr+1,NULL);
6726 maxex = 1;
6727 } else {
6728 max = strtod(c->argv[3]->ptr,NULL);
6729 }
6730
6731 /* Parse "WITHSCORES": note that if the command was called with
6732 * the name ZCOUNT then we are sure that c->argc == 4, so we'll never
6733 * enter the following paths to parse WITHSCORES and LIMIT. */
0500ef27 6734 if (c->argc == 5 || c->argc == 8) {
3a3978b1 6735 if (strcasecmp(c->argv[c->argc-1]->ptr,"withscores") == 0)
6736 withscores = 1;
6737 else
6738 badsyntax = 1;
0500ef27 6739 }
3a3978b1 6740 if (c->argc != (4 + withscores) && c->argc != (7 + withscores))
0500ef27 6741 badsyntax = 1;
0500ef27 6742 if (badsyntax) {
454d4e43 6743 addReplySds(c,
6744 sdsnew("-ERR wrong number of arguments for ZRANGEBYSCORE\r\n"));
80181f78 6745 return;
0500ef27
SH
6746 }
6747
f44dd428 6748 /* Parse "LIMIT" */
0500ef27 6749 if (c->argc == (7 + withscores) && strcasecmp(c->argv[4]->ptr,"limit")) {
80181f78 6750 addReply(c,shared.syntaxerr);
6751 return;
0500ef27 6752 } else if (c->argc == (7 + withscores)) {
80181f78 6753 offset = atoi(c->argv[5]->ptr);
6754 limit = atoi(c->argv[6]->ptr);
0b13687c 6755 if (offset < 0) offset = 0;
80181f78 6756 }
50c55df5 6757
f44dd428 6758 /* Ok, lookup the key and get the range */
50c55df5 6759 o = lookupKeyRead(c->db,c->argv[1]);
6760 if (o == NULL) {
4e27f268 6761 addReply(c,justcount ? shared.czero : shared.emptymultibulk);
50c55df5 6762 } else {
6763 if (o->type != REDIS_ZSET) {
6764 addReply(c,shared.wrongtypeerr);
6765 } else {
6766 zset *zsetobj = o->ptr;
6767 zskiplist *zsl = zsetobj->zsl;
6768 zskiplistNode *ln;
f44dd428 6769 robj *ele, *lenobj = NULL;
6770 unsigned long rangelen = 0;
50c55df5 6771
f44dd428 6772 /* Get the first node with the score >= min, or with
6773 * score > min if 'minex' is true. */
50c55df5 6774 ln = zslFirstWithScore(zsl,min);
f44dd428 6775 while (minex && ln && ln->score == min) ln = ln->forward[0];
6776
50c55df5 6777 if (ln == NULL) {
6778 /* No element matching the speciifed interval */
f44dd428 6779 addReply(c,justcount ? shared.czero : shared.emptymultibulk);
50c55df5 6780 return;
6781 }
6782
6783 /* We don't know in advance how many matching elements there
6784 * are in the list, so we push this object that will represent
6785 * the multi-bulk length in the output buffer, and will "fix"
6786 * it later */
f44dd428 6787 if (!justcount) {
6788 lenobj = createObject(REDIS_STRING,NULL);
6789 addReply(c,lenobj);
6790 decrRefCount(lenobj);
6791 }
50c55df5 6792
f44dd428 6793 while(ln && (maxex ? (ln->score < max) : (ln->score <= max))) {
80181f78 6794 if (offset) {
6795 offset--;
6796 ln = ln->forward[0];
6797 continue;
6798 }
6799 if (limit == 0) break;
f44dd428 6800 if (!justcount) {
6801 ele = ln->obj;
dd88747b 6802 addReplyBulk(c,ele);
f44dd428 6803 if (withscores)
6804 addReplyDouble(c,ln->score);
6805 }
50c55df5 6806 ln = ln->forward[0];
6807 rangelen++;
80181f78 6808 if (limit > 0) limit--;
50c55df5 6809 }
f44dd428 6810 if (justcount) {
482b672d 6811 addReplyLongLong(c,(long)rangelen);
f44dd428 6812 } else {
6813 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",
6814 withscores ? (rangelen*2) : rangelen);
6815 }
50c55df5 6816 }
6817 }
6818}
6819
f44dd428 6820static void zrangebyscoreCommand(redisClient *c) {
6821 genericZrangebyscoreCommand(c,0);
6822}
6823
6824static void zcountCommand(redisClient *c) {
6825 genericZrangebyscoreCommand(c,1);
6826}
6827
3c41331e 6828static void zcardCommand(redisClient *c) {
e197b441 6829 robj *o;
6830 zset *zs;
dd88747b 6831
6832 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
6833 checkType(c,o,REDIS_ZSET)) return;
6834
6835 zs = o->ptr;
6836 addReplyUlong(c,zs->zsl->length);
e197b441 6837}
6838
6e333bbe 6839static void zscoreCommand(redisClient *c) {
6840 robj *o;
6841 zset *zs;
dd88747b 6842 dictEntry *de;
6843
6844 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
6845 checkType(c,o,REDIS_ZSET)) return;
6846
6847 zs = o->ptr;
6848 de = dictFind(zs->dict,c->argv[2]);
6849 if (!de) {
96d8b4ee 6850 addReply(c,shared.nullbulk);
6e333bbe 6851 } else {
dd88747b 6852 double *score = dictGetEntryVal(de);
6e333bbe 6853
dd88747b 6854 addReplyDouble(c,*score);
6e333bbe 6855 }
6856}
6857
798d9e55 6858static void zrankGenericCommand(redisClient *c, int reverse) {
69d95c3e 6859 robj *o;
dd88747b 6860 zset *zs;
6861 zskiplist *zsl;
6862 dictEntry *de;
6863 unsigned long rank;
6864 double *score;
6865
6866 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
6867 checkType(c,o,REDIS_ZSET)) return;
6868
6869 zs = o->ptr;
6870 zsl = zs->zsl;
6871 de = dictFind(zs->dict,c->argv[2]);
6872 if (!de) {
69d95c3e
PN
6873 addReply(c,shared.nullbulk);
6874 return;
6875 }
69d95c3e 6876
dd88747b 6877 score = dictGetEntryVal(de);
003f0840 6878 rank = zslistTypeGetRank(zsl, *score, c->argv[2]);
dd88747b 6879 if (rank) {
6880 if (reverse) {
482b672d 6881 addReplyLongLong(c, zsl->length - rank);
27b0ccca 6882 } else {
482b672d 6883 addReplyLongLong(c, rank-1);
69d95c3e 6884 }
dd88747b 6885 } else {
6886 addReply(c,shared.nullbulk);
978c2c94 6887 }
6888}
6889
798d9e55
PN
6890static void zrankCommand(redisClient *c) {
6891 zrankGenericCommand(c, 0);
6892}
6893
6894static void zrevrankCommand(redisClient *c) {
6895 zrankGenericCommand(c, 1);
6896}
6897
7fb16bac
PN
6898/* ========================= Hashes utility functions ======================= */
6899#define REDIS_HASH_KEY 1
6900#define REDIS_HASH_VALUE 2
978c2c94 6901
7fb16bac
PN
6902/* Check the length of a number of objects to see if we need to convert a
6903 * zipmap to a real hash. Note that we only check string encoded objects
6904 * as their string length can be queried in constant time. */
d1578a33 6905static void hashTypeTryConversion(robj *subject, robj **argv, int start, int end) {
7fb16bac
PN
6906 int i;
6907 if (subject->encoding != REDIS_ENCODING_ZIPMAP) return;
978c2c94 6908
7fb16bac
PN
6909 for (i = start; i <= end; i++) {
6910 if (argv[i]->encoding == REDIS_ENCODING_RAW &&
6911 sdslen(argv[i]->ptr) > server.hash_max_zipmap_value)
6912 {
6913 convertToRealHash(subject);
978c2c94 6914 return;
6915 }
6916 }
7fb16bac 6917}
bae2c7ec 6918
97224de7 6919/* Encode given objects in-place when the hash uses a dict. */
d1578a33 6920static void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2) {
97224de7 6921 if (subject->encoding == REDIS_ENCODING_HT) {
3f973463
PN
6922 if (o1) *o1 = tryObjectEncoding(*o1);
6923 if (o2) *o2 = tryObjectEncoding(*o2);
97224de7
PN
6924 }
6925}
6926
7fb16bac 6927/* Get the value from a hash identified by key. Returns either a string
a3f3af86
PN
6928 * object or NULL if the value cannot be found. The refcount of the object
6929 * is always increased by 1 when the value was found. */
d1578a33 6930static robj *hashTypeGet(robj *o, robj *key) {
7fb16bac 6931 robj *value = NULL;
978c2c94 6932 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
7fb16bac
PN
6933 unsigned char *v;
6934 unsigned int vlen;
6935 key = getDecodedObject(key);
6936 if (zipmapGet(o->ptr,key->ptr,sdslen(key->ptr),&v,&vlen)) {
6937 value = createStringObject((char*)v,vlen);
6938 }
6939 decrRefCount(key);
6940 } else {
6941 dictEntry *de = dictFind(o->ptr,key);
6942 if (de != NULL) {
6943 value = dictGetEntryVal(de);
a3f3af86 6944 incrRefCount(value);
7fb16bac
PN
6945 }
6946 }
6947 return value;
6948}
978c2c94 6949
7fb16bac
PN
6950/* Test if the key exists in the given hash. Returns 1 if the key
6951 * exists and 0 when it doesn't. */
d1578a33 6952static int hashTypeExists(robj *o, robj *key) {
7fb16bac
PN
6953 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
6954 key = getDecodedObject(key);
6955 if (zipmapExists(o->ptr,key->ptr,sdslen(key->ptr))) {
6956 decrRefCount(key);
6957 return 1;
6958 }
6959 decrRefCount(key);
6960 } else {
6961 if (dictFind(o->ptr,key) != NULL) {
6962 return 1;
6963 }
6964 }
6965 return 0;
6966}
bae2c7ec 6967
7fb16bac
PN
6968/* Add an element, discard the old if the key already exists.
6969 * Return 0 on insert and 1 on update. */
d1578a33 6970static int hashTypeSet(robj *o, robj *key, robj *value) {
7fb16bac
PN
6971 int update = 0;
6972 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
6973 key = getDecodedObject(key);
6974 value = getDecodedObject(value);
6975 o->ptr = zipmapSet(o->ptr,
6976 key->ptr,sdslen(key->ptr),
6977 value->ptr,sdslen(value->ptr), &update);
6978 decrRefCount(key);
6979 decrRefCount(value);
6980
6981 /* Check if the zipmap needs to be upgraded to a real hash table */
6982 if (zipmapLen(o->ptr) > server.hash_max_zipmap_entries)
bae2c7ec 6983 convertToRealHash(o);
978c2c94 6984 } else {
7fb16bac
PN
6985 if (dictReplace(o->ptr,key,value)) {
6986 /* Insert */
6987 incrRefCount(key);
978c2c94 6988 } else {
7fb16bac 6989 /* Update */
978c2c94 6990 update = 1;
6991 }
7fb16bac 6992 incrRefCount(value);
978c2c94 6993 }
7fb16bac 6994 return update;
978c2c94 6995}
6996
7fb16bac
PN
6997/* Delete an element from a hash.
6998 * Return 1 on deleted and 0 on not found. */
d1578a33 6999static int hashTypeDelete(robj *o, robj *key) {
7fb16bac
PN
7000 int deleted = 0;
7001 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
7002 key = getDecodedObject(key);
7003 o->ptr = zipmapDel(o->ptr,key->ptr,sdslen(key->ptr), &deleted);
7004 decrRefCount(key);
7005 } else {
7006 deleted = dictDelete((dict*)o->ptr,key) == DICT_OK;
7007 /* Always check if the dictionary needs a resize after a delete. */
7008 if (deleted && htNeedsResize(o->ptr)) dictResize(o->ptr);
d33278d1 7009 }
7fb16bac
PN
7010 return deleted;
7011}
d33278d1 7012
7fb16bac 7013/* Return the number of elements in a hash. */
d1578a33 7014static unsigned long hashTypeLength(robj *o) {
7fb16bac
PN
7015 return (o->encoding == REDIS_ENCODING_ZIPMAP) ?
7016 zipmapLen((unsigned char*)o->ptr) : dictSize((dict*)o->ptr);
7017}
7018
7019/* Structure to hold hash iteration abstration. Note that iteration over
7020 * hashes involves both fields and values. Because it is possible that
7021 * not both are required, store pointers in the iterator to avoid
7022 * unnecessary memory allocation for fields/values. */
7023typedef struct {
7024 int encoding;
7025 unsigned char *zi;
7026 unsigned char *zk, *zv;
7027 unsigned int zklen, zvlen;
7028
7029 dictIterator *di;
7030 dictEntry *de;
d1578a33 7031} hashTypeIterator;
7fb16bac 7032
d1578a33
PN
7033static hashTypeIterator *hashTypeInitIterator(robj *subject) {
7034 hashTypeIterator *hi = zmalloc(sizeof(hashTypeIterator));
7fb16bac
PN
7035 hi->encoding = subject->encoding;
7036 if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
7037 hi->zi = zipmapRewind(subject->ptr);
7038 } else if (hi->encoding == REDIS_ENCODING_HT) {
7039 hi->di = dictGetIterator(subject->ptr);
d33278d1 7040 } else {
7fb16bac 7041 redisAssert(NULL);
d33278d1 7042 }
c44d3b56 7043 return hi;
7fb16bac 7044}
d33278d1 7045
d1578a33 7046static void hashTypeReleaseIterator(hashTypeIterator *hi) {
7fb16bac
PN
7047 if (hi->encoding == REDIS_ENCODING_HT) {
7048 dictReleaseIterator(hi->di);
d33278d1 7049 }
c44d3b56 7050 zfree(hi);
7fb16bac 7051}
d33278d1 7052
7fb16bac
PN
7053/* Move to the next entry in the hash. Return REDIS_OK when the next entry
7054 * could be found and REDIS_ERR when the iterator reaches the end. */
d1578a33 7055static int hashTypeNext(hashTypeIterator *hi) {
7fb16bac
PN
7056 if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
7057 if ((hi->zi = zipmapNext(hi->zi, &hi->zk, &hi->zklen,
7058 &hi->zv, &hi->zvlen)) == NULL) return REDIS_ERR;
7059 } else {
7060 if ((hi->de = dictNext(hi->di)) == NULL) return REDIS_ERR;
7061 }
7062 return REDIS_OK;
7063}
d33278d1 7064
0c390abc 7065/* Get key or value object at current iteration position.
a3f3af86 7066 * This increases the refcount of the field object by 1. */
d1578a33 7067static robj *hashTypeCurrent(hashTypeIterator *hi, int what) {
7fb16bac
PN
7068 robj *o;
7069 if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
7070 if (what & REDIS_HASH_KEY) {
7071 o = createStringObject((char*)hi->zk,hi->zklen);
7072 } else {
7073 o = createStringObject((char*)hi->zv,hi->zvlen);
d33278d1 7074 }
d33278d1 7075 } else {
7fb16bac
PN
7076 if (what & REDIS_HASH_KEY) {
7077 o = dictGetEntryKey(hi->de);
7078 } else {
7079 o = dictGetEntryVal(hi->de);
d33278d1 7080 }
a3f3af86 7081 incrRefCount(o);
d33278d1 7082 }
7fb16bac 7083 return o;
d33278d1
PN
7084}
7085
d1578a33 7086static robj *hashTypeLookupWriteOrCreate(redisClient *c, robj *key) {
7fb16bac 7087 robj *o = lookupKeyWrite(c->db,key);
01426b05
PN
7088 if (o == NULL) {
7089 o = createHashObject();
09241813 7090 dbAdd(c->db,key,o);
01426b05
PN
7091 } else {
7092 if (o->type != REDIS_HASH) {
7093 addReply(c,shared.wrongtypeerr);
7fb16bac 7094 return NULL;
01426b05
PN
7095 }
7096 }
7fb16bac
PN
7097 return o;
7098}
01426b05 7099
7fb16bac
PN
7100/* ============================= Hash commands ============================== */
7101static void hsetCommand(redisClient *c) {
6e9e463f 7102 int update;
7fb16bac 7103 robj *o;
bbe025e0 7104
d1578a33
PN
7105 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7106 hashTypeTryConversion(o,c->argv,2,3);
7107 hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);
7108 update = hashTypeSet(o,c->argv[2],c->argv[3]);
6e9e463f 7109 addReply(c, update ? shared.czero : shared.cone);
7fb16bac
PN
7110 server.dirty++;
7111}
01426b05 7112
1f1c7695
PN
7113static void hsetnxCommand(redisClient *c) {
7114 robj *o;
d1578a33
PN
7115 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7116 hashTypeTryConversion(o,c->argv,2,3);
1f1c7695 7117
d1578a33 7118 if (hashTypeExists(o, c->argv[2])) {
1f1c7695 7119 addReply(c, shared.czero);
01426b05 7120 } else {
d1578a33
PN
7121 hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);
7122 hashTypeSet(o,c->argv[2],c->argv[3]);
1f1c7695
PN
7123 addReply(c, shared.cone);
7124 server.dirty++;
7125 }
7126}
01426b05 7127
7fb16bac
PN
7128static void hmsetCommand(redisClient *c) {
7129 int i;
7130 robj *o;
01426b05 7131
7fb16bac
PN
7132 if ((c->argc % 2) == 1) {
7133 addReplySds(c,sdsnew("-ERR wrong number of arguments for HMSET\r\n"));
7134 return;
7135 }
01426b05 7136
d1578a33
PN
7137 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7138 hashTypeTryConversion(o,c->argv,2,c->argc-1);
7fb16bac 7139 for (i = 2; i < c->argc; i += 2) {
d1578a33
PN
7140 hashTypeTryObjectEncoding(o,&c->argv[i], &c->argv[i+1]);
7141 hashTypeSet(o,c->argv[i],c->argv[i+1]);
7fb16bac
PN
7142 }
7143 addReply(c, shared.ok);
edc2f63a 7144 server.dirty++;
7fb16bac
PN
7145}
7146
7147static void hincrbyCommand(redisClient *c) {
7148 long long value, incr;
7149 robj *o, *current, *new;
7150
bd79a6bd 7151 if (getLongLongFromObjectOrReply(c,c->argv[3],&incr,NULL) != REDIS_OK) return;
d1578a33
PN
7152 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
7153 if ((current = hashTypeGet(o,c->argv[2])) != NULL) {
946342c1
PN
7154 if (getLongLongFromObjectOrReply(c,current,&value,
7155 "hash value is not an integer") != REDIS_OK) {
7156 decrRefCount(current);
7157 return;
7158 }
a3f3af86 7159 decrRefCount(current);
7fb16bac
PN
7160 } else {
7161 value = 0;
01426b05
PN
7162 }
7163
7fb16bac 7164 value += incr;
3f973463 7165 new = createStringObjectFromLongLong(value);
d1578a33
PN
7166 hashTypeTryObjectEncoding(o,&c->argv[2],NULL);
7167 hashTypeSet(o,c->argv[2],new);
7fb16bac
PN
7168 decrRefCount(new);
7169 addReplyLongLong(c,value);
01426b05 7170 server.dirty++;
01426b05
PN
7171}
7172
978c2c94 7173static void hgetCommand(redisClient *c) {
7fb16bac 7174 robj *o, *value;
dd88747b 7175 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
7176 checkType(c,o,REDIS_HASH)) return;
7177
d1578a33 7178 if ((value = hashTypeGet(o,c->argv[2])) != NULL) {
7fb16bac 7179 addReplyBulk(c,value);
a3f3af86 7180 decrRefCount(value);
dd88747b 7181 } else {
7fb16bac 7182 addReply(c,shared.nullbulk);
69d95c3e 7183 }
69d95c3e
PN
7184}
7185
09aeb579
PN
7186static void hmgetCommand(redisClient *c) {
7187 int i;
7fb16bac
PN
7188 robj *o, *value;
7189 o = lookupKeyRead(c->db,c->argv[1]);
7190 if (o != NULL && o->type != REDIS_HASH) {
7191 addReply(c,shared.wrongtypeerr);
09aeb579
PN
7192 }
7193
7fb16bac
PN
7194 /* Note the check for o != NULL happens inside the loop. This is
7195 * done because objects that cannot be found are considered to be
7196 * an empty hash. The reply should then be a series of NULLs. */
09aeb579 7197 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-2));
7fb16bac 7198 for (i = 2; i < c->argc; i++) {
d1578a33 7199 if (o != NULL && (value = hashTypeGet(o,c->argv[i])) != NULL) {
7fb16bac 7200 addReplyBulk(c,value);
a3f3af86 7201 decrRefCount(value);
7fb16bac
PN
7202 } else {
7203 addReply(c,shared.nullbulk);
09aeb579
PN
7204 }
7205 }
7206}
7207
07efaf74 7208static void hdelCommand(redisClient *c) {
dd88747b 7209 robj *o;
dd88747b 7210 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
7211 checkType(c,o,REDIS_HASH)) return;
07efaf74 7212
d1578a33
PN
7213 if (hashTypeDelete(o,c->argv[2])) {
7214 if (hashTypeLength(o) == 0) dbDelete(c->db,c->argv[1]);
7fb16bac
PN
7215 addReply(c,shared.cone);
7216 server.dirty++;
dd88747b 7217 } else {
7fb16bac 7218 addReply(c,shared.czero);
07efaf74 7219 }
7220}
7221
92b27fe9 7222static void hlenCommand(redisClient *c) {
7223 robj *o;
dd88747b 7224 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
92b27fe9 7225 checkType(c,o,REDIS_HASH)) return;
7226
d1578a33 7227 addReplyUlong(c,hashTypeLength(o));
92b27fe9 7228}
7229
78409a0f 7230static void genericHgetallCommand(redisClient *c, int flags) {
7fb16bac 7231 robj *o, *lenobj, *obj;
78409a0f 7232 unsigned long count = 0;
d1578a33 7233 hashTypeIterator *hi;
78409a0f 7234
4e27f268 7235 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
78409a0f 7236 || checkType(c,o,REDIS_HASH)) return;
7237
7238 lenobj = createObject(REDIS_STRING,NULL);
7239 addReply(c,lenobj);
7240 decrRefCount(lenobj);
7241
d1578a33
PN
7242 hi = hashTypeInitIterator(o);
7243 while (hashTypeNext(hi) != REDIS_ERR) {
7fb16bac 7244 if (flags & REDIS_HASH_KEY) {
d1578a33 7245 obj = hashTypeCurrent(hi,REDIS_HASH_KEY);
7fb16bac 7246 addReplyBulk(c,obj);
a3f3af86 7247 decrRefCount(obj);
7fb16bac 7248 count++;
78409a0f 7249 }
7fb16bac 7250 if (flags & REDIS_HASH_VALUE) {
d1578a33 7251 obj = hashTypeCurrent(hi,REDIS_HASH_VALUE);
7fb16bac 7252 addReplyBulk(c,obj);
a3f3af86 7253 decrRefCount(obj);
7fb16bac 7254 count++;
78409a0f 7255 }
78409a0f 7256 }
d1578a33 7257 hashTypeReleaseIterator(hi);
7fb16bac 7258
78409a0f 7259 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",count);
7260}
7261
7262static void hkeysCommand(redisClient *c) {
7fb16bac 7263 genericHgetallCommand(c,REDIS_HASH_KEY);
78409a0f 7264}
7265
7266static void hvalsCommand(redisClient *c) {
7fb16bac 7267 genericHgetallCommand(c,REDIS_HASH_VALUE);
78409a0f 7268}
7269
7270static void hgetallCommand(redisClient *c) {
7fb16bac 7271 genericHgetallCommand(c,REDIS_HASH_KEY|REDIS_HASH_VALUE);
78409a0f 7272}
7273
a86f14b1 7274static void hexistsCommand(redisClient *c) {
7275 robj *o;
a86f14b1 7276 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
7277 checkType(c,o,REDIS_HASH)) return;
7278
d1578a33 7279 addReply(c, hashTypeExists(o,c->argv[2]) ? shared.cone : shared.czero);
a86f14b1 7280}
7281
ada386b2 7282static void convertToRealHash(robj *o) {
7283 unsigned char *key, *val, *p, *zm = o->ptr;
7284 unsigned int klen, vlen;
7285 dict *dict = dictCreate(&hashDictType,NULL);
7286
7287 assert(o->type == REDIS_HASH && o->encoding != REDIS_ENCODING_HT);
7288 p = zipmapRewind(zm);
7289 while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
7290 robj *keyobj, *valobj;
7291
7292 keyobj = createStringObject((char*)key,klen);
7293 valobj = createStringObject((char*)val,vlen);
05df7621 7294 keyobj = tryObjectEncoding(keyobj);
7295 valobj = tryObjectEncoding(valobj);
ada386b2 7296 dictAdd(dict,keyobj,valobj);
7297 }
7298 o->encoding = REDIS_ENCODING_HT;
7299 o->ptr = dict;
7300 zfree(zm);
7301}
7302
6b47e12e 7303/* ========================= Non type-specific commands ==================== */
7304
ed9b544e 7305static void flushdbCommand(redisClient *c) {
ca37e9cd 7306 server.dirty += dictSize(c->db->dict);
9b30e1a2 7307 touchWatchedKeysOnFlush(c->db->id);
3305306f 7308 dictEmpty(c->db->dict);
7309 dictEmpty(c->db->expires);
ed9b544e 7310 addReply(c,shared.ok);
ed9b544e 7311}
7312
7313static void flushallCommand(redisClient *c) {
9b30e1a2 7314 touchWatchedKeysOnFlush(-1);
ca37e9cd 7315 server.dirty += emptyDb();
ed9b544e 7316 addReply(c,shared.ok);
500ece7c 7317 if (server.bgsavechildpid != -1) {
7318 kill(server.bgsavechildpid,SIGKILL);
7319 rdbRemoveTempFile(server.bgsavechildpid);
7320 }
f78fd11b 7321 rdbSave(server.dbfilename);
ca37e9cd 7322 server.dirty++;
ed9b544e 7323}
7324
56906eef 7325static redisSortOperation *createSortOperation(int type, robj *pattern) {
ed9b544e 7326 redisSortOperation *so = zmalloc(sizeof(*so));
ed9b544e 7327 so->type = type;
7328 so->pattern = pattern;
7329 return so;
7330}
7331
7332/* Return the value associated to the key with a name obtained
55017f9d
PN
7333 * substituting the first occurence of '*' in 'pattern' with 'subst'.
7334 * The returned object will always have its refcount increased by 1
7335 * when it is non-NULL. */
56906eef 7336static robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
6d7d1370 7337 char *p, *f;
ed9b544e 7338 sds spat, ssub;
6d7d1370
PN
7339 robj keyobj, fieldobj, *o;
7340 int prefixlen, sublen, postfixlen, fieldlen;
ed9b544e 7341 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
7342 struct {
f1017b3f 7343 long len;
7344 long free;
ed9b544e 7345 char buf[REDIS_SORTKEY_MAX+1];
6d7d1370 7346 } keyname, fieldname;
ed9b544e 7347
28173a49 7348 /* If the pattern is "#" return the substitution object itself in order
7349 * to implement the "SORT ... GET #" feature. */
7350 spat = pattern->ptr;
7351 if (spat[0] == '#' && spat[1] == '\0') {
55017f9d 7352 incrRefCount(subst);
28173a49 7353 return subst;
7354 }
7355
7356 /* The substitution object may be specially encoded. If so we create
9d65a1bb 7357 * a decoded object on the fly. Otherwise getDecodedObject will just
7358 * increment the ref count, that we'll decrement later. */
7359 subst = getDecodedObject(subst);
942a3961 7360
ed9b544e 7361 ssub = subst->ptr;
7362 if (sdslen(spat)+sdslen(ssub)-1 > REDIS_SORTKEY_MAX) return NULL;
7363 p = strchr(spat,'*');
ed5a857a 7364 if (!p) {
7365 decrRefCount(subst);
7366 return NULL;
7367 }
ed9b544e 7368
6d7d1370
PN
7369 /* Find out if we're dealing with a hash dereference. */
7370 if ((f = strstr(p+1, "->")) != NULL) {
7371 fieldlen = sdslen(spat)-(f-spat);
7372 /* this also copies \0 character */
7373 memcpy(fieldname.buf,f+2,fieldlen-1);
7374 fieldname.len = fieldlen-2;
7375 } else {
7376 fieldlen = 0;
7377 }
7378
ed9b544e 7379 prefixlen = p-spat;
7380 sublen = sdslen(ssub);
6d7d1370 7381 postfixlen = sdslen(spat)-(prefixlen+1)-fieldlen;
ed9b544e 7382 memcpy(keyname.buf,spat,prefixlen);
7383 memcpy(keyname.buf+prefixlen,ssub,sublen);
7384 memcpy(keyname.buf+prefixlen+sublen,p+1,postfixlen);
7385 keyname.buf[prefixlen+sublen+postfixlen] = '\0';
7386 keyname.len = prefixlen+sublen+postfixlen;
942a3961 7387 decrRefCount(subst);
7388
6d7d1370
PN
7389 /* Lookup substituted key */
7390 initStaticStringObject(keyobj,((char*)&keyname)+(sizeof(long)*2));
7391 o = lookupKeyRead(db,&keyobj);
55017f9d
PN
7392 if (o == NULL) return NULL;
7393
7394 if (fieldlen > 0) {
7395 if (o->type != REDIS_HASH || fieldname.len < 1) return NULL;
6d7d1370 7396
705dad38
PN
7397 /* Retrieve value from hash by the field name. This operation
7398 * already increases the refcount of the returned object. */
6d7d1370 7399 initStaticStringObject(fieldobj,((char*)&fieldname)+(sizeof(long)*2));
d1578a33 7400 o = hashTypeGet(o, &fieldobj);
705dad38 7401 } else {
55017f9d 7402 if (o->type != REDIS_STRING) return NULL;
b6f07345 7403
705dad38
PN
7404 /* Every object that this function returns needs to have its refcount
7405 * increased. sortCommand decreases it again. */
7406 incrRefCount(o);
6d7d1370
PN
7407 }
7408
7409 return o;
ed9b544e 7410}
7411
7412/* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
7413 * the additional parameter is not standard but a BSD-specific we have to
7414 * pass sorting parameters via the global 'server' structure */
7415static int sortCompare(const void *s1, const void *s2) {
7416 const redisSortObject *so1 = s1, *so2 = s2;
7417 int cmp;
7418
7419 if (!server.sort_alpha) {
7420 /* Numeric sorting. Here it's trivial as we precomputed scores */
7421 if (so1->u.score > so2->u.score) {
7422 cmp = 1;
7423 } else if (so1->u.score < so2->u.score) {
7424 cmp = -1;
7425 } else {
7426 cmp = 0;
7427 }
7428 } else {
7429 /* Alphanumeric sorting */
7430 if (server.sort_bypattern) {
7431 if (!so1->u.cmpobj || !so2->u.cmpobj) {
7432 /* At least one compare object is NULL */
7433 if (so1->u.cmpobj == so2->u.cmpobj)
7434 cmp = 0;
7435 else if (so1->u.cmpobj == NULL)
7436 cmp = -1;
7437 else
7438 cmp = 1;
7439 } else {
7440 /* We have both the objects, use strcoll */
7441 cmp = strcoll(so1->u.cmpobj->ptr,so2->u.cmpobj->ptr);
7442 }
7443 } else {
08ee9b57 7444 /* Compare elements directly. */
7445 cmp = compareStringObjects(so1->obj,so2->obj);
ed9b544e 7446 }
7447 }
7448 return server.sort_desc ? -cmp : cmp;
7449}
7450
7451/* The SORT command is the most complex command in Redis. Warning: this code
7452 * is optimized for speed and a bit less for readability */
7453static void sortCommand(redisClient *c) {
ed9b544e 7454 list *operations;
a03611e1 7455 unsigned int outputlen = 0;
ed9b544e 7456 int desc = 0, alpha = 0;
7457 int limit_start = 0, limit_count = -1, start, end;
7458 int j, dontsort = 0, vectorlen;
7459 int getop = 0; /* GET operation counter */
443c6409 7460 robj *sortval, *sortby = NULL, *storekey = NULL;
ed9b544e 7461 redisSortObject *vector; /* Resulting vector to sort */
7462
7463 /* Lookup the key to sort. It must be of the right types */
3305306f 7464 sortval = lookupKeyRead(c->db,c->argv[1]);
7465 if (sortval == NULL) {
4e27f268 7466 addReply(c,shared.emptymultibulk);
ed9b544e 7467 return;
7468 }
a5eb649b 7469 if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST &&
7470 sortval->type != REDIS_ZSET)
7471 {
c937aa89 7472 addReply(c,shared.wrongtypeerr);
ed9b544e 7473 return;
7474 }
7475
7476 /* Create a list of operations to perform for every sorted element.
7477 * Operations can be GET/DEL/INCR/DECR */
7478 operations = listCreate();
092dac2a 7479 listSetFreeMethod(operations,zfree);
ed9b544e 7480 j = 2;
7481
7482 /* Now we need to protect sortval incrementing its count, in the future
7483 * SORT may have options able to overwrite/delete keys during the sorting
7484 * and the sorted key itself may get destroied */
7485 incrRefCount(sortval);
7486
7487 /* The SORT command has an SQL-alike syntax, parse it */
7488 while(j < c->argc) {
7489 int leftargs = c->argc-j-1;
7490 if (!strcasecmp(c->argv[j]->ptr,"asc")) {
7491 desc = 0;
7492 } else if (!strcasecmp(c->argv[j]->ptr,"desc")) {
7493 desc = 1;
7494 } else if (!strcasecmp(c->argv[j]->ptr,"alpha")) {
7495 alpha = 1;
7496 } else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) {
7497 limit_start = atoi(c->argv[j+1]->ptr);
7498 limit_count = atoi(c->argv[j+2]->ptr);
7499 j+=2;
443c6409 7500 } else if (!strcasecmp(c->argv[j]->ptr,"store") && leftargs >= 1) {
7501 storekey = c->argv[j+1];
7502 j++;
ed9b544e 7503 } else if (!strcasecmp(c->argv[j]->ptr,"by") && leftargs >= 1) {
7504 sortby = c->argv[j+1];
7505 /* If the BY pattern does not contain '*', i.e. it is constant,
7506 * we don't need to sort nor to lookup the weight keys. */
7507 if (strchr(c->argv[j+1]->ptr,'*') == NULL) dontsort = 1;
7508 j++;
7509 } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
7510 listAddNodeTail(operations,createSortOperation(
7511 REDIS_SORT_GET,c->argv[j+1]));
7512 getop++;
7513 j++;
ed9b544e 7514 } else {
7515 decrRefCount(sortval);
7516 listRelease(operations);
c937aa89 7517 addReply(c,shared.syntaxerr);
ed9b544e 7518 return;
7519 }
7520 j++;
7521 }
7522
7523 /* Load the sorting vector with all the objects to sort */
a5eb649b 7524 switch(sortval->type) {
003f0840 7525 case REDIS_LIST: vectorlen = listTypeLength(sortval); break;
a5eb649b 7526 case REDIS_SET: vectorlen = dictSize((dict*)sortval->ptr); break;
7527 case REDIS_ZSET: vectorlen = dictSize(((zset*)sortval->ptr)->dict); break;
f83c6cb5 7528 default: vectorlen = 0; redisPanic("Bad SORT type"); /* Avoid GCC warning */
a5eb649b 7529 }
ed9b544e 7530 vector = zmalloc(sizeof(redisSortObject)*vectorlen);
ed9b544e 7531 j = 0;
a5eb649b 7532
ed9b544e 7533 if (sortval->type == REDIS_LIST) {
003f0840
PN
7534 listTypeIterator *li = listTypeInitIterator(sortval,0,REDIS_TAIL);
7535 listTypeEntry entry;
7536 while(listTypeNext(li,&entry)) {
7537 vector[j].obj = listTypeGet(&entry);
ed9b544e 7538 vector[j].u.score = 0;
7539 vector[j].u.cmpobj = NULL;
ed9b544e 7540 j++;
7541 }
003f0840 7542 listTypeReleaseIterator(li);
ed9b544e 7543 } else {
a5eb649b 7544 dict *set;
ed9b544e 7545 dictIterator *di;
7546 dictEntry *setele;
7547
a5eb649b 7548 if (sortval->type == REDIS_SET) {
7549 set = sortval->ptr;
7550 } else {
7551 zset *zs = sortval->ptr;
7552 set = zs->dict;
7553 }
7554
ed9b544e 7555 di = dictGetIterator(set);
ed9b544e 7556 while((setele = dictNext(di)) != NULL) {
7557 vector[j].obj = dictGetEntryKey(setele);
7558 vector[j].u.score = 0;
7559 vector[j].u.cmpobj = NULL;
7560 j++;
7561 }
7562 dictReleaseIterator(di);
7563 }
dfc5e96c 7564 redisAssert(j == vectorlen);
ed9b544e 7565
7566 /* Now it's time to load the right scores in the sorting vector */
7567 if (dontsort == 0) {
7568 for (j = 0; j < vectorlen; j++) {
6d7d1370 7569 robj *byval;
ed9b544e 7570 if (sortby) {
6d7d1370 7571 /* lookup value to sort by */
3305306f 7572 byval = lookupKeyByPattern(c->db,sortby,vector[j].obj);
705dad38 7573 if (!byval) continue;
ed9b544e 7574 } else {
6d7d1370
PN
7575 /* use object itself to sort by */
7576 byval = vector[j].obj;
7577 }
7578
7579 if (alpha) {
08ee9b57 7580 if (sortby) vector[j].u.cmpobj = getDecodedObject(byval);
6d7d1370
PN
7581 } else {
7582 if (byval->encoding == REDIS_ENCODING_RAW) {
7583 vector[j].u.score = strtod(byval->ptr,NULL);
16fa22f1 7584 } else if (byval->encoding == REDIS_ENCODING_INT) {
6d7d1370
PN
7585 /* Don't need to decode the object if it's
7586 * integer-encoded (the only encoding supported) so
7587 * far. We can just cast it */
16fa22f1
PN
7588 vector[j].u.score = (long)byval->ptr;
7589 } else {
7590 redisAssert(1 != 1);
942a3961 7591 }
ed9b544e 7592 }
6d7d1370 7593
705dad38
PN
7594 /* when the object was retrieved using lookupKeyByPattern,
7595 * its refcount needs to be decreased. */
7596 if (sortby) {
7597 decrRefCount(byval);
ed9b544e 7598 }
7599 }
7600 }
7601
7602 /* We are ready to sort the vector... perform a bit of sanity check
7603 * on the LIMIT option too. We'll use a partial version of quicksort. */
7604 start = (limit_start < 0) ? 0 : limit_start;
7605 end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1;
7606 if (start >= vectorlen) {
7607 start = vectorlen-1;
7608 end = vectorlen-2;
7609 }
7610 if (end >= vectorlen) end = vectorlen-1;
7611
7612 if (dontsort == 0) {
7613 server.sort_desc = desc;
7614 server.sort_alpha = alpha;
7615 server.sort_bypattern = sortby ? 1 : 0;
5f5b9840 7616 if (sortby && (start != 0 || end != vectorlen-1))
7617 pqsort(vector,vectorlen,sizeof(redisSortObject),sortCompare, start,end);
7618 else
7619 qsort(vector,vectorlen,sizeof(redisSortObject),sortCompare);
ed9b544e 7620 }
7621
7622 /* Send command output to the output buffer, performing the specified
7623 * GET/DEL/INCR/DECR operations if any. */
7624 outputlen = getop ? getop*(end-start+1) : end-start+1;
443c6409 7625 if (storekey == NULL) {
7626 /* STORE option not specified, sent the sorting result to client */
7627 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",outputlen));
7628 for (j = start; j <= end; j++) {
7629 listNode *ln;
c7df85a4 7630 listIter li;
7631
dd88747b 7632 if (!getop) addReplyBulk(c,vector[j].obj);
c7df85a4 7633 listRewind(operations,&li);
7634 while((ln = listNext(&li))) {
443c6409 7635 redisSortOperation *sop = ln->value;
7636 robj *val = lookupKeyByPattern(c->db,sop->pattern,
7637 vector[j].obj);
7638
7639 if (sop->type == REDIS_SORT_GET) {
55017f9d 7640 if (!val) {
443c6409 7641 addReply(c,shared.nullbulk);
7642 } else {
dd88747b 7643 addReplyBulk(c,val);
55017f9d 7644 decrRefCount(val);
443c6409 7645 }
7646 } else {
dfc5e96c 7647 redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
443c6409 7648 }
7649 }
ed9b544e 7650 }
443c6409 7651 } else {
74e0f445 7652 robj *sobj = createZiplistObject();
443c6409 7653
7654 /* STORE option specified, set the sorting result as a List object */
7655 for (j = start; j <= end; j++) {
7656 listNode *ln;
c7df85a4 7657 listIter li;
7658
443c6409 7659 if (!getop) {
003f0840 7660 listTypePush(sobj,vector[j].obj,REDIS_TAIL);
a03611e1
PN
7661 } else {
7662 listRewind(operations,&li);
7663 while((ln = listNext(&li))) {
7664 redisSortOperation *sop = ln->value;
7665 robj *val = lookupKeyByPattern(c->db,sop->pattern,
7666 vector[j].obj);
7667
7668 if (sop->type == REDIS_SORT_GET) {
7669 if (!val) val = createStringObject("",0);
7670
003f0840 7671 /* listTypePush does an incrRefCount, so we should take care
a03611e1
PN
7672 * care of the incremented refcount caused by either
7673 * lookupKeyByPattern or createStringObject("",0) */
003f0840 7674 listTypePush(sobj,val,REDIS_TAIL);
a03611e1 7675 decrRefCount(val);
443c6409 7676 } else {
a03611e1
PN
7677 /* always fails */
7678 redisAssert(sop->type == REDIS_SORT_GET);
443c6409 7679 }
ed9b544e 7680 }
ed9b544e 7681 }
ed9b544e 7682 }
846d8b3e 7683 dbReplace(c->db,storekey,sobj);
443c6409 7684 /* Note: we add 1 because the DB is dirty anyway since even if the
7685 * SORT result is empty a new key is set and maybe the old content
7686 * replaced. */
7687 server.dirty += 1+outputlen;
7688 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",outputlen));
ed9b544e 7689 }
7690
7691 /* Cleanup */
a03611e1
PN
7692 if (sortval->type == REDIS_LIST)
7693 for (j = 0; j < vectorlen; j++)
7694 decrRefCount(vector[j].obj);
ed9b544e 7695 decrRefCount(sortval);
7696 listRelease(operations);
7697 for (j = 0; j < vectorlen; j++) {
16fa22f1 7698 if (alpha && vector[j].u.cmpobj)
ed9b544e 7699 decrRefCount(vector[j].u.cmpobj);
7700 }
7701 zfree(vector);
7702}
7703
ec6c7a1d 7704/* Convert an amount of bytes into a human readable string in the form
7705 * of 100B, 2G, 100M, 4K, and so forth. */
7706static void bytesToHuman(char *s, unsigned long long n) {
7707 double d;
7708
7709 if (n < 1024) {
7710 /* Bytes */
7711 sprintf(s,"%lluB",n);
7712 return;
7713 } else if (n < (1024*1024)) {
7714 d = (double)n/(1024);
7715 sprintf(s,"%.2fK",d);
7716 } else if (n < (1024LL*1024*1024)) {
7717 d = (double)n/(1024*1024);
7718 sprintf(s,"%.2fM",d);
7719 } else if (n < (1024LL*1024*1024*1024)) {
7720 d = (double)n/(1024LL*1024*1024);
b72f6a4b 7721 sprintf(s,"%.2fG",d);
ec6c7a1d 7722 }
7723}
7724
1c85b79f 7725/* Create the string returned by the INFO command. This is decoupled
7726 * by the INFO command itself as we need to report the same information
7727 * on memory corruption problems. */
7728static sds genRedisInfoString(void) {
ed9b544e 7729 sds info;
7730 time_t uptime = time(NULL)-server.stat_starttime;
c3cb078d 7731 int j;
ec6c7a1d 7732 char hmem[64];
55a8298f 7733
b72f6a4b 7734 bytesToHuman(hmem,zmalloc_used_memory());
ed9b544e 7735 info = sdscatprintf(sdsempty(),
7736 "redis_version:%s\r\n"
5436146c
PN
7737 "redis_git_sha1:%s\r\n"
7738 "redis_git_dirty:%d\r\n"
f1017b3f 7739 "arch_bits:%s\r\n"
7a932b74 7740 "multiplexing_api:%s\r\n"
0d7170a4 7741 "process_id:%ld\r\n"
682ac724 7742 "uptime_in_seconds:%ld\r\n"
7743 "uptime_in_days:%ld\r\n"
ed9b544e 7744 "connected_clients:%d\r\n"
7745 "connected_slaves:%d\r\n"
f86a74e9 7746 "blocked_clients:%d\r\n"
5fba9f71 7747 "used_memory:%zu\r\n"
ec6c7a1d 7748 "used_memory_human:%s\r\n"
ed9b544e 7749 "changes_since_last_save:%lld\r\n"
be2bb6b0 7750 "bgsave_in_progress:%d\r\n"
682ac724 7751 "last_save_time:%ld\r\n"
b3fad521 7752 "bgrewriteaof_in_progress:%d\r\n"
ed9b544e 7753 "total_connections_received:%lld\r\n"
7754 "total_commands_processed:%lld\r\n"
2a6a2ed1 7755 "expired_keys:%lld\r\n"
3be2c9d7 7756 "hash_max_zipmap_entries:%zu\r\n"
7757 "hash_max_zipmap_value:%zu\r\n"
ffc6b7f8 7758 "pubsub_channels:%ld\r\n"
7759 "pubsub_patterns:%u\r\n"
7d98e08c 7760 "vm_enabled:%d\r\n"
a0f643ea 7761 "role:%s\r\n"
ed9b544e 7762 ,REDIS_VERSION,
7c4fc71c 7763 redisGitSHA1(),
7764 strtol(redisGitDirty(),NULL,10) > 0,
f1017b3f 7765 (sizeof(long) == 8) ? "64" : "32",
7a932b74 7766 aeGetApiName(),
0d7170a4 7767 (long) getpid(),
a0f643ea 7768 uptime,
7769 uptime/(3600*24),
ed9b544e 7770 listLength(server.clients)-listLength(server.slaves),
7771 listLength(server.slaves),
d5d55fc3 7772 server.blpop_blocked_clients,
b72f6a4b 7773 zmalloc_used_memory(),
ec6c7a1d 7774 hmem,
ed9b544e 7775 server.dirty,
9d65a1bb 7776 server.bgsavechildpid != -1,
ed9b544e 7777 server.lastsave,
b3fad521 7778 server.bgrewritechildpid != -1,
ed9b544e 7779 server.stat_numconnections,
7780 server.stat_numcommands,
2a6a2ed1 7781 server.stat_expiredkeys,
55a8298f 7782 server.hash_max_zipmap_entries,
7783 server.hash_max_zipmap_value,
ffc6b7f8 7784 dictSize(server.pubsub_channels),
7785 listLength(server.pubsub_patterns),
7d98e08c 7786 server.vm_enabled != 0,
a0f643ea 7787 server.masterhost == NULL ? "master" : "slave"
ed9b544e 7788 );
a0f643ea 7789 if (server.masterhost) {
7790 info = sdscatprintf(info,
7791 "master_host:%s\r\n"
7792 "master_port:%d\r\n"
7793 "master_link_status:%s\r\n"
7794 "master_last_io_seconds_ago:%d\r\n"
7795 ,server.masterhost,
7796 server.masterport,
7797 (server.replstate == REDIS_REPL_CONNECTED) ?
7798 "up" : "down",
f72b934d 7799 server.master ? ((int)(time(NULL)-server.master->lastinteraction)) : -1
a0f643ea 7800 );
7801 }
7d98e08c 7802 if (server.vm_enabled) {
1064ef87 7803 lockThreadedIO();
7d98e08c 7804 info = sdscatprintf(info,
7805 "vm_conf_max_memory:%llu\r\n"
7806 "vm_conf_page_size:%llu\r\n"
7807 "vm_conf_pages:%llu\r\n"
7808 "vm_stats_used_pages:%llu\r\n"
7809 "vm_stats_swapped_objects:%llu\r\n"
7810 "vm_stats_swappin_count:%llu\r\n"
7811 "vm_stats_swappout_count:%llu\r\n"
b9bc0eef 7812 "vm_stats_io_newjobs_len:%lu\r\n"
7813 "vm_stats_io_processing_len:%lu\r\n"
7814 "vm_stats_io_processed_len:%lu\r\n"
25fd2cb2 7815 "vm_stats_io_active_threads:%lu\r\n"
d5d55fc3 7816 "vm_stats_blocked_clients:%lu\r\n"
7d98e08c 7817 ,(unsigned long long) server.vm_max_memory,
7818 (unsigned long long) server.vm_page_size,
7819 (unsigned long long) server.vm_pages,
7820 (unsigned long long) server.vm_stats_used_pages,
7821 (unsigned long long) server.vm_stats_swapped_objects,
7822 (unsigned long long) server.vm_stats_swapins,
b9bc0eef 7823 (unsigned long long) server.vm_stats_swapouts,
7824 (unsigned long) listLength(server.io_newjobs),
7825 (unsigned long) listLength(server.io_processing),
7826 (unsigned long) listLength(server.io_processed),
d5d55fc3 7827 (unsigned long) server.io_active_threads,
7828 (unsigned long) server.vm_blocked_clients
7d98e08c 7829 );
1064ef87 7830 unlockThreadedIO();
7d98e08c 7831 }
c3cb078d 7832 for (j = 0; j < server.dbnum; j++) {
7833 long long keys, vkeys;
7834
7835 keys = dictSize(server.db[j].dict);
7836 vkeys = dictSize(server.db[j].expires);
7837 if (keys || vkeys) {
9d65a1bb 7838 info = sdscatprintf(info, "db%d:keys=%lld,expires=%lld\r\n",
c3cb078d 7839 j, keys, vkeys);
7840 }
7841 }
1c85b79f 7842 return info;
7843}
7844
7845static void infoCommand(redisClient *c) {
7846 sds info = genRedisInfoString();
83c6a618 7847 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n",
7848 (unsigned long)sdslen(info)));
ed9b544e 7849 addReplySds(c,info);
70003d28 7850 addReply(c,shared.crlf);
ed9b544e 7851}
7852
3305306f 7853static void monitorCommand(redisClient *c) {
7854 /* ignore MONITOR if aleady slave or in monitor mode */
7855 if (c->flags & REDIS_SLAVE) return;
7856
7857 c->flags |= (REDIS_SLAVE|REDIS_MONITOR);
7858 c->slaveseldb = 0;
6b47e12e 7859 listAddNodeTail(server.monitors,c);
3305306f 7860 addReply(c,shared.ok);
7861}
7862
7863/* ================================= Expire ================================= */
7864static int removeExpire(redisDb *db, robj *key) {
829137b9
PN
7865 /* An expire may only be removed if there is a corresponding entry in the
7866 * main dict. Otherwise, the key will never be freed. */
7867 redisAssert(dictFind(db->dict,key->ptr) != NULL);
09241813 7868 if (dictDelete(db->expires,key->ptr) == DICT_OK) {
3305306f 7869 return 1;
7870 } else {
7871 return 0;
7872 }
7873}
7874
7875static int setExpire(redisDb *db, robj *key, time_t when) {
829137b9
PN
7876 dictEntry *de;
7877
7878 /* Reuse the sds from the main dict in the expire dict */
7879 redisAssert((de = dictFind(db->dict,key->ptr)) != NULL);
7880 if (dictAdd(db->expires,dictGetEntryKey(de),(void*)when) == DICT_ERR) {
3305306f 7881 return 0;
7882 } else {
3305306f 7883 return 1;
7884 }
7885}
7886
bb32ede5 7887/* Return the expire time of the specified key, or -1 if no expire
7888 * is associated with this key (i.e. the key is non volatile) */
7889static time_t getExpire(redisDb *db, robj *key) {
7890 dictEntry *de;
7891
7892 /* No expire? return ASAP */
7893 if (dictSize(db->expires) == 0 ||
09241813 7894 (de = dictFind(db->expires,key->ptr)) == NULL) return -1;
bb32ede5 7895
829137b9
PN
7896 /* The entry was found in the expire dict, this means it should also
7897 * be present in the main dict (safety check). */
7898 redisAssert(dictFind(db->dict,key->ptr) != NULL);
bb32ede5 7899 return (time_t) dictGetEntryVal(de);
7900}
7901
3305306f 7902static int expireIfNeeded(redisDb *db, robj *key) {
829137b9
PN
7903 time_t when = getExpire(db,key);
7904 if (when < 0) return 0;
3305306f 7905
829137b9 7906 /* Return when this key has not expired */
3305306f 7907 if (time(NULL) <= when) return 0;
7908
7909 /* Delete the key */
2a6a2ed1 7910 server.stat_expiredkeys++;
829137b9
PN
7911 server.dirty++;
7912 return dbDelete(db,key);
3305306f 7913}
7914
7915static int deleteIfVolatile(redisDb *db, robj *key) {
829137b9 7916 if (getExpire(db,key) < 0) return 0;
3305306f 7917
7918 /* Delete the key */
2a6a2ed1 7919 server.stat_expiredkeys++;
829137b9
PN
7920 server.dirty++;
7921 return dbDelete(db,key);
3305306f 7922}
7923
bbe025e0 7924static void expireGenericCommand(redisClient *c, robj *key, robj *param, long offset) {
3305306f 7925 dictEntry *de;
bbe025e0
AM
7926 time_t seconds;
7927
bd79a6bd 7928 if (getLongFromObjectOrReply(c, param, &seconds, NULL) != REDIS_OK) return;
bbe025e0
AM
7929
7930 seconds -= offset;
3305306f 7931
09241813 7932 de = dictFind(c->db->dict,key->ptr);
3305306f 7933 if (de == NULL) {
7934 addReply(c,shared.czero);
7935 return;
7936 }
d4dd6556 7937 if (seconds <= 0) {
09241813 7938 if (dbDelete(c->db,key)) server.dirty++;
43e5ccdf 7939 addReply(c, shared.cone);
3305306f 7940 return;
7941 } else {
7942 time_t when = time(NULL)+seconds;
802e8373 7943 if (setExpire(c->db,key,when)) {
3305306f 7944 addReply(c,shared.cone);
77423026 7945 server.dirty++;
7946 } else {
3305306f 7947 addReply(c,shared.czero);
77423026 7948 }
3305306f 7949 return;
7950 }
7951}
7952
802e8373 7953static void expireCommand(redisClient *c) {
bbe025e0 7954 expireGenericCommand(c,c->argv[1],c->argv[2],0);
802e8373 7955}
7956
7957static void expireatCommand(redisClient *c) {
bbe025e0 7958 expireGenericCommand(c,c->argv[1],c->argv[2],time(NULL));
802e8373 7959}
7960
fd88489a 7961static void ttlCommand(redisClient *c) {
7962 time_t expire;
7963 int ttl = -1;
7964
7965 expire = getExpire(c->db,c->argv[1]);
7966 if (expire != -1) {
7967 ttl = (int) (expire-time(NULL));
7968 if (ttl < 0) ttl = -1;
7969 }
7970 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",ttl));
7971}
7972
6e469882 7973/* ================================ MULTI/EXEC ============================== */
7974
7975/* Client state initialization for MULTI/EXEC */
7976static void initClientMultiState(redisClient *c) {
7977 c->mstate.commands = NULL;
7978 c->mstate.count = 0;
7979}
7980
7981/* Release all the resources associated with MULTI/EXEC state */
7982static void freeClientMultiState(redisClient *c) {
7983 int j;
7984
7985 for (j = 0; j < c->mstate.count; j++) {
7986 int i;
7987 multiCmd *mc = c->mstate.commands+j;
7988
7989 for (i = 0; i < mc->argc; i++)
7990 decrRefCount(mc->argv[i]);
7991 zfree(mc->argv);
7992 }
7993 zfree(c->mstate.commands);
7994}
7995
7996/* Add a new command into the MULTI commands queue */
7997static void queueMultiCommand(redisClient *c, struct redisCommand *cmd) {
7998 multiCmd *mc;
7999 int j;
8000
8001 c->mstate.commands = zrealloc(c->mstate.commands,
8002 sizeof(multiCmd)*(c->mstate.count+1));
8003 mc = c->mstate.commands+c->mstate.count;
8004 mc->cmd = cmd;
8005 mc->argc = c->argc;
8006 mc->argv = zmalloc(sizeof(robj*)*c->argc);
8007 memcpy(mc->argv,c->argv,sizeof(robj*)*c->argc);
8008 for (j = 0; j < c->argc; j++)
8009 incrRefCount(mc->argv[j]);
8010 c->mstate.count++;
8011}
8012
8013static void multiCommand(redisClient *c) {
6531c94d 8014 if (c->flags & REDIS_MULTI) {
8015 addReplySds(c,sdsnew("-ERR MULTI calls can not be nested\r\n"));
8016 return;
8017 }
6e469882 8018 c->flags |= REDIS_MULTI;
36c548f0 8019 addReply(c,shared.ok);
6e469882 8020}
8021
18b6cb76
DJ
8022static void discardCommand(redisClient *c) {
8023 if (!(c->flags & REDIS_MULTI)) {
8024 addReplySds(c,sdsnew("-ERR DISCARD without MULTI\r\n"));
8025 return;
8026 }
8027
8028 freeClientMultiState(c);
8029 initClientMultiState(c);
8030 c->flags &= (~REDIS_MULTI);
a2645226 8031 unwatchAllKeys(c);
18b6cb76
DJ
8032 addReply(c,shared.ok);
8033}
8034
66c8853f 8035/* Send a MULTI command to all the slaves and AOF file. Check the execCommand
8036 * implememntation for more information. */
8037static void execCommandReplicateMulti(redisClient *c) {
8038 struct redisCommand *cmd;
8039 robj *multistring = createStringObject("MULTI",5);
8040
8041 cmd = lookupCommand("multi");
8042 if (server.appendonly)
8043 feedAppendOnlyFile(cmd,c->db->id,&multistring,1);
8044 if (listLength(server.slaves))
8045 replicationFeedSlaves(server.slaves,c->db->id,&multistring,1);
8046 decrRefCount(multistring);
8047}
8048
6e469882 8049static void execCommand(redisClient *c) {
8050 int j;
8051 robj **orig_argv;
8052 int orig_argc;
8053
8054 if (!(c->flags & REDIS_MULTI)) {
8055 addReplySds(c,sdsnew("-ERR EXEC without MULTI\r\n"));
8056 return;
8057 }
8058
37ab76c9 8059 /* Check if we need to abort the EXEC if some WATCHed key was touched.
8060 * A failed EXEC will return a multi bulk nil object. */
8061 if (c->flags & REDIS_DIRTY_CAS) {
8062 freeClientMultiState(c);
8063 initClientMultiState(c);
8064 c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS);
8065 unwatchAllKeys(c);
8066 addReply(c,shared.nullmultibulk);
8067 return;
8068 }
8069
66c8853f 8070 /* Replicate a MULTI request now that we are sure the block is executed.
8071 * This way we'll deliver the MULTI/..../EXEC block as a whole and
8072 * both the AOF and the replication link will have the same consistency
8073 * and atomicity guarantees. */
8074 execCommandReplicateMulti(c);
8075
8076 /* Exec all the queued commands */
1ad4d316 8077 unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */
6e469882 8078 orig_argv = c->argv;
8079 orig_argc = c->argc;
8080 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->mstate.count));
8081 for (j = 0; j < c->mstate.count; j++) {
8082 c->argc = c->mstate.commands[j].argc;
8083 c->argv = c->mstate.commands[j].argv;
8084 call(c,c->mstate.commands[j].cmd);
8085 }
8086 c->argv = orig_argv;
8087 c->argc = orig_argc;
8088 freeClientMultiState(c);
8089 initClientMultiState(c);
1ad4d316 8090 c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS);
66c8853f 8091 /* Make sure the EXEC command is always replicated / AOF, since we
8092 * always send the MULTI command (we can't know beforehand if the
8093 * next operations will contain at least a modification to the DB). */
8094 server.dirty++;
6e469882 8095}
8096
4409877e 8097/* =========================== Blocking Operations ========================= */
8098
8099/* Currently Redis blocking operations support is limited to list POP ops,
8100 * so the current implementation is not fully generic, but it is also not
8101 * completely specific so it will not require a rewrite to support new
8102 * kind of blocking operations in the future.
8103 *
8104 * Still it's important to note that list blocking operations can be already
8105 * used as a notification mechanism in order to implement other blocking
8106 * operations at application level, so there must be a very strong evidence
8107 * of usefulness and generality before new blocking operations are implemented.
8108 *
8109 * This is how the current blocking POP works, we use BLPOP as example:
8110 * - If the user calls BLPOP and the key exists and contains a non empty list
8111 * then LPOP is called instead. So BLPOP is semantically the same as LPOP
8112 * if there is not to block.
8113 * - If instead BLPOP is called and the key does not exists or the list is
8114 * empty we need to block. In order to do so we remove the notification for
8115 * new data to read in the client socket (so that we'll not serve new
8116 * requests if the blocking request is not served). Also we put the client
37ab76c9 8117 * in a dictionary (db->blocking_keys) mapping keys to a list of clients
4409877e 8118 * blocking for this keys.
8119 * - If a PUSH operation against a key with blocked clients waiting is
8120 * performed, we serve the first in the list: basically instead to push
8121 * the new element inside the list we return it to the (first / oldest)
8122 * blocking client, unblock the client, and remove it form the list.
8123 *
8124 * The above comment and the source code should be enough in order to understand
8125 * the implementation and modify / fix it later.
8126 */
8127
8128/* Set a client in blocking mode for the specified key, with the specified
8129 * timeout */
b177fd30 8130static void blockForKeys(redisClient *c, robj **keys, int numkeys, time_t timeout) {
4409877e 8131 dictEntry *de;
8132 list *l;
b177fd30 8133 int j;
4409877e 8134
37ab76c9 8135 c->blocking_keys = zmalloc(sizeof(robj*)*numkeys);
8136 c->blocking_keys_num = numkeys;
4409877e 8137 c->blockingto = timeout;
b177fd30 8138 for (j = 0; j < numkeys; j++) {
8139 /* Add the key in the client structure, to map clients -> keys */
37ab76c9 8140 c->blocking_keys[j] = keys[j];
b177fd30 8141 incrRefCount(keys[j]);
4409877e 8142
b177fd30 8143 /* And in the other "side", to map keys -> clients */
37ab76c9 8144 de = dictFind(c->db->blocking_keys,keys[j]);
b177fd30 8145 if (de == NULL) {
8146 int retval;
8147
8148 /* For every key we take a list of clients blocked for it */
8149 l = listCreate();
37ab76c9 8150 retval = dictAdd(c->db->blocking_keys,keys[j],l);
b177fd30 8151 incrRefCount(keys[j]);
8152 assert(retval == DICT_OK);
8153 } else {
8154 l = dictGetEntryVal(de);
8155 }
8156 listAddNodeTail(l,c);
4409877e 8157 }
b177fd30 8158 /* Mark the client as a blocked client */
4409877e 8159 c->flags |= REDIS_BLOCKED;
d5d55fc3 8160 server.blpop_blocked_clients++;
4409877e 8161}
8162
8163/* Unblock a client that's waiting in a blocking operation such as BLPOP */
b0d8747d 8164static void unblockClientWaitingData(redisClient *c) {
4409877e 8165 dictEntry *de;
8166 list *l;
b177fd30 8167 int j;
4409877e 8168
37ab76c9 8169 assert(c->blocking_keys != NULL);
b177fd30 8170 /* The client may wait for multiple keys, so unblock it for every key. */
37ab76c9 8171 for (j = 0; j < c->blocking_keys_num; j++) {
b177fd30 8172 /* Remove this client from the list of clients waiting for this key. */
37ab76c9 8173 de = dictFind(c->db->blocking_keys,c->blocking_keys[j]);
b177fd30 8174 assert(de != NULL);
8175 l = dictGetEntryVal(de);
8176 listDelNode(l,listSearchKey(l,c));
8177 /* If the list is empty we need to remove it to avoid wasting memory */
8178 if (listLength(l) == 0)
37ab76c9 8179 dictDelete(c->db->blocking_keys,c->blocking_keys[j]);
8180 decrRefCount(c->blocking_keys[j]);
b177fd30 8181 }
8182 /* Cleanup the client structure */
37ab76c9 8183 zfree(c->blocking_keys);
8184 c->blocking_keys = NULL;
4409877e 8185 c->flags &= (~REDIS_BLOCKED);
d5d55fc3 8186 server.blpop_blocked_clients--;
5921aa36 8187 /* We want to process data if there is some command waiting
b0d8747d 8188 * in the input buffer. Note that this is safe even if
8189 * unblockClientWaitingData() gets called from freeClient() because
8190 * freeClient() will be smart enough to call this function
8191 * *after* c->querybuf was set to NULL. */
4409877e 8192 if (c->querybuf && sdslen(c->querybuf) > 0) processInputBuffer(c);
8193}
8194
8195/* This should be called from any function PUSHing into lists.
8196 * 'c' is the "pushing client", 'key' is the key it is pushing data against,
8197 * 'ele' is the element pushed.
8198 *
8199 * If the function returns 0 there was no client waiting for a list push
8200 * against this key.
8201 *
8202 * If the function returns 1 there was a client waiting for a list push
8203 * against this key, the element was passed to this client thus it's not
8204 * needed to actually add it to the list and the caller should return asap. */
8205static int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
8206 struct dictEntry *de;
8207 redisClient *receiver;
8208 list *l;
8209 listNode *ln;
8210
37ab76c9 8211 de = dictFind(c->db->blocking_keys,key);
4409877e 8212 if (de == NULL) return 0;
8213 l = dictGetEntryVal(de);
8214 ln = listFirst(l);
8215 assert(ln != NULL);
8216 receiver = ln->value;
4409877e 8217
b177fd30 8218 addReplySds(receiver,sdsnew("*2\r\n"));
dd88747b 8219 addReplyBulk(receiver,key);
8220 addReplyBulk(receiver,ele);
b0d8747d 8221 unblockClientWaitingData(receiver);
4409877e 8222 return 1;
8223}
8224
8225/* Blocking RPOP/LPOP */
8226static void blockingPopGenericCommand(redisClient *c, int where) {
8227 robj *o;
8228 time_t timeout;
b177fd30 8229 int j;
4409877e 8230
b177fd30 8231 for (j = 1; j < c->argc-1; j++) {
8232 o = lookupKeyWrite(c->db,c->argv[j]);
8233 if (o != NULL) {
8234 if (o->type != REDIS_LIST) {
8235 addReply(c,shared.wrongtypeerr);
4409877e 8236 return;
b177fd30 8237 } else {
8238 list *list = o->ptr;
8239 if (listLength(list) != 0) {
8240 /* If the list contains elements fall back to the usual
8241 * non-blocking POP operation */
8242 robj *argv[2], **orig_argv;
8243 int orig_argc;
e0a62c7f 8244
b177fd30 8245 /* We need to alter the command arguments before to call
8246 * popGenericCommand() as the command takes a single key. */
8247 orig_argv = c->argv;
8248 orig_argc = c->argc;
8249 argv[1] = c->argv[j];
8250 c->argv = argv;
8251 c->argc = 2;
8252
8253 /* Also the return value is different, we need to output
8254 * the multi bulk reply header and the key name. The
8255 * "real" command will add the last element (the value)
8256 * for us. If this souds like an hack to you it's just
8257 * because it is... */
8258 addReplySds(c,sdsnew("*2\r\n"));
dd88747b 8259 addReplyBulk(c,argv[1]);
b177fd30 8260 popGenericCommand(c,where);
8261
8262 /* Fix the client structure with the original stuff */
8263 c->argv = orig_argv;
8264 c->argc = orig_argc;
8265 return;
8266 }
4409877e 8267 }
8268 }
8269 }
8270 /* If the list is empty or the key does not exists we must block */
b177fd30 8271 timeout = strtol(c->argv[c->argc-1]->ptr,NULL,10);
4409877e 8272 if (timeout > 0) timeout += time(NULL);
b177fd30 8273 blockForKeys(c,c->argv+1,c->argc-2,timeout);
4409877e 8274}
8275
8276static void blpopCommand(redisClient *c) {
8277 blockingPopGenericCommand(c,REDIS_HEAD);
8278}
8279
8280static void brpopCommand(redisClient *c) {
8281 blockingPopGenericCommand(c,REDIS_TAIL);
8282}
8283
ed9b544e 8284/* =============================== Replication ============================= */
8285
a4d1ba9a 8286static int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 8287 ssize_t nwritten, ret = size;
8288 time_t start = time(NULL);
8289
8290 timeout++;
8291 while(size) {
8292 if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
8293 nwritten = write(fd,ptr,size);
8294 if (nwritten == -1) return -1;
8295 ptr += nwritten;
8296 size -= nwritten;
8297 }
8298 if ((time(NULL)-start) > timeout) {
8299 errno = ETIMEDOUT;
8300 return -1;
8301 }
8302 }
8303 return ret;
8304}
8305
a4d1ba9a 8306static int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 8307 ssize_t nread, totread = 0;
8308 time_t start = time(NULL);
8309
8310 timeout++;
8311 while(size) {
8312 if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
8313 nread = read(fd,ptr,size);
8314 if (nread == -1) return -1;
8315 ptr += nread;
8316 size -= nread;
8317 totread += nread;
8318 }
8319 if ((time(NULL)-start) > timeout) {
8320 errno = ETIMEDOUT;
8321 return -1;
8322 }
8323 }
8324 return totread;
8325}
8326
8327static int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
8328 ssize_t nread = 0;
8329
8330 size--;
8331 while(size) {
8332 char c;
8333
8334 if (syncRead(fd,&c,1,timeout) == -1) return -1;
8335 if (c == '\n') {
8336 *ptr = '\0';
8337 if (nread && *(ptr-1) == '\r') *(ptr-1) = '\0';
8338 return nread;
8339 } else {
8340 *ptr++ = c;
8341 *ptr = '\0';
8342 nread++;
8343 }
8344 }
8345 return nread;
8346}
8347
8348static void syncCommand(redisClient *c) {
40d224a9 8349 /* ignore SYNC if aleady slave or in monitor mode */
8350 if (c->flags & REDIS_SLAVE) return;
8351
8352 /* SYNC can't be issued when the server has pending data to send to
8353 * the client about already issued commands. We need a fresh reply
8354 * buffer registering the differences between the BGSAVE and the current
8355 * dataset, so that we can copy to other slaves if needed. */
8356 if (listLength(c->reply) != 0) {
8357 addReplySds(c,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
8358 return;
8359 }
8360
8361 redisLog(REDIS_NOTICE,"Slave ask for synchronization");
8362 /* Here we need to check if there is a background saving operation
8363 * in progress, or if it is required to start one */
9d65a1bb 8364 if (server.bgsavechildpid != -1) {
40d224a9 8365 /* Ok a background save is in progress. Let's check if it is a good
8366 * one for replication, i.e. if there is another slave that is
8367 * registering differences since the server forked to save */
8368 redisClient *slave;
8369 listNode *ln;
c7df85a4 8370 listIter li;
40d224a9 8371
c7df85a4 8372 listRewind(server.slaves,&li);
8373 while((ln = listNext(&li))) {
40d224a9 8374 slave = ln->value;
8375 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break;
40d224a9 8376 }
8377 if (ln) {
8378 /* Perfect, the server is already registering differences for
8379 * another slave. Set the right state, and copy the buffer. */
8380 listRelease(c->reply);
8381 c->reply = listDup(slave->reply);
40d224a9 8382 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
8383 redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC");
8384 } else {
8385 /* No way, we need to wait for the next BGSAVE in order to
8386 * register differences */
8387 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
8388 redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
8389 }
8390 } else {
8391 /* Ok we don't have a BGSAVE in progress, let's start one */
8392 redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
8393 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
8394 redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE");
8395 addReplySds(c,sdsnew("-ERR Unalbe to perform background save\r\n"));
8396 return;
8397 }
8398 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
8399 }
6208b3a7 8400 c->repldbfd = -1;
40d224a9 8401 c->flags |= REDIS_SLAVE;
8402 c->slaveseldb = 0;
6b47e12e 8403 listAddNodeTail(server.slaves,c);
40d224a9 8404 return;
8405}
8406
6208b3a7 8407static void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
8408 redisClient *slave = privdata;
8409 REDIS_NOTUSED(el);
8410 REDIS_NOTUSED(mask);
8411 char buf[REDIS_IOBUF_LEN];
8412 ssize_t nwritten, buflen;
8413
8414 if (slave->repldboff == 0) {
8415 /* Write the bulk write count before to transfer the DB. In theory here
8416 * we don't know how much room there is in the output buffer of the
8417 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
8418 * operations) will never be smaller than the few bytes we need. */
8419 sds bulkcount;
8420
8421 bulkcount = sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
8422 slave->repldbsize);
8423 if (write(fd,bulkcount,sdslen(bulkcount)) != (signed)sdslen(bulkcount))
8424 {
8425 sdsfree(bulkcount);
8426 freeClient(slave);
8427 return;
8428 }
8429 sdsfree(bulkcount);
8430 }
8431 lseek(slave->repldbfd,slave->repldboff,SEEK_SET);
8432 buflen = read(slave->repldbfd,buf,REDIS_IOBUF_LEN);
8433 if (buflen <= 0) {
8434 redisLog(REDIS_WARNING,"Read error sending DB to slave: %s",
8435 (buflen == 0) ? "premature EOF" : strerror(errno));
8436 freeClient(slave);
8437 return;
8438 }
8439 if ((nwritten = write(fd,buf,buflen)) == -1) {
f870935d 8440 redisLog(REDIS_VERBOSE,"Write error sending DB to slave: %s",
6208b3a7 8441 strerror(errno));
8442 freeClient(slave);
8443 return;
8444 }
8445 slave->repldboff += nwritten;
8446 if (slave->repldboff == slave->repldbsize) {
8447 close(slave->repldbfd);
8448 slave->repldbfd = -1;
8449 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
8450 slave->replstate = REDIS_REPL_ONLINE;
8451 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
266373b2 8452 sendReplyToClient, slave) == AE_ERR) {
6208b3a7 8453 freeClient(slave);
8454 return;
8455 }
8456 addReplySds(slave,sdsempty());
8457 redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
8458 }
8459}
ed9b544e 8460
a3b21203 8461/* This function is called at the end of every backgrond saving.
8462 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
8463 * otherwise REDIS_ERR is passed to the function.
8464 *
8465 * The goal of this function is to handle slaves waiting for a successful
8466 * background saving in order to perform non-blocking synchronization. */
8467static void updateSlavesWaitingBgsave(int bgsaveerr) {
6208b3a7 8468 listNode *ln;
8469 int startbgsave = 0;
c7df85a4 8470 listIter li;
ed9b544e 8471
c7df85a4 8472 listRewind(server.slaves,&li);
8473 while((ln = listNext(&li))) {
6208b3a7 8474 redisClient *slave = ln->value;
ed9b544e 8475
6208b3a7 8476 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) {
8477 startbgsave = 1;
8478 slave->replstate = REDIS_REPL_WAIT_BGSAVE_END;
8479 } else if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
dde65f3f 8480 struct redis_stat buf;
e0a62c7f 8481
6208b3a7 8482 if (bgsaveerr != REDIS_OK) {
8483 freeClient(slave);
8484 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE child returned an error");
8485 continue;
8486 }
8487 if ((slave->repldbfd = open(server.dbfilename,O_RDONLY)) == -1 ||
dde65f3f 8488 redis_fstat(slave->repldbfd,&buf) == -1) {
6208b3a7 8489 freeClient(slave);
8490 redisLog(REDIS_WARNING,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno));
8491 continue;
8492 }
8493 slave->repldboff = 0;
8494 slave->repldbsize = buf.st_size;
8495 slave->replstate = REDIS_REPL_SEND_BULK;
8496 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
266373b2 8497 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE, sendBulkToSlave, slave) == AE_ERR) {
6208b3a7 8498 freeClient(slave);
8499 continue;
8500 }
8501 }
ed9b544e 8502 }
6208b3a7 8503 if (startbgsave) {
8504 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
c7df85a4 8505 listIter li;
8506
8507 listRewind(server.slaves,&li);
6208b3a7 8508 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE failed");
c7df85a4 8509 while((ln = listNext(&li))) {
6208b3a7 8510 redisClient *slave = ln->value;
ed9b544e 8511
6208b3a7 8512 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START)
8513 freeClient(slave);
8514 }
8515 }
8516 }
ed9b544e 8517}
8518
8519static int syncWithMaster(void) {
d0ccebcf 8520 char buf[1024], tmpfile[256], authcmd[1024];
18e61fa2 8521 long dumpsize;
ed9b544e 8522 int fd = anetTcpConnect(NULL,server.masterhost,server.masterport);
8c5abee8 8523 int dfd, maxtries = 5;
ed9b544e 8524
8525 if (fd == -1) {
8526 redisLog(REDIS_WARNING,"Unable to connect to MASTER: %s",
8527 strerror(errno));
8528 return REDIS_ERR;
8529 }
d0ccebcf 8530
8531 /* AUTH with the master if required. */
8532 if(server.masterauth) {
8533 snprintf(authcmd, 1024, "AUTH %s\r\n", server.masterauth);
8534 if (syncWrite(fd, authcmd, strlen(server.masterauth)+7, 5) == -1) {
8535 close(fd);
8536 redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",
8537 strerror(errno));
8538 return REDIS_ERR;
8539 }
8540 /* Read the AUTH result. */
8541 if (syncReadLine(fd,buf,1024,3600) == -1) {
8542 close(fd);
8543 redisLog(REDIS_WARNING,"I/O error reading auth result from MASTER: %s",
8544 strerror(errno));
8545 return REDIS_ERR;
8546 }
8547 if (buf[0] != '+') {
8548 close(fd);
8549 redisLog(REDIS_WARNING,"Cannot AUTH to MASTER, is the masterauth password correct?");
8550 return REDIS_ERR;
8551 }
8552 }
8553
ed9b544e 8554 /* Issue the SYNC command */
8555 if (syncWrite(fd,"SYNC \r\n",7,5) == -1) {
8556 close(fd);
8557 redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
8558 strerror(errno));
8559 return REDIS_ERR;
8560 }
8561 /* Read the bulk write count */
8c4d91fc 8562 if (syncReadLine(fd,buf,1024,3600) == -1) {
ed9b544e 8563 close(fd);
8564 redisLog(REDIS_WARNING,"I/O error reading bulk count from MASTER: %s",
8565 strerror(errno));
8566 return REDIS_ERR;
8567 }
4aa701c1 8568 if (buf[0] != '$') {
8569 close(fd);
8570 redisLog(REDIS_WARNING,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
8571 return REDIS_ERR;
8572 }
18e61fa2 8573 dumpsize = strtol(buf+1,NULL,10);
8574 redisLog(REDIS_NOTICE,"Receiving %ld bytes data dump from MASTER",dumpsize);
ed9b544e 8575 /* Read the bulk write data on a temp file */
8c5abee8 8576 while(maxtries--) {
8577 snprintf(tmpfile,256,
8578 "temp-%d.%ld.rdb",(int)time(NULL),(long int)getpid());
8579 dfd = open(tmpfile,O_CREAT|O_WRONLY|O_EXCL,0644);
8580 if (dfd != -1) break;
5de9ad7c 8581 sleep(1);
8c5abee8 8582 }
ed9b544e 8583 if (dfd == -1) {
8584 close(fd);
8585 redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
8586 return REDIS_ERR;
8587 }
8588 while(dumpsize) {
8589 int nread, nwritten;
8590
8591 nread = read(fd,buf,(dumpsize < 1024)?dumpsize:1024);
8592 if (nread == -1) {
8593 redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
8594 strerror(errno));
8595 close(fd);
8596 close(dfd);
8597 return REDIS_ERR;
8598 }
8599 nwritten = write(dfd,buf,nread);
8600 if (nwritten == -1) {
8601 redisLog(REDIS_WARNING,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
8602 close(fd);
8603 close(dfd);
8604 return REDIS_ERR;
8605 }
8606 dumpsize -= nread;
8607 }
8608 close(dfd);
8609 if (rename(tmpfile,server.dbfilename) == -1) {
8610 redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
8611 unlink(tmpfile);
8612 close(fd);
8613 return REDIS_ERR;
8614 }
8615 emptyDb();
f78fd11b 8616 if (rdbLoad(server.dbfilename) != REDIS_OK) {
ed9b544e 8617 redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
8618 close(fd);
8619 return REDIS_ERR;
8620 }
8621 server.master = createClient(fd);
8622 server.master->flags |= REDIS_MASTER;
179b3952 8623 server.master->authenticated = 1;
ed9b544e 8624 server.replstate = REDIS_REPL_CONNECTED;
8625 return REDIS_OK;
8626}
8627
321b0e13 8628static void slaveofCommand(redisClient *c) {
8629 if (!strcasecmp(c->argv[1]->ptr,"no") &&
8630 !strcasecmp(c->argv[2]->ptr,"one")) {
8631 if (server.masterhost) {
8632 sdsfree(server.masterhost);
8633 server.masterhost = NULL;
8634 if (server.master) freeClient(server.master);
8635 server.replstate = REDIS_REPL_NONE;
8636 redisLog(REDIS_NOTICE,"MASTER MODE enabled (user request)");
8637 }
8638 } else {
8639 sdsfree(server.masterhost);
8640 server.masterhost = sdsdup(c->argv[1]->ptr);
8641 server.masterport = atoi(c->argv[2]->ptr);
8642 if (server.master) freeClient(server.master);
8643 server.replstate = REDIS_REPL_CONNECT;
8644 redisLog(REDIS_NOTICE,"SLAVE OF %s:%d enabled (user request)",
8645 server.masterhost, server.masterport);
8646 }
8647 addReply(c,shared.ok);
8648}
8649
3fd78bcd 8650/* ============================ Maxmemory directive ======================== */
8651
a5819310 8652/* Try to free one object form the pre-allocated objects free list.
8653 * This is useful under low mem conditions as by default we take 1 million
8654 * free objects allocated. On success REDIS_OK is returned, otherwise
8655 * REDIS_ERR. */
8656static int tryFreeOneObjectFromFreelist(void) {
f870935d 8657 robj *o;
8658
a5819310 8659 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
8660 if (listLength(server.objfreelist)) {
8661 listNode *head = listFirst(server.objfreelist);
8662 o = listNodeValue(head);
8663 listDelNode(server.objfreelist,head);
8664 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
8665 zfree(o);
8666 return REDIS_OK;
8667 } else {
8668 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
8669 return REDIS_ERR;
8670 }
f870935d 8671}
8672
3fd78bcd 8673/* This function gets called when 'maxmemory' is set on the config file to limit
8674 * the max memory used by the server, and we are out of memory.
8675 * This function will try to, in order:
8676 *
8677 * - Free objects from the free list
8678 * - Try to remove keys with an EXPIRE set
8679 *
8680 * It is not possible to free enough memory to reach used-memory < maxmemory
8681 * the server will start refusing commands that will enlarge even more the
8682 * memory usage.
8683 */
8684static void freeMemoryIfNeeded(void) {
8685 while (server.maxmemory && zmalloc_used_memory() > server.maxmemory) {
a5819310 8686 int j, k, freed = 0;
8687
8688 if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
8689 for (j = 0; j < server.dbnum; j++) {
8690 int minttl = -1;
8691 robj *minkey = NULL;
8692 struct dictEntry *de;
8693
8694 if (dictSize(server.db[j].expires)) {
8695 freed = 1;
8696 /* From a sample of three keys drop the one nearest to
8697 * the natural expire */
8698 for (k = 0; k < 3; k++) {
8699 time_t t;
8700
8701 de = dictGetRandomKey(server.db[j].expires);
8702 t = (time_t) dictGetEntryVal(de);
8703 if (minttl == -1 || t < minttl) {
8704 minkey = dictGetEntryKey(de);
8705 minttl = t;
3fd78bcd 8706 }
3fd78bcd 8707 }
09241813 8708 dbDelete(server.db+j,minkey);
3fd78bcd 8709 }
3fd78bcd 8710 }
a5819310 8711 if (!freed) return; /* nothing to free... */
3fd78bcd 8712 }
8713}
8714
f80dff62 8715/* ============================== Append Only file ========================== */
8716
560db612 8717/* Called when the user switches from "appendonly yes" to "appendonly no"
8718 * at runtime using the CONFIG command. */
8719static void stopAppendOnly(void) {
8720 flushAppendOnlyFile();
8721 aof_fsync(server.appendfd);
8722 close(server.appendfd);
8723
8724 server.appendfd = -1;
8725 server.appendseldb = -1;
8726 server.appendonly = 0;
8727 /* rewrite operation in progress? kill it, wait child exit */
8728 if (server.bgsavechildpid != -1) {
8729 int statloc;
8730
8731 if (kill(server.bgsavechildpid,SIGKILL) != -1)
8732 wait3(&statloc,0,NULL);
8733 /* reset the buffer accumulating changes while the child saves */
8734 sdsfree(server.bgrewritebuf);
8735 server.bgrewritebuf = sdsempty();
8736 server.bgsavechildpid = -1;
8737 }
8738}
8739
8740/* Called when the user switches from "appendonly no" to "appendonly yes"
8741 * at runtime using the CONFIG command. */
8742static int startAppendOnly(void) {
8743 server.appendonly = 1;
8744 server.lastfsync = time(NULL);
8745 server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
8746 if (server.appendfd == -1) {
8747 redisLog(REDIS_WARNING,"Used tried to switch on AOF via CONFIG, but I can't open the AOF file: %s",strerror(errno));
8748 return REDIS_ERR;
8749 }
8750 if (rewriteAppendOnlyFileBackground() == REDIS_ERR) {
8751 server.appendonly = 0;
8752 close(server.appendfd);
8753 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));
8754 return REDIS_ERR;
8755 }
8756 return REDIS_OK;
8757}
8758
28ed1f33 8759/* Write the append only file buffer on disk.
8760 *
8761 * Since we are required to write the AOF before replying to the client,
8762 * and the only way the client socket can get a write is entering when the
8763 * the event loop, we accumulate all the AOF writes in a memory
8764 * buffer and write it on disk using this function just before entering
8765 * the event loop again. */
8766static void flushAppendOnlyFile(void) {
8767 time_t now;
8768 ssize_t nwritten;
8769
8770 if (sdslen(server.aofbuf) == 0) return;
8771
8772 /* We want to perform a single write. This should be guaranteed atomic
8773 * at least if the filesystem we are writing is a real physical one.
8774 * While this will save us against the server being killed I don't think
8775 * there is much to do about the whole server stopping for power problems
8776 * or alike */
8777 nwritten = write(server.appendfd,server.aofbuf,sdslen(server.aofbuf));
8778 if (nwritten != (signed)sdslen(server.aofbuf)) {
8779 /* Ooops, we are in troubles. The best thing to do for now is
8780 * aborting instead of giving the illusion that everything is
8781 * working as expected. */
8782 if (nwritten == -1) {
8783 redisLog(REDIS_WARNING,"Exiting on error writing to the append-only file: %s",strerror(errno));
8784 } else {
8785 redisLog(REDIS_WARNING,"Exiting on short write while writing to the append-only file: %s",strerror(errno));
8786 }
8787 exit(1);
8788 }
8789 sdsfree(server.aofbuf);
8790 server.aofbuf = sdsempty();
8791
38db9171 8792 /* Don't Fsync if no-appendfsync-on-rewrite is set to yes and we have
8793 * childs performing heavy I/O on disk. */
8794 if (server.no_appendfsync_on_rewrite &&
8795 (server.bgrewritechildpid != -1 || server.bgsavechildpid != -1))
8796 return;
28ed1f33 8797 /* Fsync if needed */
8798 now = time(NULL);
8799 if (server.appendfsync == APPENDFSYNC_ALWAYS ||
8800 (server.appendfsync == APPENDFSYNC_EVERYSEC &&
8801 now-server.lastfsync > 1))
8802 {
8803 /* aof_fsync is defined as fdatasync() for Linux in order to avoid
8804 * flushing metadata. */
8805 aof_fsync(server.appendfd); /* Let's try to get this data on the disk */
8806 server.lastfsync = now;
8807 }
8808}
8809
9376e434
PN
8810static sds catAppendOnlyGenericCommand(sds buf, int argc, robj **argv) {
8811 int j;
8812 buf = sdscatprintf(buf,"*%d\r\n",argc);
8813 for (j = 0; j < argc; j++) {
8814 robj *o = getDecodedObject(argv[j]);
8815 buf = sdscatprintf(buf,"$%lu\r\n",(unsigned long)sdslen(o->ptr));
8816 buf = sdscatlen(buf,o->ptr,sdslen(o->ptr));
8817 buf = sdscatlen(buf,"\r\n",2);
8818 decrRefCount(o);
8819 }
8820 return buf;
8821}
8822
8823static sds catAppendOnlyExpireAtCommand(sds buf, robj *key, robj *seconds) {
8824 int argc = 3;
8825 long when;
8826 robj *argv[3];
8827
8828 /* Make sure we can use strtol */
8829 seconds = getDecodedObject(seconds);
8830 when = time(NULL)+strtol(seconds->ptr,NULL,10);
8831 decrRefCount(seconds);
8832
8833 argv[0] = createStringObject("EXPIREAT",8);
8834 argv[1] = key;
8835 argv[2] = createObject(REDIS_STRING,
8836 sdscatprintf(sdsempty(),"%ld",when));
8837 buf = catAppendOnlyGenericCommand(buf, argc, argv);
8838 decrRefCount(argv[0]);
8839 decrRefCount(argv[2]);
8840 return buf;
8841}
8842
f80dff62 8843static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {
8844 sds buf = sdsempty();
f80dff62 8845 robj *tmpargv[3];
8846
8847 /* The DB this command was targetting is not the same as the last command
8848 * we appendend. To issue a SELECT command is needed. */
8849 if (dictid != server.appendseldb) {
8850 char seldb[64];
8851
8852 snprintf(seldb,sizeof(seldb),"%d",dictid);
682ac724 8853 buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
83c6a618 8854 (unsigned long)strlen(seldb),seldb);
f80dff62 8855 server.appendseldb = dictid;
8856 }
8857
f80dff62 8858 if (cmd->proc == expireCommand) {
9376e434
PN
8859 /* Translate EXPIRE into EXPIREAT */
8860 buf = catAppendOnlyExpireAtCommand(buf,argv[1],argv[2]);
8861 } else if (cmd->proc == setexCommand) {
8862 /* Translate SETEX to SET and EXPIREAT */
8863 tmpargv[0] = createStringObject("SET",3);
f80dff62 8864 tmpargv[1] = argv[1];
9376e434
PN
8865 tmpargv[2] = argv[3];
8866 buf = catAppendOnlyGenericCommand(buf,3,tmpargv);
8867 decrRefCount(tmpargv[0]);
8868 buf = catAppendOnlyExpireAtCommand(buf,argv[1],argv[2]);
8869 } else {
8870 buf = catAppendOnlyGenericCommand(buf,argc,argv);
f80dff62 8871 }
8872
28ed1f33 8873 /* Append to the AOF buffer. This will be flushed on disk just before
8874 * of re-entering the event loop, so before the client will get a
8875 * positive reply about the operation performed. */
8876 server.aofbuf = sdscatlen(server.aofbuf,buf,sdslen(buf));
8877
85a83172 8878 /* If a background append only file rewriting is in progress we want to
8879 * accumulate the differences between the child DB and the current one
8880 * in a buffer, so that when the child process will do its work we
8881 * can append the differences to the new append only file. */
8882 if (server.bgrewritechildpid != -1)
8883 server.bgrewritebuf = sdscatlen(server.bgrewritebuf,buf,sdslen(buf));
8884
8885 sdsfree(buf);
f80dff62 8886}
8887
8888/* In Redis commands are always executed in the context of a client, so in
8889 * order to load the append only file we need to create a fake client. */
8890static struct redisClient *createFakeClient(void) {
8891 struct redisClient *c = zmalloc(sizeof(*c));
8892
8893 selectDb(c,0);
8894 c->fd = -1;
8895 c->querybuf = sdsempty();
8896 c->argc = 0;
8897 c->argv = NULL;
8898 c->flags = 0;
9387d17d 8899 /* We set the fake client as a slave waiting for the synchronization
8900 * so that Redis will not try to send replies to this client. */
8901 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
f80dff62 8902 c->reply = listCreate();
8903 listSetFreeMethod(c->reply,decrRefCount);
8904 listSetDupMethod(c->reply,dupClientReplyValue);
4132ad8d 8905 initClientMultiState(c);
f80dff62 8906 return c;
8907}
8908
8909static void freeFakeClient(struct redisClient *c) {
8910 sdsfree(c->querybuf);
8911 listRelease(c->reply);
4132ad8d 8912 freeClientMultiState(c);
f80dff62 8913 zfree(c);
8914}
8915
8916/* Replay the append log file. On error REDIS_OK is returned. On non fatal
8917 * error (the append only file is zero-length) REDIS_ERR is returned. On
8918 * fatal error an error message is logged and the program exists. */
8919int loadAppendOnlyFile(char *filename) {
8920 struct redisClient *fakeClient;
8921 FILE *fp = fopen(filename,"r");
8922 struct redis_stat sb;
4132ad8d 8923 int appendonly = server.appendonly;
f80dff62 8924
8925 if (redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0)
8926 return REDIS_ERR;
8927
8928 if (fp == NULL) {
8929 redisLog(REDIS_WARNING,"Fatal error: can't open the append log file for reading: %s",strerror(errno));
8930 exit(1);
8931 }
8932
4132ad8d
PN
8933 /* Temporarily disable AOF, to prevent EXEC from feeding a MULTI
8934 * to the same file we're about to read. */
8935 server.appendonly = 0;
8936
f80dff62 8937 fakeClient = createFakeClient();
8938 while(1) {
8939 int argc, j;
8940 unsigned long len;
8941 robj **argv;
8942 char buf[128];
8943 sds argsds;
8944 struct redisCommand *cmd;
a89b7013 8945 int force_swapout;
f80dff62 8946
8947 if (fgets(buf,sizeof(buf),fp) == NULL) {
8948 if (feof(fp))
8949 break;
8950 else
8951 goto readerr;
8952 }
8953 if (buf[0] != '*') goto fmterr;
8954 argc = atoi(buf+1);
8955 argv = zmalloc(sizeof(robj*)*argc);
8956 for (j = 0; j < argc; j++) {
8957 if (fgets(buf,sizeof(buf),fp) == NULL) goto readerr;
8958 if (buf[0] != '$') goto fmterr;
8959 len = strtol(buf+1,NULL,10);
8960 argsds = sdsnewlen(NULL,len);
0f151ef1 8961 if (len && fread(argsds,len,1,fp) == 0) goto fmterr;
f80dff62 8962 argv[j] = createObject(REDIS_STRING,argsds);
8963 if (fread(buf,2,1,fp) == 0) goto fmterr; /* discard CRLF */
8964 }
8965
8966 /* Command lookup */
8967 cmd = lookupCommand(argv[0]->ptr);
8968 if (!cmd) {
8969 redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", argv[0]->ptr);
8970 exit(1);
8971 }
bdcb92f2 8972 /* Try object encoding */
f80dff62 8973 if (cmd->flags & REDIS_CMD_BULK)
05df7621 8974 argv[argc-1] = tryObjectEncoding(argv[argc-1]);
f80dff62 8975 /* Run the command in the context of a fake client */
8976 fakeClient->argc = argc;
8977 fakeClient->argv = argv;
8978 cmd->proc(fakeClient);
8979 /* Discard the reply objects list from the fake client */
8980 while(listLength(fakeClient->reply))
8981 listDelNode(fakeClient->reply,listFirst(fakeClient->reply));
8982 /* Clean up, ready for the next command */
8983 for (j = 0; j < argc; j++) decrRefCount(argv[j]);
8984 zfree(argv);
b492cf00 8985 /* Handle swapping while loading big datasets when VM is on */
a89b7013 8986 force_swapout = 0;
8987 if ((zmalloc_used_memory() - server.vm_max_memory) > 1024*1024*32)
8988 force_swapout = 1;
8989
8990 if (server.vm_enabled && force_swapout) {
b492cf00 8991 while (zmalloc_used_memory() > server.vm_max_memory) {
a69a0c9c 8992 if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
b492cf00 8993 }
8994 }
f80dff62 8995 }
4132ad8d
PN
8996
8997 /* This point can only be reached when EOF is reached without errors.
8998 * If the client is in the middle of a MULTI/EXEC, log error and quit. */
8999 if (fakeClient->flags & REDIS_MULTI) goto readerr;
9000
f80dff62 9001 fclose(fp);
9002 freeFakeClient(fakeClient);
4132ad8d 9003 server.appendonly = appendonly;
f80dff62 9004 return REDIS_OK;
9005
9006readerr:
9007 if (feof(fp)) {
9008 redisLog(REDIS_WARNING,"Unexpected end of file reading the append only file");
9009 } else {
9010 redisLog(REDIS_WARNING,"Unrecoverable error reading the append only file: %s", strerror(errno));
9011 }
9012 exit(1);
9013fmterr:
9014 redisLog(REDIS_WARNING,"Bad file format reading the append only file");
9015 exit(1);
9016}
9017
9c8e3cee 9018/* Write binary-safe string into a file in the bulkformat
9019 * $<count>\r\n<payload>\r\n */
9020static int fwriteBulkString(FILE *fp, char *s, unsigned long len) {
9eaef89f
PN
9021 char cbuf[128];
9022 int clen;
9023 cbuf[0] = '$';
9024 clen = 1+ll2string(cbuf+1,sizeof(cbuf)-1,len);
9025 cbuf[clen++] = '\r';
9026 cbuf[clen++] = '\n';
9027 if (fwrite(cbuf,clen,1,fp) == 0) return 0;
9028 if (len > 0 && fwrite(s,len,1,fp) == 0) return 0;
9c8e3cee 9029 if (fwrite("\r\n",2,1,fp) == 0) return 0;
9030 return 1;
9031}
9032
9d65a1bb 9033/* Write a double value in bulk format $<count>\r\n<payload>\r\n */
9034static int fwriteBulkDouble(FILE *fp, double d) {
9035 char buf[128], dbuf[128];
9036
9037 snprintf(dbuf,sizeof(dbuf),"%.17g\r\n",d);
9038 snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(dbuf)-2);
9039 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
9040 if (fwrite(dbuf,strlen(dbuf),1,fp) == 0) return 0;
9041 return 1;
9042}
9043
9044/* Write a long value in bulk format $<count>\r\n<payload>\r\n */
9eaef89f
PN
9045static int fwriteBulkLongLong(FILE *fp, long long l) {
9046 char bbuf[128], lbuf[128];
9047 unsigned int blen, llen;
9048 llen = ll2string(lbuf,32,l);
9049 blen = snprintf(bbuf,sizeof(bbuf),"$%u\r\n%s\r\n",llen,lbuf);
9050 if (fwrite(bbuf,blen,1,fp) == 0) return 0;
9d65a1bb 9051 return 1;
9052}
9053
9eaef89f
PN
9054/* Delegate writing an object to writing a bulk string or bulk long long. */
9055static int fwriteBulkObject(FILE *fp, robj *obj) {
9056 /* Avoid using getDecodedObject to help copy-on-write (we are often
9057 * in a child process when this function is called). */
9058 if (obj->encoding == REDIS_ENCODING_INT) {
9059 return fwriteBulkLongLong(fp,(long)obj->ptr);
9060 } else if (obj->encoding == REDIS_ENCODING_RAW) {
9061 return fwriteBulkString(fp,obj->ptr,sdslen(obj->ptr));
9062 } else {
9063 redisPanic("Unknown string encoding");
9064 }
9065}
9066
9d65a1bb 9067/* Write a sequence of commands able to fully rebuild the dataset into
9068 * "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
9069static int rewriteAppendOnlyFile(char *filename) {
9070 dictIterator *di = NULL;
9071 dictEntry *de;
9072 FILE *fp;
9073 char tmpfile[256];
9074 int j;
9075 time_t now = time(NULL);
9076
9077 /* Note that we have to use a different temp name here compared to the
9078 * one used by rewriteAppendOnlyFileBackground() function. */
9079 snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid());
9080 fp = fopen(tmpfile,"w");
9081 if (!fp) {
9082 redisLog(REDIS_WARNING, "Failed rewriting the append only file: %s", strerror(errno));
9083 return REDIS_ERR;
9084 }
9085 for (j = 0; j < server.dbnum; j++) {
9086 char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n";
9087 redisDb *db = server.db+j;
9088 dict *d = db->dict;
9089 if (dictSize(d) == 0) continue;
9090 di = dictGetIterator(d);
9091 if (!di) {
9092 fclose(fp);
9093 return REDIS_ERR;
9094 }
9095
9096 /* SELECT the new DB */
9097 if (fwrite(selectcmd,sizeof(selectcmd)-1,1,fp) == 0) goto werr;
9eaef89f 9098 if (fwriteBulkLongLong(fp,j) == 0) goto werr;
9d65a1bb 9099
9100 /* Iterate this DB writing every entry */
9101 while((de = dictNext(di)) != NULL) {
09241813 9102 sds keystr = dictGetEntryKey(de);
9103 robj key, *o;
e7546c63 9104 time_t expiretime;
9105 int swapped;
9106
09241813 9107 keystr = dictGetEntryKey(de);
560db612 9108 o = dictGetEntryVal(de);
09241813 9109 initStaticStringObject(key,keystr);
b9bc0eef 9110 /* If the value for this key is swapped, load a preview in memory.
9111 * We use a "swapped" flag to remember if we need to free the
9112 * value object instead to just increment the ref count anyway
9113 * in order to avoid copy-on-write of pages if we are forked() */
560db612 9114 if (!server.vm_enabled || o->storage == REDIS_VM_MEMORY ||
9115 o->storage == REDIS_VM_SWAPPING) {
e7546c63 9116 swapped = 0;
9117 } else {
560db612 9118 o = vmPreviewObject(o);
e7546c63 9119 swapped = 1;
9120 }
09241813 9121 expiretime = getExpire(db,&key);
9d65a1bb 9122
9123 /* Save the key and associated value */
9d65a1bb 9124 if (o->type == REDIS_STRING) {
9125 /* Emit a SET command */
9126 char cmd[]="*3\r\n$3\r\nSET\r\n";
9127 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
9128 /* Key and value */
09241813 9129 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9130 if (fwriteBulkObject(fp,o) == 0) goto werr;
9d65a1bb 9131 } else if (o->type == REDIS_LIST) {
9132 /* Emit the RPUSHes needed to rebuild the list */
6ddc908a
PN
9133 char cmd[]="*3\r\n$5\r\nRPUSH\r\n";
9134 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
9135 unsigned char *zl = o->ptr;
9136 unsigned char *p = ziplistIndex(zl,0);
9137 unsigned char *vstr;
9138 unsigned int vlen;
9139 long long vlong;
9140
9141 while(ziplistGet(p,&vstr,&vlen,&vlong)) {
9142 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
846d8b3e 9143 if (fwriteBulkObject(fp,&key) == 0) goto werr;
6ddc908a
PN
9144 if (vstr) {
9145 if (fwriteBulkString(fp,(char*)vstr,vlen) == 0)
9146 goto werr;
9147 } else {
9148 if (fwriteBulkLongLong(fp,vlong) == 0)
9149 goto werr;
9150 }
9151 p = ziplistNext(zl,p);
9152 }
7e79de54 9153 } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
6ddc908a
PN
9154 list *list = o->ptr;
9155 listNode *ln;
9156 listIter li;
9157
9158 listRewind(list,&li);
9159 while((ln = listNext(&li))) {
9160 robj *eleobj = listNodeValue(ln);
9161
9162 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
846d8b3e 9163 if (fwriteBulkObject(fp,&key) == 0) goto werr;
6ddc908a
PN
9164 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
9165 }
9166 } else {
9167 redisPanic("Unknown list encoding");
9d65a1bb 9168 }
9169 } else if (o->type == REDIS_SET) {
9170 /* Emit the SADDs needed to rebuild the set */
9171 dict *set = o->ptr;
9172 dictIterator *di = dictGetIterator(set);
9173 dictEntry *de;
9174
9175 while((de = dictNext(di)) != NULL) {
9176 char cmd[]="*3\r\n$4\r\nSADD\r\n";
9177 robj *eleobj = dictGetEntryKey(de);
9178
9179 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9180 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9181 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
9d65a1bb 9182 }
9183 dictReleaseIterator(di);
9184 } else if (o->type == REDIS_ZSET) {
9185 /* Emit the ZADDs needed to rebuild the sorted set */
9186 zset *zs = o->ptr;
9187 dictIterator *di = dictGetIterator(zs->dict);
9188 dictEntry *de;
9189
9190 while((de = dictNext(di)) != NULL) {
9191 char cmd[]="*4\r\n$4\r\nZADD\r\n";
9192 robj *eleobj = dictGetEntryKey(de);
9193 double *score = dictGetEntryVal(de);
9194
9195 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9196 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9d65a1bb 9197 if (fwriteBulkDouble(fp,*score) == 0) goto werr;
9c8e3cee 9198 if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
9d65a1bb 9199 }
9200 dictReleaseIterator(di);
9c8e3cee 9201 } else if (o->type == REDIS_HASH) {
9202 char cmd[]="*4\r\n$4\r\nHSET\r\n";
9203
9204 /* Emit the HSETs needed to rebuild the hash */
9205 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
9206 unsigned char *p = zipmapRewind(o->ptr);
9207 unsigned char *field, *val;
9208 unsigned int flen, vlen;
9209
9210 while((p = zipmapNext(p,&field,&flen,&val,&vlen)) != NULL) {
9211 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9212 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9213 if (fwriteBulkString(fp,(char*)field,flen) == -1)
9214 return -1;
9215 if (fwriteBulkString(fp,(char*)val,vlen) == -1)
9216 return -1;
9217 }
9218 } else {
9219 dictIterator *di = dictGetIterator(o->ptr);
9220 dictEntry *de;
9221
9222 while((de = dictNext(di)) != NULL) {
9223 robj *field = dictGetEntryKey(de);
9224 robj *val = dictGetEntryVal(de);
9225
9226 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9227 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9c8e3cee 9228 if (fwriteBulkObject(fp,field) == -1) return -1;
9229 if (fwriteBulkObject(fp,val) == -1) return -1;
9230 }
9231 dictReleaseIterator(di);
9232 }
9d65a1bb 9233 } else {
f83c6cb5 9234 redisPanic("Unknown object type");
9d65a1bb 9235 }
9236 /* Save the expire time */
9237 if (expiretime != -1) {
e96e4fbf 9238 char cmd[]="*3\r\n$8\r\nEXPIREAT\r\n";
9d65a1bb 9239 /* If this key is already expired skip it */
9240 if (expiretime < now) continue;
9241 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
09241813 9242 if (fwriteBulkObject(fp,&key) == 0) goto werr;
9eaef89f 9243 if (fwriteBulkLongLong(fp,expiretime) == 0) goto werr;
9d65a1bb 9244 }
b9bc0eef 9245 if (swapped) decrRefCount(o);
9d65a1bb 9246 }
9247 dictReleaseIterator(di);
9248 }
9249
9250 /* Make sure data will not remain on the OS's output buffers */
9251 fflush(fp);
b0bd87f6 9252 aof_fsync(fileno(fp));
9d65a1bb 9253 fclose(fp);
e0a62c7f 9254
9d65a1bb 9255 /* Use RENAME to make sure the DB file is changed atomically only
9256 * if the generate DB file is ok. */
9257 if (rename(tmpfile,filename) == -1) {
9258 redisLog(REDIS_WARNING,"Error moving temp append only file on the final destination: %s", strerror(errno));
9259 unlink(tmpfile);
9260 return REDIS_ERR;
9261 }
9262 redisLog(REDIS_NOTICE,"SYNC append only file rewrite performed");
9263 return REDIS_OK;
9264
9265werr:
9266 fclose(fp);
9267 unlink(tmpfile);
e96e4fbf 9268 redisLog(REDIS_WARNING,"Write error writing append only file on disk: %s", strerror(errno));
9d65a1bb 9269 if (di) dictReleaseIterator(di);
9270 return REDIS_ERR;
9271}
9272
9273/* This is how rewriting of the append only file in background works:
9274 *
9275 * 1) The user calls BGREWRITEAOF
9276 * 2) Redis calls this function, that forks():
9277 * 2a) the child rewrite the append only file in a temp file.
9278 * 2b) the parent accumulates differences in server.bgrewritebuf.
9279 * 3) When the child finished '2a' exists.
9280 * 4) The parent will trap the exit code, if it's OK, will append the
9281 * data accumulated into server.bgrewritebuf into the temp file, and
9282 * finally will rename(2) the temp file in the actual file name.
9283 * The the new file is reopened as the new append only file. Profit!
9284 */
9285static int rewriteAppendOnlyFileBackground(void) {
9286 pid_t childpid;
9287
9288 if (server.bgrewritechildpid != -1) return REDIS_ERR;
054e426d 9289 if (server.vm_enabled) waitEmptyIOJobsQueue();
9d65a1bb 9290 if ((childpid = fork()) == 0) {
9291 /* Child */
9292 char tmpfile[256];
9d65a1bb 9293
054e426d 9294 if (server.vm_enabled) vmReopenSwapFile();
9295 close(server.fd);
9d65a1bb 9296 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
9297 if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
478c2c6f 9298 _exit(0);
9d65a1bb 9299 } else {
478c2c6f 9300 _exit(1);
9d65a1bb 9301 }
9302 } else {
9303 /* Parent */
9304 if (childpid == -1) {
9305 redisLog(REDIS_WARNING,
9306 "Can't rewrite append only file in background: fork: %s",
9307 strerror(errno));
9308 return REDIS_ERR;
9309 }
9310 redisLog(REDIS_NOTICE,
9311 "Background append only file rewriting started by pid %d",childpid);
9312 server.bgrewritechildpid = childpid;
884d4b39 9313 updateDictResizePolicy();
85a83172 9314 /* We set appendseldb to -1 in order to force the next call to the
9315 * feedAppendOnlyFile() to issue a SELECT command, so the differences
9316 * accumulated by the parent into server.bgrewritebuf will start
9317 * with a SELECT statement and it will be safe to merge. */
9318 server.appendseldb = -1;
9d65a1bb 9319 return REDIS_OK;
9320 }
9321 return REDIS_OK; /* unreached */
9322}
9323
9324static void bgrewriteaofCommand(redisClient *c) {
9325 if (server.bgrewritechildpid != -1) {
9326 addReplySds(c,sdsnew("-ERR background append only file rewriting already in progress\r\n"));
9327 return;
9328 }
9329 if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
49b99ab4 9330 char *status = "+Background append only file rewriting started\r\n";
9331 addReplySds(c,sdsnew(status));
9d65a1bb 9332 } else {
9333 addReply(c,shared.err);
9334 }
9335}
9336
9337static void aofRemoveTempFile(pid_t childpid) {
9338 char tmpfile[256];
9339
9340 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) childpid);
9341 unlink(tmpfile);
9342}
9343
996cb5f7 9344/* Virtual Memory is composed mainly of two subsystems:
9345 * - Blocking Virutal Memory
9346 * - Threaded Virtual Memory I/O
9347 * The two parts are not fully decoupled, but functions are split among two
9348 * different sections of the source code (delimited by comments) in order to
9349 * make more clear what functionality is about the blocking VM and what about
9350 * the threaded (not blocking) VM.
9351 *
9352 * Redis VM design:
9353 *
9354 * Redis VM is a blocking VM (one that blocks reading swapped values from
9355 * disk into memory when a value swapped out is needed in memory) that is made
9356 * unblocking by trying to examine the command argument vector in order to
9357 * load in background values that will likely be needed in order to exec
9358 * the command. The command is executed only once all the relevant keys
9359 * are loaded into memory.
9360 *
9361 * This basically is almost as simple of a blocking VM, but almost as parallel
9362 * as a fully non-blocking VM.
9363 */
9364
560db612 9365/* =================== Virtual Memory - Blocking Side ====================== */
2e5eb04e 9366
560db612 9367/* Create a VM pointer object. This kind of objects are used in place of
9368 * values in the key -> value hash table, for swapped out objects. */
9369static vmpointer *createVmPointer(int vtype) {
9370 vmpointer *vp = zmalloc(sizeof(vmpointer));
2e5eb04e 9371
560db612 9372 vp->type = REDIS_VMPOINTER;
9373 vp->storage = REDIS_VM_SWAPPED;
9374 vp->vtype = vtype;
9375 return vp;
2e5eb04e 9376}
9377
75680a3c 9378static void vmInit(void) {
9379 off_t totsize;
996cb5f7 9380 int pipefds[2];
bcaa7a4f 9381 size_t stacksize;
8b5bb414 9382 struct flock fl;
75680a3c 9383
4ad37480 9384 if (server.vm_max_threads != 0)
9385 zmalloc_enable_thread_safeness(); /* we need thread safe zmalloc() */
9386
054e426d 9387 redisLog(REDIS_NOTICE,"Using '%s' as swap file",server.vm_swap_file);
8b5bb414 9388 /* Try to open the old swap file, otherwise create it */
6fa987e3 9389 if ((server.vm_fp = fopen(server.vm_swap_file,"r+b")) == NULL) {
9390 server.vm_fp = fopen(server.vm_swap_file,"w+b");
9391 }
75680a3c 9392 if (server.vm_fp == NULL) {
6fa987e3 9393 redisLog(REDIS_WARNING,
8b5bb414 9394 "Can't open the swap file: %s. Exiting.",
6fa987e3 9395 strerror(errno));
75680a3c 9396 exit(1);
9397 }
9398 server.vm_fd = fileno(server.vm_fp);
8b5bb414 9399 /* Lock the swap file for writing, this is useful in order to avoid
9400 * another instance to use the same swap file for a config error. */
9401 fl.l_type = F_WRLCK;
9402 fl.l_whence = SEEK_SET;
9403 fl.l_start = fl.l_len = 0;
9404 if (fcntl(server.vm_fd,F_SETLK,&fl) == -1) {
9405 redisLog(REDIS_WARNING,
9406 "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));
9407 exit(1);
9408 }
9409 /* Initialize */
75680a3c 9410 server.vm_next_page = 0;
9411 server.vm_near_pages = 0;
7d98e08c 9412 server.vm_stats_used_pages = 0;
9413 server.vm_stats_swapped_objects = 0;
9414 server.vm_stats_swapouts = 0;
9415 server.vm_stats_swapins = 0;
75680a3c 9416 totsize = server.vm_pages*server.vm_page_size;
9417 redisLog(REDIS_NOTICE,"Allocating %lld bytes of swap file",totsize);
9418 if (ftruncate(server.vm_fd,totsize) == -1) {
9419 redisLog(REDIS_WARNING,"Can't ftruncate swap file: %s. Exiting.",
9420 strerror(errno));
9421 exit(1);
9422 } else {
9423 redisLog(REDIS_NOTICE,"Swap file allocated with success");
9424 }
7d30035d 9425 server.vm_bitmap = zmalloc((server.vm_pages+7)/8);
f870935d 9426 redisLog(REDIS_VERBOSE,"Allocated %lld bytes page table for %lld pages",
4ef8de8a 9427 (long long) (server.vm_pages+7)/8, server.vm_pages);
7d30035d 9428 memset(server.vm_bitmap,0,(server.vm_pages+7)/8);
92f8e882 9429
996cb5f7 9430 /* Initialize threaded I/O (used by Virtual Memory) */
9431 server.io_newjobs = listCreate();
9432 server.io_processing = listCreate();
9433 server.io_processed = listCreate();
d5d55fc3 9434 server.io_ready_clients = listCreate();
92f8e882 9435 pthread_mutex_init(&server.io_mutex,NULL);
a5819310 9436 pthread_mutex_init(&server.obj_freelist_mutex,NULL);
9437 pthread_mutex_init(&server.io_swapfile_mutex,NULL);
92f8e882 9438 server.io_active_threads = 0;
996cb5f7 9439 if (pipe(pipefds) == -1) {
9440 redisLog(REDIS_WARNING,"Unable to intialized VM: pipe(2): %s. Exiting."
9441 ,strerror(errno));
9442 exit(1);
9443 }
9444 server.io_ready_pipe_read = pipefds[0];
9445 server.io_ready_pipe_write = pipefds[1];
9446 redisAssert(anetNonBlock(NULL,server.io_ready_pipe_read) != ANET_ERR);
bcaa7a4f 9447 /* LZF requires a lot of stack */
9448 pthread_attr_init(&server.io_threads_attr);
9449 pthread_attr_getstacksize(&server.io_threads_attr, &stacksize);
9450 while (stacksize < REDIS_THREAD_STACK_SIZE) stacksize *= 2;
9451 pthread_attr_setstacksize(&server.io_threads_attr, stacksize);
b9bc0eef 9452 /* Listen for events in the threaded I/O pipe */
9453 if (aeCreateFileEvent(server.el, server.io_ready_pipe_read, AE_READABLE,
9454 vmThreadedIOCompletedJob, NULL) == AE_ERR)
9455 oom("creating file event");
75680a3c 9456}
9457
06224fec 9458/* Mark the page as used */
9459static void vmMarkPageUsed(off_t page) {
9460 off_t byte = page/8;
9461 int bit = page&7;
970e10bb 9462 redisAssert(vmFreePage(page) == 1);
06224fec 9463 server.vm_bitmap[byte] |= 1<<bit;
9464}
9465
9466/* Mark N contiguous pages as used, with 'page' being the first. */
9467static void vmMarkPagesUsed(off_t page, off_t count) {
9468 off_t j;
9469
9470 for (j = 0; j < count; j++)
7d30035d 9471 vmMarkPageUsed(page+j);
7d98e08c 9472 server.vm_stats_used_pages += count;
7c775e09 9473 redisLog(REDIS_DEBUG,"Mark USED pages: %lld pages at %lld\n",
9474 (long long)count, (long long)page);
06224fec 9475}
9476
9477/* Mark the page as free */
9478static void vmMarkPageFree(off_t page) {
9479 off_t byte = page/8;
9480 int bit = page&7;
970e10bb 9481 redisAssert(vmFreePage(page) == 0);
06224fec 9482 server.vm_bitmap[byte] &= ~(1<<bit);
9483}
9484
9485/* Mark N contiguous pages as free, with 'page' being the first. */
9486static void vmMarkPagesFree(off_t page, off_t count) {
9487 off_t j;
9488
9489 for (j = 0; j < count; j++)
7d30035d 9490 vmMarkPageFree(page+j);
7d98e08c 9491 server.vm_stats_used_pages -= count;
7c775e09 9492 redisLog(REDIS_DEBUG,"Mark FREE pages: %lld pages at %lld\n",
9493 (long long)count, (long long)page);
06224fec 9494}
9495
9496/* Test if the page is free */
9497static int vmFreePage(off_t page) {
9498 off_t byte = page/8;
9499 int bit = page&7;
7d30035d 9500 return (server.vm_bitmap[byte] & (1<<bit)) == 0;
06224fec 9501}
9502
9503/* Find N contiguous free pages storing the first page of the cluster in *first.
e0a62c7f 9504 * Returns REDIS_OK if it was able to find N contiguous pages, otherwise
3a66edc7 9505 * REDIS_ERR is returned.
06224fec 9506 *
9507 * This function uses a simple algorithm: we try to allocate
9508 * REDIS_VM_MAX_NEAR_PAGES sequentially, when we reach this limit we start
9509 * again from the start of the swap file searching for free spaces.
9510 *
9511 * If it looks pretty clear that there are no free pages near our offset
9512 * we try to find less populated places doing a forward jump of
9513 * REDIS_VM_MAX_RANDOM_JUMP, then we start scanning again a few pages
9514 * without hurry, and then we jump again and so forth...
e0a62c7f 9515 *
06224fec 9516 * This function can be improved using a free list to avoid to guess
9517 * too much, since we could collect data about freed pages.
9518 *
9519 * note: I implemented this function just after watching an episode of
9520 * Battlestar Galactica, where the hybrid was continuing to say "JUMP!"
9521 */
c7df85a4 9522static int vmFindContiguousPages(off_t *first, off_t n) {
06224fec 9523 off_t base, offset = 0, since_jump = 0, numfree = 0;
9524
9525 if (server.vm_near_pages == REDIS_VM_MAX_NEAR_PAGES) {
9526 server.vm_near_pages = 0;
9527 server.vm_next_page = 0;
9528 }
9529 server.vm_near_pages++; /* Yet another try for pages near to the old ones */
9530 base = server.vm_next_page;
9531
9532 while(offset < server.vm_pages) {
9533 off_t this = base+offset;
9534
9535 /* If we overflow, restart from page zero */
9536 if (this >= server.vm_pages) {
9537 this -= server.vm_pages;
9538 if (this == 0) {
9539 /* Just overflowed, what we found on tail is no longer
9540 * interesting, as it's no longer contiguous. */
9541 numfree = 0;
9542 }
9543 }
9544 if (vmFreePage(this)) {
9545 /* This is a free page */
9546 numfree++;
9547 /* Already got N free pages? Return to the caller, with success */
9548 if (numfree == n) {
7d30035d 9549 *first = this-(n-1);
9550 server.vm_next_page = this+1;
7c775e09 9551 redisLog(REDIS_DEBUG, "FOUND CONTIGUOUS PAGES: %lld pages at %lld\n", (long long) n, (long long) *first);
3a66edc7 9552 return REDIS_OK;
06224fec 9553 }
9554 } else {
9555 /* The current one is not a free page */
9556 numfree = 0;
9557 }
9558
9559 /* Fast-forward if the current page is not free and we already
9560 * searched enough near this place. */
9561 since_jump++;
9562 if (!numfree && since_jump >= REDIS_VM_MAX_RANDOM_JUMP/4) {
9563 offset += random() % REDIS_VM_MAX_RANDOM_JUMP;
9564 since_jump = 0;
9565 /* Note that even if we rewind after the jump, we are don't need
9566 * to make sure numfree is set to zero as we only jump *if* it
9567 * is set to zero. */
9568 } else {
9569 /* Otherwise just check the next page */
9570 offset++;
9571 }
9572 }
3a66edc7 9573 return REDIS_ERR;
9574}
9575
a5819310 9576/* Write the specified object at the specified page of the swap file */
9577static int vmWriteObjectOnSwap(robj *o, off_t page) {
9578 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
9579 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
9580 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
9581 redisLog(REDIS_WARNING,
9ebed7cf 9582 "Critical VM problem in vmWriteObjectOnSwap(): can't seek: %s",
a5819310 9583 strerror(errno));
9584 return REDIS_ERR;
9585 }
9586 rdbSaveObject(server.vm_fp,o);
ba76a8f9 9587 fflush(server.vm_fp);
a5819310 9588 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
9589 return REDIS_OK;
9590}
9591
a4798f73 9592/* Transfers the 'val' object to disk. Store all the information
9593 * a 'vmpointer' object containing all the information needed to load the
9594 * object back later is returned.
9595 *
3a66edc7 9596 * If we can't find enough contiguous empty pages to swap the object on disk
a4798f73 9597 * NULL is returned. */
560db612 9598static vmpointer *vmSwapObjectBlocking(robj *val) {
b9bc0eef 9599 off_t pages = rdbSavedObjectPages(val,NULL);
3a66edc7 9600 off_t page;
560db612 9601 vmpointer *vp;
3a66edc7 9602
560db612 9603 assert(val->storage == REDIS_VM_MEMORY);
9604 assert(val->refcount == 1);
9605 if (vmFindContiguousPages(&page,pages) == REDIS_ERR) return NULL;
9606 if (vmWriteObjectOnSwap(val,page) == REDIS_ERR) return NULL;
9607
9608 vp = createVmPointer(val->type);
9609 vp->page = page;
9610 vp->usedpages = pages;
3a66edc7 9611 decrRefCount(val); /* Deallocate the object from memory. */
9612 vmMarkPagesUsed(page,pages);
560db612 9613 redisLog(REDIS_DEBUG,"VM: object %p swapped out at %lld (%lld pages)",
9614 (void*) val,
7d30035d 9615 (unsigned long long) page, (unsigned long long) pages);
7d98e08c 9616 server.vm_stats_swapped_objects++;
9617 server.vm_stats_swapouts++;
560db612 9618 return vp;
3a66edc7 9619}
9620
a5819310 9621static robj *vmReadObjectFromSwap(off_t page, int type) {
9622 robj *o;
3a66edc7 9623
a5819310 9624 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
9625 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
3a66edc7 9626 redisLog(REDIS_WARNING,
d5d55fc3 9627 "Unrecoverable VM problem in vmReadObjectFromSwap(): can't seek: %s",
3a66edc7 9628 strerror(errno));
478c2c6f 9629 _exit(1);
3a66edc7 9630 }
a5819310 9631 o = rdbLoadObject(type,server.vm_fp);
9632 if (o == NULL) {
d5d55fc3 9633 redisLog(REDIS_WARNING, "Unrecoverable VM problem in vmReadObjectFromSwap(): can't load object from swap file: %s", strerror(errno));
478c2c6f 9634 _exit(1);
3a66edc7 9635 }
a5819310 9636 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
9637 return o;
9638}
9639
560db612 9640/* Load the specified object from swap to memory.
a5819310 9641 * The newly allocated object is returned.
9642 *
9643 * If preview is true the unserialized object is returned to the caller but
560db612 9644 * the pages are not marked as freed, nor the vp object is freed. */
9645static robj *vmGenericLoadObject(vmpointer *vp, int preview) {
a5819310 9646 robj *val;
9647
560db612 9648 redisAssert(vp->type == REDIS_VMPOINTER &&
9649 (vp->storage == REDIS_VM_SWAPPED || vp->storage == REDIS_VM_LOADING));
9650 val = vmReadObjectFromSwap(vp->page,vp->vtype);
7e69548d 9651 if (!preview) {
560db612 9652 redisLog(REDIS_DEBUG, "VM: object %p loaded from disk", (void*)vp);
9653 vmMarkPagesFree(vp->page,vp->usedpages);
9654 zfree(vp);
7d98e08c 9655 server.vm_stats_swapped_objects--;
38aba9a1 9656 } else {
560db612 9657 redisLog(REDIS_DEBUG, "VM: object %p previewed from disk", (void*)vp);
7e69548d 9658 }
7d98e08c 9659 server.vm_stats_swapins++;
3a66edc7 9660 return val;
06224fec 9661}
9662
560db612 9663/* Plain object loading, from swap to memory.
9664 *
9665 * 'o' is actually a redisVmPointer structure that will be freed by the call.
9666 * The return value is the loaded object. */
9667static robj *vmLoadObject(robj *o) {
996cb5f7 9668 /* If we are loading the object in background, stop it, we
9669 * need to load this object synchronously ASAP. */
560db612 9670 if (o->storage == REDIS_VM_LOADING)
9671 vmCancelThreadedIOJob(o);
9672 return vmGenericLoadObject((vmpointer*)o,0);
7e69548d 9673}
9674
9675/* Just load the value on disk, without to modify the key.
9676 * This is useful when we want to perform some operation on the value
9677 * without to really bring it from swap to memory, like while saving the
9678 * dataset or rewriting the append only log. */
560db612 9679static robj *vmPreviewObject(robj *o) {
9680 return vmGenericLoadObject((vmpointer*)o,1);
7e69548d 9681}
9682
4ef8de8a 9683/* How a good candidate is this object for swapping?
9684 * The better candidate it is, the greater the returned value.
9685 *
9686 * Currently we try to perform a fast estimation of the object size in
9687 * memory, and combine it with aging informations.
9688 *
9689 * Basically swappability = idle-time * log(estimated size)
9690 *
9691 * Bigger objects are preferred over smaller objects, but not
9692 * proportionally, this is why we use the logarithm. This algorithm is
9693 * just a first try and will probably be tuned later. */
9694static double computeObjectSwappability(robj *o) {
560db612 9695 /* actual age can be >= minage, but not < minage. As we use wrapping
9696 * 21 bit clocks with minutes resolution for the LRU. */
9697 time_t minage = abs(server.lruclock - o->lru);
4e16d8b3
PN
9698 long asize = 0, elesize;
9699 robj *ele;
4ef8de8a 9700 list *l;
4e16d8b3 9701 listNode *ln;
4ef8de8a 9702 dict *d;
9703 struct dictEntry *de;
9704 int z;
9705
560db612 9706 if (minage <= 0) return 0;
4ef8de8a 9707 switch(o->type) {
9708 case REDIS_STRING:
9709 if (o->encoding != REDIS_ENCODING_RAW) {
9710 asize = sizeof(*o);
9711 } else {
9712 asize = sdslen(o->ptr)+sizeof(*o)+sizeof(long)*2;
9713 }
9714 break;
9715 case REDIS_LIST:
4e16d8b3
PN
9716 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
9717 asize = sizeof(*o)+ziplistSize(o->ptr);
9718 } else {
9719 l = o->ptr;
9720 ln = listFirst(l);
9721 asize = sizeof(list);
9722 if (ln) {
9723 ele = ln->value;
9724 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
9725 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
9726 asize += (sizeof(listNode)+elesize)*listLength(l);
9727 }
4ef8de8a 9728 }
9729 break;
9730 case REDIS_SET:
9731 case REDIS_ZSET:
9732 z = (o->type == REDIS_ZSET);
9733 d = z ? ((zset*)o->ptr)->dict : o->ptr;
9734
9735 asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
9736 if (z) asize += sizeof(zset)-sizeof(dict);
9737 if (dictSize(d)) {
4ef8de8a 9738 de = dictGetRandomKey(d);
9739 ele = dictGetEntryKey(de);
9740 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
560db612 9741 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
4ef8de8a 9742 asize += (sizeof(struct dictEntry)+elesize)*dictSize(d);
9743 if (z) asize += sizeof(zskiplistNode)*dictSize(d);
9744 }
9745 break;
a97b9060 9746 case REDIS_HASH:
9747 if (o->encoding == REDIS_ENCODING_ZIPMAP) {
9748 unsigned char *p = zipmapRewind((unsigned char*)o->ptr);
9749 unsigned int len = zipmapLen((unsigned char*)o->ptr);
9750 unsigned int klen, vlen;
9751 unsigned char *key, *val;
9752
9753 if ((p = zipmapNext(p,&key,&klen,&val,&vlen)) == NULL) {
9754 klen = 0;
9755 vlen = 0;
9756 }
9757 asize = len*(klen+vlen+3);
9758 } else if (o->encoding == REDIS_ENCODING_HT) {
9759 d = o->ptr;
9760 asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
9761 if (dictSize(d)) {
a97b9060 9762 de = dictGetRandomKey(d);
9763 ele = dictGetEntryKey(de);
9764 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
560db612 9765 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
a97b9060 9766 ele = dictGetEntryVal(de);
9767 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
560db612 9768 (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o);
a97b9060 9769 asize += (sizeof(struct dictEntry)+elesize)*dictSize(d);
9770 }
9771 }
9772 break;
4ef8de8a 9773 }
560db612 9774 return (double)minage*log(1+asize);
4ef8de8a 9775}
9776
9777/* Try to swap an object that's a good candidate for swapping.
9778 * Returns REDIS_OK if the object was swapped, REDIS_ERR if it's not possible
a69a0c9c 9779 * to swap any object at all.
9780 *
9781 * If 'usethreaded' is true, Redis will try to swap the object in background
9782 * using I/O threads. */
9783static int vmSwapOneObject(int usethreads) {
4ef8de8a 9784 int j, i;
9785 struct dictEntry *best = NULL;
9786 double best_swappability = 0;
b9bc0eef 9787 redisDb *best_db = NULL;
44262c58 9788 robj *val;
9789 sds key;
4ef8de8a 9790
9791 for (j = 0; j < server.dbnum; j++) {
9792 redisDb *db = server.db+j;
b72f6a4b 9793 /* Why maxtries is set to 100?
9794 * Because this way (usually) we'll find 1 object even if just 1% - 2%
9795 * are swappable objects */
b0d8747d 9796 int maxtries = 100;
4ef8de8a 9797
9798 if (dictSize(db->dict) == 0) continue;
9799 for (i = 0; i < 5; i++) {
9800 dictEntry *de;
9801 double swappability;
9802
e3cadb8a 9803 if (maxtries) maxtries--;
4ef8de8a 9804 de = dictGetRandomKey(db->dict);
4ef8de8a 9805 val = dictGetEntryVal(de);
1064ef87 9806 /* Only swap objects that are currently in memory.
9807 *
560db612 9808 * Also don't swap shared objects: not a good idea in general and
9809 * we need to ensure that the main thread does not touch the
1064ef87 9810 * object while the I/O thread is using it, but we can't
9811 * control other keys without adding additional mutex. */
560db612 9812 if (val->storage != REDIS_VM_MEMORY || val->refcount != 1) {
e3cadb8a 9813 if (maxtries) i--; /* don't count this try */
9814 continue;
9815 }
4ef8de8a 9816 swappability = computeObjectSwappability(val);
9817 if (!best || swappability > best_swappability) {
9818 best = de;
9819 best_swappability = swappability;
b9bc0eef 9820 best_db = db;
4ef8de8a 9821 }
9822 }
9823 }
7c775e09 9824 if (best == NULL) return REDIS_ERR;
4ef8de8a 9825 key = dictGetEntryKey(best);
9826 val = dictGetEntryVal(best);
9827
e3cadb8a 9828 redisLog(REDIS_DEBUG,"Key with best swappability: %s, %f",
44262c58 9829 key, best_swappability);
4ef8de8a 9830
4ef8de8a 9831 /* Swap it */
a69a0c9c 9832 if (usethreads) {
4c8f2370 9833 robj *keyobj = createStringObject(key,sdslen(key));
9834 vmSwapObjectThreaded(keyobj,val,best_db);
9835 decrRefCount(keyobj);
4ef8de8a 9836 return REDIS_OK;
9837 } else {
560db612 9838 vmpointer *vp;
9839
9840 if ((vp = vmSwapObjectBlocking(val)) != NULL) {
9841 dictGetEntryVal(best) = vp;
a69a0c9c 9842 return REDIS_OK;
9843 } else {
9844 return REDIS_ERR;
9845 }
4ef8de8a 9846 }
9847}
9848
a69a0c9c 9849static int vmSwapOneObjectBlocking() {
9850 return vmSwapOneObject(0);
9851}
9852
9853static int vmSwapOneObjectThreaded() {
9854 return vmSwapOneObject(1);
9855}
9856
7e69548d 9857/* Return true if it's safe to swap out objects in a given moment.
9858 * Basically we don't want to swap objects out while there is a BGSAVE
9859 * or a BGAEOREWRITE running in backgroud. */
9860static int vmCanSwapOut(void) {
9861 return (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1);
9862}
9863
996cb5f7 9864/* =================== Virtual Memory - Threaded I/O ======================= */
9865
b9bc0eef 9866static void freeIOJob(iojob *j) {
d5d55fc3 9867 if ((j->type == REDIS_IOJOB_PREPARE_SWAP ||
9868 j->type == REDIS_IOJOB_DO_SWAP ||
9869 j->type == REDIS_IOJOB_LOAD) && j->val != NULL)
560db612 9870 {
e4ed181d 9871 /* we fix the storage type, otherwise decrRefCount() will try to
9872 * kill the I/O thread Job (that does no longer exists). */
9873 if (j->val->storage == REDIS_VM_SWAPPING)
560db612 9874 j->val->storage = REDIS_VM_MEMORY;
b9bc0eef 9875 decrRefCount(j->val);
560db612 9876 }
9877 decrRefCount(j->key);
b9bc0eef 9878 zfree(j);
9879}
9880
996cb5f7 9881/* Every time a thread finished a Job, it writes a byte into the write side
9882 * of an unix pipe in order to "awake" the main thread, and this function
9883 * is called. */
9884static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
9885 int mask)
9886{
9887 char buf[1];
b0d8747d 9888 int retval, processed = 0, toprocess = -1, trytoswap = 1;
996cb5f7 9889 REDIS_NOTUSED(el);
9890 REDIS_NOTUSED(mask);
9891 REDIS_NOTUSED(privdata);
9892
9893 /* For every byte we read in the read side of the pipe, there is one
9894 * I/O job completed to process. */
9895 while((retval = read(fd,buf,1)) == 1) {
b9bc0eef 9896 iojob *j;
9897 listNode *ln;
b9bc0eef 9898 struct dictEntry *de;
9899
996cb5f7 9900 redisLog(REDIS_DEBUG,"Processing I/O completed job");
b9bc0eef 9901
9902 /* Get the processed element (the oldest one) */
9903 lockThreadedIO();
1064ef87 9904 assert(listLength(server.io_processed) != 0);
f6c0bba8 9905 if (toprocess == -1) {
9906 toprocess = (listLength(server.io_processed)*REDIS_MAX_COMPLETED_JOBS_PROCESSED)/100;
9907 if (toprocess <= 0) toprocess = 1;
9908 }
b9bc0eef 9909 ln = listFirst(server.io_processed);
9910 j = ln->value;
9911 listDelNode(server.io_processed,ln);
9912 unlockThreadedIO();
9913 /* If this job is marked as canceled, just ignore it */
9914 if (j->canceled) {
9915 freeIOJob(j);
9916 continue;
9917 }
9918 /* Post process it in the main thread, as there are things we
9919 * can do just here to avoid race conditions and/or invasive locks */
560db612 9920 redisLog(REDIS_DEBUG,"COMPLETED Job type: %d, ID %p, key: %s", j->type, (void*)j->id, (unsigned char*)j->key->ptr);
44262c58 9921 de = dictFind(j->db->dict,j->key->ptr);
e4ed181d 9922 redisAssert(de != NULL);
b9bc0eef 9923 if (j->type == REDIS_IOJOB_LOAD) {
d5d55fc3 9924 redisDb *db;
560db612 9925 vmpointer *vp = dictGetEntryVal(de);
d5d55fc3 9926
b9bc0eef 9927 /* Key loaded, bring it at home */
560db612 9928 vmMarkPagesFree(vp->page,vp->usedpages);
b9bc0eef 9929 redisLog(REDIS_DEBUG, "VM: object %s loaded from disk (threaded)",
560db612 9930 (unsigned char*) j->key->ptr);
b9bc0eef 9931 server.vm_stats_swapped_objects--;
9932 server.vm_stats_swapins++;
d5d55fc3 9933 dictGetEntryVal(de) = j->val;
9934 incrRefCount(j->val);
9935 db = j->db;
d5d55fc3 9936 /* Handle clients waiting for this key to be loaded. */
560db612 9937 handleClientsBlockedOnSwappedKey(db,j->key);
9938 freeIOJob(j);
9939 zfree(vp);
b9bc0eef 9940 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
9941 /* Now we know the amount of pages required to swap this object.
9942 * Let's find some space for it, and queue this task again
9943 * rebranded as REDIS_IOJOB_DO_SWAP. */
054e426d 9944 if (!vmCanSwapOut() ||
9945 vmFindContiguousPages(&j->page,j->pages) == REDIS_ERR)
9946 {
9947 /* Ooops... no space or we can't swap as there is
9948 * a fork()ed Redis trying to save stuff on disk. */
560db612 9949 j->val->storage = REDIS_VM_MEMORY; /* undo operation */
b9bc0eef 9950 freeIOJob(j);
9951 } else {
c7df85a4 9952 /* Note that we need to mark this pages as used now,
9953 * if the job will be canceled, we'll mark them as freed
9954 * again. */
9955 vmMarkPagesUsed(j->page,j->pages);
b9bc0eef 9956 j->type = REDIS_IOJOB_DO_SWAP;
9957 lockThreadedIO();
9958 queueIOJob(j);
9959 unlockThreadedIO();
9960 }
9961 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
560db612 9962 vmpointer *vp;
b9bc0eef 9963
9964 /* Key swapped. We can finally free some memory. */
560db612 9965 if (j->val->storage != REDIS_VM_SWAPPING) {
9966 vmpointer *vp = (vmpointer*) j->id;
9967 printf("storage: %d\n",vp->storage);
9968 printf("key->name: %s\n",(char*)j->key->ptr);
6c96ba7d 9969 printf("val: %p\n",(void*)j->val);
9970 printf("val->type: %d\n",j->val->type);
9971 printf("val->ptr: %s\n",(char*)j->val->ptr);
9972 }
560db612 9973 redisAssert(j->val->storage == REDIS_VM_SWAPPING);
9974 vp = createVmPointer(j->val->type);
9975 vp->page = j->page;
9976 vp->usedpages = j->pages;
9977 dictGetEntryVal(de) = vp;
e4ed181d 9978 /* Fix the storage otherwise decrRefCount will attempt to
9979 * remove the associated I/O job */
9980 j->val->storage = REDIS_VM_MEMORY;
560db612 9981 decrRefCount(j->val);
b9bc0eef 9982 redisLog(REDIS_DEBUG,
9983 "VM: object %s swapped out at %lld (%lld pages) (threaded)",
560db612 9984 (unsigned char*) j->key->ptr,
b9bc0eef 9985 (unsigned long long) j->page, (unsigned long long) j->pages);
9986 server.vm_stats_swapped_objects++;
9987 server.vm_stats_swapouts++;
9988 freeIOJob(j);
f11b8647 9989 /* Put a few more swap requests in queue if we are still
9990 * out of memory */
b0d8747d 9991 if (trytoswap && vmCanSwapOut() &&
9992 zmalloc_used_memory() > server.vm_max_memory)
9993 {
f11b8647 9994 int more = 1;
9995 while(more) {
9996 lockThreadedIO();
9997 more = listLength(server.io_newjobs) <
9998 (unsigned) server.vm_max_threads;
9999 unlockThreadedIO();
10000 /* Don't waste CPU time if swappable objects are rare. */
b0d8747d 10001 if (vmSwapOneObjectThreaded() == REDIS_ERR) {
10002 trytoswap = 0;
10003 break;
10004 }
f11b8647 10005 }
10006 }
b9bc0eef 10007 }
c953f24b 10008 processed++;
f6c0bba8 10009 if (processed == toprocess) return;
996cb5f7 10010 }
10011 if (retval < 0 && errno != EAGAIN) {
10012 redisLog(REDIS_WARNING,
10013 "WARNING: read(2) error in vmThreadedIOCompletedJob() %s",
10014 strerror(errno));
10015 }
10016}
10017
10018static void lockThreadedIO(void) {
10019 pthread_mutex_lock(&server.io_mutex);
10020}
10021
10022static void unlockThreadedIO(void) {
10023 pthread_mutex_unlock(&server.io_mutex);
10024}
10025
10026/* Remove the specified object from the threaded I/O queue if still not
10027 * processed, otherwise make sure to flag it as canceled. */
10028static void vmCancelThreadedIOJob(robj *o) {
10029 list *lists[3] = {
6c96ba7d 10030 server.io_newjobs, /* 0 */
10031 server.io_processing, /* 1 */
10032 server.io_processed /* 2 */
996cb5f7 10033 };
10034 int i;
10035
10036 assert(o->storage == REDIS_VM_LOADING || o->storage == REDIS_VM_SWAPPING);
2e111efe 10037again:
996cb5f7 10038 lockThreadedIO();
560db612 10039 /* Search for a matching object in one of the queues */
996cb5f7 10040 for (i = 0; i < 3; i++) {
10041 listNode *ln;
c7df85a4 10042 listIter li;
996cb5f7 10043
c7df85a4 10044 listRewind(lists[i],&li);
10045 while ((ln = listNext(&li)) != NULL) {
996cb5f7 10046 iojob *job = ln->value;
10047
6c96ba7d 10048 if (job->canceled) continue; /* Skip this, already canceled. */
560db612 10049 if (job->id == o) {
dbc289ae 10050 redisLog(REDIS_DEBUG,"*** CANCELED %p (key %s) (type %d) (LIST ID %d)\n",
10051 (void*)job, (char*)job->key->ptr, job->type, i);
427a2153 10052 /* Mark the pages as free since the swap didn't happened
10053 * or happened but is now discarded. */
970e10bb 10054 if (i != 1 && job->type == REDIS_IOJOB_DO_SWAP)
427a2153 10055 vmMarkPagesFree(job->page,job->pages);
10056 /* Cancel the job. It depends on the list the job is
10057 * living in. */
996cb5f7 10058 switch(i) {
10059 case 0: /* io_newjobs */
6c96ba7d 10060 /* If the job was yet not processed the best thing to do
996cb5f7 10061 * is to remove it from the queue at all */
6c96ba7d 10062 freeIOJob(job);
996cb5f7 10063 listDelNode(lists[i],ln);
10064 break;
10065 case 1: /* io_processing */
d5d55fc3 10066 /* Oh Shi- the thread is messing with the Job:
10067 *
10068 * Probably it's accessing the object if this is a
10069 * PREPARE_SWAP or DO_SWAP job.
10070 * If it's a LOAD job it may be reading from disk and
10071 * if we don't wait for the job to terminate before to
10072 * cancel it, maybe in a few microseconds data can be
10073 * corrupted in this pages. So the short story is:
10074 *
10075 * Better to wait for the job to move into the
10076 * next queue (processed)... */
10077
10078 /* We try again and again until the job is completed. */
10079 unlockThreadedIO();
10080 /* But let's wait some time for the I/O thread
10081 * to finish with this job. After all this condition
10082 * should be very rare. */
10083 usleep(1);
10084 goto again;
996cb5f7 10085 case 2: /* io_processed */
2e111efe 10086 /* The job was already processed, that's easy...
10087 * just mark it as canceled so that we'll ignore it
10088 * when processing completed jobs. */
996cb5f7 10089 job->canceled = 1;
10090 break;
10091 }
c7df85a4 10092 /* Finally we have to adjust the storage type of the object
10093 * in order to "UNDO" the operaiton. */
996cb5f7 10094 if (o->storage == REDIS_VM_LOADING)
10095 o->storage = REDIS_VM_SWAPPED;
10096 else if (o->storage == REDIS_VM_SWAPPING)
10097 o->storage = REDIS_VM_MEMORY;
10098 unlockThreadedIO();
e4ed181d 10099 redisLog(REDIS_DEBUG,"*** DONE");
996cb5f7 10100 return;
10101 }
10102 }
10103 }
10104 unlockThreadedIO();
560db612 10105 printf("Not found: %p\n", (void*)o);
10106 redisAssert(1 != 1); /* We should never reach this */
996cb5f7 10107}
10108
b9bc0eef 10109static void *IOThreadEntryPoint(void *arg) {
10110 iojob *j;
10111 listNode *ln;
10112 REDIS_NOTUSED(arg);
10113
10114 pthread_detach(pthread_self());
10115 while(1) {
10116 /* Get a new job to process */
10117 lockThreadedIO();
10118 if (listLength(server.io_newjobs) == 0) {
10119 /* No new jobs in queue, exit. */
9ebed7cf 10120 redisLog(REDIS_DEBUG,"Thread %ld exiting, nothing to do",
10121 (long) pthread_self());
b9bc0eef 10122 server.io_active_threads--;
10123 unlockThreadedIO();
10124 return NULL;
10125 }
10126 ln = listFirst(server.io_newjobs);
10127 j = ln->value;
10128 listDelNode(server.io_newjobs,ln);
10129 /* Add the job in the processing queue */
10130 j->thread = pthread_self();
10131 listAddNodeTail(server.io_processing,j);
10132 ln = listLast(server.io_processing); /* We use ln later to remove it */
10133 unlockThreadedIO();
9ebed7cf 10134 redisLog(REDIS_DEBUG,"Thread %ld got a new job (type %d): %p about key '%s'",
10135 (long) pthread_self(), j->type, (void*)j, (char*)j->key->ptr);
b9bc0eef 10136
10137 /* Process the Job */
10138 if (j->type == REDIS_IOJOB_LOAD) {
560db612 10139 vmpointer *vp = (vmpointer*)j->id;
10140 j->val = vmReadObjectFromSwap(j->page,vp->vtype);
b9bc0eef 10141 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
10142 FILE *fp = fopen("/dev/null","w+");
10143 j->pages = rdbSavedObjectPages(j->val,fp);
10144 fclose(fp);
10145 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
a5819310 10146 if (vmWriteObjectOnSwap(j->val,j->page) == REDIS_ERR)
10147 j->canceled = 1;
b9bc0eef 10148 }
10149
10150 /* Done: insert the job into the processed queue */
9ebed7cf 10151 redisLog(REDIS_DEBUG,"Thread %ld completed the job: %p (key %s)",
10152 (long) pthread_self(), (void*)j, (char*)j->key->ptr);
b9bc0eef 10153 lockThreadedIO();
10154 listDelNode(server.io_processing,ln);
10155 listAddNodeTail(server.io_processed,j);
10156 unlockThreadedIO();
e0a62c7f 10157
b9bc0eef 10158 /* Signal the main thread there is new stuff to process */
10159 assert(write(server.io_ready_pipe_write,"x",1) == 1);
10160 }
10161 return NULL; /* never reached */
10162}
10163
10164static void spawnIOThread(void) {
10165 pthread_t thread;
478c2c6f 10166 sigset_t mask, omask;
a97b9060 10167 int err;
b9bc0eef 10168
478c2c6f 10169 sigemptyset(&mask);
10170 sigaddset(&mask,SIGCHLD);
10171 sigaddset(&mask,SIGHUP);
10172 sigaddset(&mask,SIGPIPE);
10173 pthread_sigmask(SIG_SETMASK, &mask, &omask);
a97b9060 10174 while ((err = pthread_create(&thread,&server.io_threads_attr,IOThreadEntryPoint,NULL)) != 0) {
10175 redisLog(REDIS_WARNING,"Unable to spawn an I/O thread: %s",
10176 strerror(err));
10177 usleep(1000000);
10178 }
478c2c6f 10179 pthread_sigmask(SIG_SETMASK, &omask, NULL);
b9bc0eef 10180 server.io_active_threads++;
10181}
10182
4ee9488d 10183/* We need to wait for the last thread to exit before we are able to
10184 * fork() in order to BGSAVE or BGREWRITEAOF. */
054e426d 10185static void waitEmptyIOJobsQueue(void) {
4ee9488d 10186 while(1) {
76b7233a 10187 int io_processed_len;
10188
4ee9488d 10189 lockThreadedIO();
054e426d 10190 if (listLength(server.io_newjobs) == 0 &&
10191 listLength(server.io_processing) == 0 &&
10192 server.io_active_threads == 0)
10193 {
4ee9488d 10194 unlockThreadedIO();
10195 return;
10196 }
76b7233a 10197 /* While waiting for empty jobs queue condition we post-process some
10198 * finshed job, as I/O threads may be hanging trying to write against
10199 * the io_ready_pipe_write FD but there are so much pending jobs that
10200 * it's blocking. */
10201 io_processed_len = listLength(server.io_processed);
4ee9488d 10202 unlockThreadedIO();
76b7233a 10203 if (io_processed_len) {
10204 vmThreadedIOCompletedJob(NULL,server.io_ready_pipe_read,NULL,0);
10205 usleep(1000); /* 1 millisecond */
10206 } else {
10207 usleep(10000); /* 10 milliseconds */
10208 }
4ee9488d 10209 }
10210}
10211
054e426d 10212static void vmReopenSwapFile(void) {
478c2c6f 10213 /* Note: we don't close the old one as we are in the child process
10214 * and don't want to mess at all with the original file object. */
054e426d 10215 server.vm_fp = fopen(server.vm_swap_file,"r+b");
10216 if (server.vm_fp == NULL) {
10217 redisLog(REDIS_WARNING,"Can't re-open the VM swap file: %s. Exiting.",
10218 server.vm_swap_file);
478c2c6f 10219 _exit(1);
054e426d 10220 }
10221 server.vm_fd = fileno(server.vm_fp);
10222}
10223
b9bc0eef 10224/* This function must be called while with threaded IO locked */
10225static void queueIOJob(iojob *j) {
6c96ba7d 10226 redisLog(REDIS_DEBUG,"Queued IO Job %p type %d about key '%s'\n",
10227 (void*)j, j->type, (char*)j->key->ptr);
b9bc0eef 10228 listAddNodeTail(server.io_newjobs,j);
10229 if (server.io_active_threads < server.vm_max_threads)
10230 spawnIOThread();
10231}
10232
10233static int vmSwapObjectThreaded(robj *key, robj *val, redisDb *db) {
10234 iojob *j;
e0a62c7f 10235
b9bc0eef 10236 j = zmalloc(sizeof(*j));
10237 j->type = REDIS_IOJOB_PREPARE_SWAP;
10238 j->db = db;
78ebe4c8 10239 j->key = key;
7dd8e7cf 10240 incrRefCount(key);
560db612 10241 j->id = j->val = val;
b9bc0eef 10242 incrRefCount(val);
10243 j->canceled = 0;
10244 j->thread = (pthread_t) -1;
560db612 10245 val->storage = REDIS_VM_SWAPPING;
b9bc0eef 10246
10247 lockThreadedIO();
10248 queueIOJob(j);
10249 unlockThreadedIO();
10250 return REDIS_OK;
10251}
10252
b0d8747d 10253/* ============ Virtual Memory - Blocking clients on missing keys =========== */
10254
d5d55fc3 10255/* This function makes the clinet 'c' waiting for the key 'key' to be loaded.
10256 * If there is not already a job loading the key, it is craeted.
10257 * The key is added to the io_keys list in the client structure, and also
10258 * in the hash table mapping swapped keys to waiting clients, that is,
10259 * server.io_waited_keys. */
10260static int waitForSwappedKey(redisClient *c, robj *key) {
10261 struct dictEntry *de;
10262 robj *o;
10263 list *l;
10264
10265 /* If the key does not exist or is already in RAM we don't need to
10266 * block the client at all. */
09241813 10267 de = dictFind(c->db->dict,key->ptr);
d5d55fc3 10268 if (de == NULL) return 0;
560db612 10269 o = dictGetEntryVal(de);
d5d55fc3 10270 if (o->storage == REDIS_VM_MEMORY) {
10271 return 0;
10272 } else if (o->storage == REDIS_VM_SWAPPING) {
10273 /* We were swapping the key, undo it! */
10274 vmCancelThreadedIOJob(o);
10275 return 0;
10276 }
e0a62c7f 10277
d5d55fc3 10278 /* OK: the key is either swapped, or being loaded just now. */
10279
10280 /* Add the key to the list of keys this client is waiting for.
10281 * This maps clients to keys they are waiting for. */
10282 listAddNodeTail(c->io_keys,key);
10283 incrRefCount(key);
10284
10285 /* Add the client to the swapped keys => clients waiting map. */
10286 de = dictFind(c->db->io_keys,key);
10287 if (de == NULL) {
10288 int retval;
10289
10290 /* For every key we take a list of clients blocked for it */
10291 l = listCreate();
10292 retval = dictAdd(c->db->io_keys,key,l);
10293 incrRefCount(key);
10294 assert(retval == DICT_OK);
10295 } else {
10296 l = dictGetEntryVal(de);
10297 }
10298 listAddNodeTail(l,c);
10299
10300 /* Are we already loading the key from disk? If not create a job */
10301 if (o->storage == REDIS_VM_SWAPPED) {
10302 iojob *j;
560db612 10303 vmpointer *vp = (vmpointer*)o;
d5d55fc3 10304
10305 o->storage = REDIS_VM_LOADING;
10306 j = zmalloc(sizeof(*j));
10307 j->type = REDIS_IOJOB_LOAD;
10308 j->db = c->db;
560db612 10309 j->id = (robj*)vp;
10310 j->key = key;
10311 incrRefCount(key);
10312 j->page = vp->page;
d5d55fc3 10313 j->val = NULL;
10314 j->canceled = 0;
10315 j->thread = (pthread_t) -1;
10316 lockThreadedIO();
10317 queueIOJob(j);
10318 unlockThreadedIO();
10319 }
10320 return 1;
10321}
10322
6f078746
PN
10323/* Preload keys for any command with first, last and step values for
10324 * the command keys prototype, as defined in the command table. */
10325static void waitForMultipleSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv) {
10326 int j, last;
10327 if (cmd->vm_firstkey == 0) return;
10328 last = cmd->vm_lastkey;
10329 if (last < 0) last = argc+last;
10330 for (j = cmd->vm_firstkey; j <= last; j += cmd->vm_keystep) {
10331 redisAssert(j < argc);
10332 waitForSwappedKey(c,argv[j]);
10333 }
10334}
10335
5d373da9 10336/* Preload keys needed for the ZUNIONSTORE and ZINTERSTORE commands.
739ba0d2
PN
10337 * Note that the number of keys to preload is user-defined, so we need to
10338 * apply a sanity check against argc. */
ca1788b5 10339static void zunionInterBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv) {
76583ea4 10340 int i, num;
ca1788b5 10341 REDIS_NOTUSED(cmd);
ca1788b5
PN
10342
10343 num = atoi(argv[2]->ptr);
739ba0d2 10344 if (num > (argc-3)) return;
76583ea4 10345 for (i = 0; i < num; i++) {
ca1788b5 10346 waitForSwappedKey(c,argv[3+i]);
76583ea4
PN
10347 }
10348}
10349
3805e04f
PN
10350/* Preload keys needed to execute the entire MULTI/EXEC block.
10351 *
10352 * This function is called by blockClientOnSwappedKeys when EXEC is issued,
10353 * and will block the client when any command requires a swapped out value. */
10354static void execBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv) {
10355 int i, margc;
10356 struct redisCommand *mcmd;
10357 robj **margv;
10358 REDIS_NOTUSED(cmd);
10359 REDIS_NOTUSED(argc);
10360 REDIS_NOTUSED(argv);
10361
10362 if (!(c->flags & REDIS_MULTI)) return;
10363 for (i = 0; i < c->mstate.count; i++) {
10364 mcmd = c->mstate.commands[i].cmd;
10365 margc = c->mstate.commands[i].argc;
10366 margv = c->mstate.commands[i].argv;
10367
10368 if (mcmd->vm_preload_proc != NULL) {
10369 mcmd->vm_preload_proc(c,mcmd,margc,margv);
10370 } else {
10371 waitForMultipleSwappedKeys(c,mcmd,margc,margv);
10372 }
76583ea4
PN
10373 }
10374}
10375
b0d8747d 10376/* Is this client attempting to run a command against swapped keys?
d5d55fc3 10377 * If so, block it ASAP, load the keys in background, then resume it.
b0d8747d 10378 *
d5d55fc3 10379 * The important idea about this function is that it can fail! If keys will
10380 * still be swapped when the client is resumed, this key lookups will
10381 * just block loading keys from disk. In practical terms this should only
10382 * happen with SORT BY command or if there is a bug in this function.
10383 *
10384 * Return 1 if the client is marked as blocked, 0 if the client can
10385 * continue as the keys it is going to access appear to be in memory. */
0a6f3f0f 10386static int blockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd) {
76583ea4 10387 if (cmd->vm_preload_proc != NULL) {
ca1788b5 10388 cmd->vm_preload_proc(c,cmd,c->argc,c->argv);
76583ea4 10389 } else {
6f078746 10390 waitForMultipleSwappedKeys(c,cmd,c->argc,c->argv);
76583ea4
PN
10391 }
10392
d5d55fc3 10393 /* If the client was blocked for at least one key, mark it as blocked. */
10394 if (listLength(c->io_keys)) {
10395 c->flags |= REDIS_IO_WAIT;
10396 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
10397 server.vm_blocked_clients++;
10398 return 1;
10399 } else {
10400 return 0;
10401 }
10402}
10403
10404/* Remove the 'key' from the list of blocked keys for a given client.
10405 *
10406 * The function returns 1 when there are no longer blocking keys after
10407 * the current one was removed (and the client can be unblocked). */
10408static int dontWaitForSwappedKey(redisClient *c, robj *key) {
10409 list *l;
10410 listNode *ln;
10411 listIter li;
10412 struct dictEntry *de;
10413
10414 /* Remove the key from the list of keys this client is waiting for. */
10415 listRewind(c->io_keys,&li);
10416 while ((ln = listNext(&li)) != NULL) {
bf028098 10417 if (equalStringObjects(ln->value,key)) {
d5d55fc3 10418 listDelNode(c->io_keys,ln);
10419 break;
10420 }
10421 }
10422 assert(ln != NULL);
10423
10424 /* Remove the client form the key => waiting clients map. */
10425 de = dictFind(c->db->io_keys,key);
10426 assert(de != NULL);
10427 l = dictGetEntryVal(de);
10428 ln = listSearchKey(l,c);
10429 assert(ln != NULL);
10430 listDelNode(l,ln);
10431 if (listLength(l) == 0)
10432 dictDelete(c->db->io_keys,key);
10433
10434 return listLength(c->io_keys) == 0;
10435}
10436
560db612 10437/* Every time we now a key was loaded back in memory, we handle clients
10438 * waiting for this key if any. */
d5d55fc3 10439static void handleClientsBlockedOnSwappedKey(redisDb *db, robj *key) {
10440 struct dictEntry *de;
10441 list *l;
10442 listNode *ln;
10443 int len;
10444
10445 de = dictFind(db->io_keys,key);
10446 if (!de) return;
10447
10448 l = dictGetEntryVal(de);
10449 len = listLength(l);
10450 /* Note: we can't use something like while(listLength(l)) as the list
10451 * can be freed by the calling function when we remove the last element. */
10452 while (len--) {
10453 ln = listFirst(l);
10454 redisClient *c = ln->value;
10455
10456 if (dontWaitForSwappedKey(c,key)) {
10457 /* Put the client in the list of clients ready to go as we
10458 * loaded all the keys about it. */
10459 listAddNodeTail(server.io_ready_clients,c);
10460 }
10461 }
b0d8747d 10462}
b0d8747d 10463
500ece7c 10464/* =========================== Remote Configuration ========================= */
10465
10466static void configSetCommand(redisClient *c) {
10467 robj *o = getDecodedObject(c->argv[3]);
2e5eb04e 10468 long long ll;
10469
500ece7c 10470 if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) {
10471 zfree(server.dbfilename);
10472 server.dbfilename = zstrdup(o->ptr);
10473 } else if (!strcasecmp(c->argv[2]->ptr,"requirepass")) {
10474 zfree(server.requirepass);
10475 server.requirepass = zstrdup(o->ptr);
10476 } else if (!strcasecmp(c->argv[2]->ptr,"masterauth")) {
10477 zfree(server.masterauth);
10478 server.masterauth = zstrdup(o->ptr);
10479 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory")) {
2e5eb04e 10480 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
10481 ll < 0) goto badfmt;
10482 server.maxmemory = ll;
10483 } else if (!strcasecmp(c->argv[2]->ptr,"timeout")) {
10484 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
10485 ll < 0 || ll > LONG_MAX) goto badfmt;
10486 server.maxidletime = ll;
1b677732 10487 } else if (!strcasecmp(c->argv[2]->ptr,"appendfsync")) {
10488 if (!strcasecmp(o->ptr,"no")) {
10489 server.appendfsync = APPENDFSYNC_NO;
10490 } else if (!strcasecmp(o->ptr,"everysec")) {
10491 server.appendfsync = APPENDFSYNC_EVERYSEC;
10492 } else if (!strcasecmp(o->ptr,"always")) {
10493 server.appendfsync = APPENDFSYNC_ALWAYS;
10494 } else {
10495 goto badfmt;
10496 }
38db9171 10497 } else if (!strcasecmp(c->argv[2]->ptr,"no-appendfsync-on-rewrite")) {
10498 int yn = yesnotoi(o->ptr);
10499
10500 if (yn == -1) goto badfmt;
10501 server.no_appendfsync_on_rewrite = yn;
2e5eb04e 10502 } else if (!strcasecmp(c->argv[2]->ptr,"appendonly")) {
10503 int old = server.appendonly;
10504 int new = yesnotoi(o->ptr);
10505
10506 if (new == -1) goto badfmt;
10507 if (old != new) {
10508 if (new == 0) {
10509 stopAppendOnly();
10510 } else {
10511 if (startAppendOnly() == REDIS_ERR) {
10512 addReplySds(c,sdscatprintf(sdsempty(),
10513 "-ERR Unable to turn on AOF. Check server logs.\r\n"));
10514 decrRefCount(o);
10515 return;
10516 }
10517 }
10518 }
a34e0a25 10519 } else if (!strcasecmp(c->argv[2]->ptr,"save")) {
10520 int vlen, j;
10521 sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen);
10522
10523 /* Perform sanity check before setting the new config:
10524 * - Even number of args
10525 * - Seconds >= 1, changes >= 0 */
10526 if (vlen & 1) {
10527 sdsfreesplitres(v,vlen);
10528 goto badfmt;
10529 }
10530 for (j = 0; j < vlen; j++) {
10531 char *eptr;
10532 long val;
10533
10534 val = strtoll(v[j], &eptr, 10);
10535 if (eptr[0] != '\0' ||
10536 ((j & 1) == 0 && val < 1) ||
10537 ((j & 1) == 1 && val < 0)) {
10538 sdsfreesplitres(v,vlen);
10539 goto badfmt;
10540 }
10541 }
10542 /* Finally set the new config */
10543 resetServerSaveParams();
10544 for (j = 0; j < vlen; j += 2) {
10545 time_t seconds;
10546 int changes;
10547
10548 seconds = strtoll(v[j],NULL,10);
10549 changes = strtoll(v[j+1],NULL,10);
10550 appendServerSaveParams(seconds, changes);
10551 }
10552 sdsfreesplitres(v,vlen);
500ece7c 10553 } else {
10554 addReplySds(c,sdscatprintf(sdsempty(),
10555 "-ERR not supported CONFIG parameter %s\r\n",
10556 (char*)c->argv[2]->ptr));
10557 decrRefCount(o);
10558 return;
10559 }
10560 decrRefCount(o);
10561 addReply(c,shared.ok);
a34e0a25 10562 return;
10563
10564badfmt: /* Bad format errors */
10565 addReplySds(c,sdscatprintf(sdsempty(),
10566 "-ERR invalid argument '%s' for CONFIG SET '%s'\r\n",
10567 (char*)o->ptr,
10568 (char*)c->argv[2]->ptr));
10569 decrRefCount(o);
500ece7c 10570}
10571
10572static void configGetCommand(redisClient *c) {
10573 robj *o = getDecodedObject(c->argv[2]);
10574 robj *lenobj = createObject(REDIS_STRING,NULL);
10575 char *pattern = o->ptr;
10576 int matches = 0;
10577
10578 addReply(c,lenobj);
10579 decrRefCount(lenobj);
10580
10581 if (stringmatch(pattern,"dbfilename",0)) {
10582 addReplyBulkCString(c,"dbfilename");
10583 addReplyBulkCString(c,server.dbfilename);
10584 matches++;
10585 }
10586 if (stringmatch(pattern,"requirepass",0)) {
10587 addReplyBulkCString(c,"requirepass");
10588 addReplyBulkCString(c,server.requirepass);
10589 matches++;
10590 }
10591 if (stringmatch(pattern,"masterauth",0)) {
10592 addReplyBulkCString(c,"masterauth");
10593 addReplyBulkCString(c,server.masterauth);
10594 matches++;
10595 }
10596 if (stringmatch(pattern,"maxmemory",0)) {
10597 char buf[128];
10598
2e5eb04e 10599 ll2string(buf,128,server.maxmemory);
500ece7c 10600 addReplyBulkCString(c,"maxmemory");
10601 addReplyBulkCString(c,buf);
10602 matches++;
10603 }
2e5eb04e 10604 if (stringmatch(pattern,"timeout",0)) {
10605 char buf[128];
10606
10607 ll2string(buf,128,server.maxidletime);
10608 addReplyBulkCString(c,"timeout");
10609 addReplyBulkCString(c,buf);
10610 matches++;
10611 }
10612 if (stringmatch(pattern,"appendonly",0)) {
10613 addReplyBulkCString(c,"appendonly");
10614 addReplyBulkCString(c,server.appendonly ? "yes" : "no");
10615 matches++;
10616 }
38db9171 10617 if (stringmatch(pattern,"no-appendfsync-on-rewrite",0)) {
10618 addReplyBulkCString(c,"no-appendfsync-on-rewrite");
10619 addReplyBulkCString(c,server.no_appendfsync_on_rewrite ? "yes" : "no");
10620 matches++;
10621 }
1b677732 10622 if (stringmatch(pattern,"appendfsync",0)) {
10623 char *policy;
10624
10625 switch(server.appendfsync) {
10626 case APPENDFSYNC_NO: policy = "no"; break;
10627 case APPENDFSYNC_EVERYSEC: policy = "everysec"; break;
10628 case APPENDFSYNC_ALWAYS: policy = "always"; break;
10629 default: policy = "unknown"; break; /* too harmless to panic */
10630 }
10631 addReplyBulkCString(c,"appendfsync");
10632 addReplyBulkCString(c,policy);
10633 matches++;
10634 }
a34e0a25 10635 if (stringmatch(pattern,"save",0)) {
10636 sds buf = sdsempty();
10637 int j;
10638
10639 for (j = 0; j < server.saveparamslen; j++) {
10640 buf = sdscatprintf(buf,"%ld %d",
10641 server.saveparams[j].seconds,
10642 server.saveparams[j].changes);
10643 if (j != server.saveparamslen-1)
10644 buf = sdscatlen(buf," ",1);
10645 }
10646 addReplyBulkCString(c,"save");
10647 addReplyBulkCString(c,buf);
10648 sdsfree(buf);
10649 matches++;
10650 }
500ece7c 10651 decrRefCount(o);
10652 lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",matches*2);
10653}
10654
10655static void configCommand(redisClient *c) {
10656 if (!strcasecmp(c->argv[1]->ptr,"set")) {
10657 if (c->argc != 4) goto badarity;
10658 configSetCommand(c);
10659 } else if (!strcasecmp(c->argv[1]->ptr,"get")) {
10660 if (c->argc != 3) goto badarity;
10661 configGetCommand(c);
10662 } else if (!strcasecmp(c->argv[1]->ptr,"resetstat")) {
10663 if (c->argc != 2) goto badarity;
10664 server.stat_numcommands = 0;
10665 server.stat_numconnections = 0;
10666 server.stat_expiredkeys = 0;
10667 server.stat_starttime = time(NULL);
10668 addReply(c,shared.ok);
10669 } else {
10670 addReplySds(c,sdscatprintf(sdsempty(),
10671 "-ERR CONFIG subcommand must be one of GET, SET, RESETSTAT\r\n"));
10672 }
10673 return;
10674
10675badarity:
10676 addReplySds(c,sdscatprintf(sdsempty(),
10677 "-ERR Wrong number of arguments for CONFIG %s\r\n",
10678 (char*) c->argv[1]->ptr));
10679}
10680
befec3cd 10681/* =========================== Pubsub implementation ======================== */
10682
ffc6b7f8 10683static void freePubsubPattern(void *p) {
10684 pubsubPattern *pat = p;
10685
10686 decrRefCount(pat->pattern);
10687 zfree(pat);
10688}
10689
10690static int listMatchPubsubPattern(void *a, void *b) {
10691 pubsubPattern *pa = a, *pb = b;
10692
10693 return (pa->client == pb->client) &&
bf028098 10694 (equalStringObjects(pa->pattern,pb->pattern));
ffc6b7f8 10695}
10696
10697/* Subscribe a client to a channel. Returns 1 if the operation succeeded, or
10698 * 0 if the client was already subscribed to that channel. */
10699static int pubsubSubscribeChannel(redisClient *c, robj *channel) {
befec3cd 10700 struct dictEntry *de;
10701 list *clients = NULL;
10702 int retval = 0;
10703
ffc6b7f8 10704 /* Add the channel to the client -> channels hash table */
10705 if (dictAdd(c->pubsub_channels,channel,NULL) == DICT_OK) {
befec3cd 10706 retval = 1;
ffc6b7f8 10707 incrRefCount(channel);
10708 /* Add the client to the channel -> list of clients hash table */
10709 de = dictFind(server.pubsub_channels,channel);
befec3cd 10710 if (de == NULL) {
10711 clients = listCreate();
ffc6b7f8 10712 dictAdd(server.pubsub_channels,channel,clients);
10713 incrRefCount(channel);
befec3cd 10714 } else {
10715 clients = dictGetEntryVal(de);
10716 }
10717 listAddNodeTail(clients,c);
10718 }
10719 /* Notify the client */
10720 addReply(c,shared.mbulk3);
10721 addReply(c,shared.subscribebulk);
ffc6b7f8 10722 addReplyBulk(c,channel);
482b672d 10723 addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns));
befec3cd 10724 return retval;
10725}
10726
ffc6b7f8 10727/* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
10728 * 0 if the client was not subscribed to the specified channel. */
10729static int pubsubUnsubscribeChannel(redisClient *c, robj *channel, int notify) {
befec3cd 10730 struct dictEntry *de;
10731 list *clients;
10732 listNode *ln;
10733 int retval = 0;
10734
ffc6b7f8 10735 /* Remove the channel from the client -> channels hash table */
10736 incrRefCount(channel); /* channel may be just a pointer to the same object
201037f5 10737 we have in the hash tables. Protect it... */
ffc6b7f8 10738 if (dictDelete(c->pubsub_channels,channel) == DICT_OK) {
befec3cd 10739 retval = 1;
ffc6b7f8 10740 /* Remove the client from the channel -> clients list hash table */
10741 de = dictFind(server.pubsub_channels,channel);
befec3cd 10742 assert(de != NULL);
10743 clients = dictGetEntryVal(de);
10744 ln = listSearchKey(clients,c);
10745 assert(ln != NULL);
10746 listDelNode(clients,ln);
ff767a75 10747 if (listLength(clients) == 0) {
10748 /* Free the list and associated hash entry at all if this was
10749 * the latest client, so that it will be possible to abuse
ffc6b7f8 10750 * Redis PUBSUB creating millions of channels. */
10751 dictDelete(server.pubsub_channels,channel);
ff767a75 10752 }
befec3cd 10753 }
10754 /* Notify the client */
10755 if (notify) {
10756 addReply(c,shared.mbulk3);
10757 addReply(c,shared.unsubscribebulk);
ffc6b7f8 10758 addReplyBulk(c,channel);
482b672d 10759 addReplyLongLong(c,dictSize(c->pubsub_channels)+
ffc6b7f8 10760 listLength(c->pubsub_patterns));
10761
10762 }
10763 decrRefCount(channel); /* it is finally safe to release it */
10764 return retval;
10765}
10766
10767/* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the clinet was already subscribed to that pattern. */
10768static int pubsubSubscribePattern(redisClient *c, robj *pattern) {
10769 int retval = 0;
10770
10771 if (listSearchKey(c->pubsub_patterns,pattern) == NULL) {
10772 retval = 1;
10773 pubsubPattern *pat;
10774 listAddNodeTail(c->pubsub_patterns,pattern);
10775 incrRefCount(pattern);
10776 pat = zmalloc(sizeof(*pat));
10777 pat->pattern = getDecodedObject(pattern);
10778 pat->client = c;
10779 listAddNodeTail(server.pubsub_patterns,pat);
10780 }
10781 /* Notify the client */
10782 addReply(c,shared.mbulk3);
10783 addReply(c,shared.psubscribebulk);
10784 addReplyBulk(c,pattern);
482b672d 10785 addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns));
ffc6b7f8 10786 return retval;
10787}
10788
10789/* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
10790 * 0 if the client was not subscribed to the specified channel. */
10791static int pubsubUnsubscribePattern(redisClient *c, robj *pattern, int notify) {
10792 listNode *ln;
10793 pubsubPattern pat;
10794 int retval = 0;
10795
10796 incrRefCount(pattern); /* Protect the object. May be the same we remove */
10797 if ((ln = listSearchKey(c->pubsub_patterns,pattern)) != NULL) {
10798 retval = 1;
10799 listDelNode(c->pubsub_patterns,ln);
10800 pat.client = c;
10801 pat.pattern = pattern;
10802 ln = listSearchKey(server.pubsub_patterns,&pat);
10803 listDelNode(server.pubsub_patterns,ln);
10804 }
10805 /* Notify the client */
10806 if (notify) {
10807 addReply(c,shared.mbulk3);
10808 addReply(c,shared.punsubscribebulk);
10809 addReplyBulk(c,pattern);
482b672d 10810 addReplyLongLong(c,dictSize(c->pubsub_channels)+
ffc6b7f8 10811 listLength(c->pubsub_patterns));
befec3cd 10812 }
ffc6b7f8 10813 decrRefCount(pattern);
befec3cd 10814 return retval;
10815}
10816
ffc6b7f8 10817/* Unsubscribe from all the channels. Return the number of channels the
10818 * client was subscribed from. */
10819static int pubsubUnsubscribeAllChannels(redisClient *c, int notify) {
10820 dictIterator *di = dictGetIterator(c->pubsub_channels);
befec3cd 10821 dictEntry *de;
10822 int count = 0;
10823
10824 while((de = dictNext(di)) != NULL) {
ffc6b7f8 10825 robj *channel = dictGetEntryKey(de);
befec3cd 10826
ffc6b7f8 10827 count += pubsubUnsubscribeChannel(c,channel,notify);
befec3cd 10828 }
10829 dictReleaseIterator(di);
10830 return count;
10831}
10832
ffc6b7f8 10833/* Unsubscribe from all the patterns. Return the number of patterns the
10834 * client was subscribed from. */
10835static int pubsubUnsubscribeAllPatterns(redisClient *c, int notify) {
10836 listNode *ln;
10837 listIter li;
10838 int count = 0;
10839
10840 listRewind(c->pubsub_patterns,&li);
10841 while ((ln = listNext(&li)) != NULL) {
10842 robj *pattern = ln->value;
10843
10844 count += pubsubUnsubscribePattern(c,pattern,notify);
10845 }
10846 return count;
10847}
10848
befec3cd 10849/* Publish a message */
ffc6b7f8 10850static int pubsubPublishMessage(robj *channel, robj *message) {
befec3cd 10851 int receivers = 0;
10852 struct dictEntry *de;
ffc6b7f8 10853 listNode *ln;
10854 listIter li;
befec3cd 10855
ffc6b7f8 10856 /* Send to clients listening for that channel */
10857 de = dictFind(server.pubsub_channels,channel);
befec3cd 10858 if (de) {
10859 list *list = dictGetEntryVal(de);
10860 listNode *ln;
10861 listIter li;
10862
10863 listRewind(list,&li);
10864 while ((ln = listNext(&li)) != NULL) {
10865 redisClient *c = ln->value;
10866
10867 addReply(c,shared.mbulk3);
10868 addReply(c,shared.messagebulk);
ffc6b7f8 10869 addReplyBulk(c,channel);
befec3cd 10870 addReplyBulk(c,message);
10871 receivers++;
10872 }
10873 }
ffc6b7f8 10874 /* Send to clients listening to matching channels */
10875 if (listLength(server.pubsub_patterns)) {
10876 listRewind(server.pubsub_patterns,&li);
10877 channel = getDecodedObject(channel);
10878 while ((ln = listNext(&li)) != NULL) {
10879 pubsubPattern *pat = ln->value;
10880
10881 if (stringmatchlen((char*)pat->pattern->ptr,
10882 sdslen(pat->pattern->ptr),
10883 (char*)channel->ptr,
10884 sdslen(channel->ptr),0)) {
c8d0ea0e 10885 addReply(pat->client,shared.mbulk4);
10886 addReply(pat->client,shared.pmessagebulk);
10887 addReplyBulk(pat->client,pat->pattern);
ffc6b7f8 10888 addReplyBulk(pat->client,channel);
10889 addReplyBulk(pat->client,message);
10890 receivers++;
10891 }
10892 }
10893 decrRefCount(channel);
10894 }
befec3cd 10895 return receivers;
10896}
10897
10898static void subscribeCommand(redisClient *c) {
10899 int j;
10900
10901 for (j = 1; j < c->argc; j++)
ffc6b7f8 10902 pubsubSubscribeChannel(c,c->argv[j]);
befec3cd 10903}
10904
10905static void unsubscribeCommand(redisClient *c) {
10906 if (c->argc == 1) {
ffc6b7f8 10907 pubsubUnsubscribeAllChannels(c,1);
10908 return;
10909 } else {
10910 int j;
10911
10912 for (j = 1; j < c->argc; j++)
10913 pubsubUnsubscribeChannel(c,c->argv[j],1);
10914 }
10915}
10916
10917static void psubscribeCommand(redisClient *c) {
10918 int j;
10919
10920 for (j = 1; j < c->argc; j++)
10921 pubsubSubscribePattern(c,c->argv[j]);
10922}
10923
10924static void punsubscribeCommand(redisClient *c) {
10925 if (c->argc == 1) {
10926 pubsubUnsubscribeAllPatterns(c,1);
befec3cd 10927 return;
10928 } else {
10929 int j;
10930
10931 for (j = 1; j < c->argc; j++)
ffc6b7f8 10932 pubsubUnsubscribePattern(c,c->argv[j],1);
befec3cd 10933 }
10934}
10935
10936static void publishCommand(redisClient *c) {
10937 int receivers = pubsubPublishMessage(c->argv[1],c->argv[2]);
482b672d 10938 addReplyLongLong(c,receivers);
befec3cd 10939}
10940
37ab76c9 10941/* ===================== WATCH (CAS alike for MULTI/EXEC) ===================
10942 *
10943 * The implementation uses a per-DB hash table mapping keys to list of clients
10944 * WATCHing those keys, so that given a key that is going to be modified
10945 * we can mark all the associated clients as dirty.
10946 *
10947 * Also every client contains a list of WATCHed keys so that's possible to
10948 * un-watch such keys when the client is freed or when UNWATCH is called. */
10949
10950/* In the client->watched_keys list we need to use watchedKey structures
10951 * as in order to identify a key in Redis we need both the key name and the
10952 * DB */
10953typedef struct watchedKey {
10954 robj *key;
10955 redisDb *db;
10956} watchedKey;
10957
10958/* Watch for the specified key */
10959static void watchForKey(redisClient *c, robj *key) {
10960 list *clients = NULL;
10961 listIter li;
10962 listNode *ln;
10963 watchedKey *wk;
10964
10965 /* Check if we are already watching for this key */
10966 listRewind(c->watched_keys,&li);
10967 while((ln = listNext(&li))) {
10968 wk = listNodeValue(ln);
10969 if (wk->db == c->db && equalStringObjects(key,wk->key))
10970 return; /* Key already watched */
10971 }
10972 /* This key is not already watched in this DB. Let's add it */
10973 clients = dictFetchValue(c->db->watched_keys,key);
10974 if (!clients) {
10975 clients = listCreate();
10976 dictAdd(c->db->watched_keys,key,clients);
10977 incrRefCount(key);
10978 }
10979 listAddNodeTail(clients,c);
10980 /* Add the new key to the lits of keys watched by this client */
10981 wk = zmalloc(sizeof(*wk));
10982 wk->key = key;
10983 wk->db = c->db;
10984 incrRefCount(key);
10985 listAddNodeTail(c->watched_keys,wk);
10986}
10987
10988/* Unwatch all the keys watched by this client. To clean the EXEC dirty
10989 * flag is up to the caller. */
10990static void unwatchAllKeys(redisClient *c) {
10991 listIter li;
10992 listNode *ln;
10993
10994 if (listLength(c->watched_keys) == 0) return;
10995 listRewind(c->watched_keys,&li);
10996 while((ln = listNext(&li))) {
10997 list *clients;
10998 watchedKey *wk;
10999
11000 /* Lookup the watched key -> clients list and remove the client
11001 * from the list */
11002 wk = listNodeValue(ln);
11003 clients = dictFetchValue(wk->db->watched_keys, wk->key);
11004 assert(clients != NULL);
11005 listDelNode(clients,listSearchKey(clients,c));
11006 /* Kill the entry at all if this was the only client */
11007 if (listLength(clients) == 0)
11008 dictDelete(wk->db->watched_keys, wk->key);
11009 /* Remove this watched key from the client->watched list */
11010 listDelNode(c->watched_keys,ln);
11011 decrRefCount(wk->key);
11012 zfree(wk);
11013 }
11014}
11015
ca3f830b 11016/* "Touch" a key, so that if this key is being WATCHed by some client the
37ab76c9 11017 * next EXEC will fail. */
11018static void touchWatchedKey(redisDb *db, robj *key) {
11019 list *clients;
11020 listIter li;
11021 listNode *ln;
11022
11023 if (dictSize(db->watched_keys) == 0) return;
11024 clients = dictFetchValue(db->watched_keys, key);
11025 if (!clients) return;
11026
11027 /* Mark all the clients watching this key as REDIS_DIRTY_CAS */
11028 /* Check if we are already watching for this key */
11029 listRewind(clients,&li);
11030 while((ln = listNext(&li))) {
11031 redisClient *c = listNodeValue(ln);
11032
11033 c->flags |= REDIS_DIRTY_CAS;
11034 }
11035}
11036
9b30e1a2 11037/* On FLUSHDB or FLUSHALL all the watched keys that are present before the
11038 * flush but will be deleted as effect of the flushing operation should
11039 * be touched. "dbid" is the DB that's getting the flush. -1 if it is
11040 * a FLUSHALL operation (all the DBs flushed). */
11041static void touchWatchedKeysOnFlush(int dbid) {
11042 listIter li1, li2;
11043 listNode *ln;
11044
11045 /* For every client, check all the waited keys */
11046 listRewind(server.clients,&li1);
11047 while((ln = listNext(&li1))) {
11048 redisClient *c = listNodeValue(ln);
11049 listRewind(c->watched_keys,&li2);
11050 while((ln = listNext(&li2))) {
11051 watchedKey *wk = listNodeValue(ln);
11052
11053 /* For every watched key matching the specified DB, if the
11054 * key exists, mark the client as dirty, as the key will be
11055 * removed. */
11056 if (dbid == -1 || wk->db->id == dbid) {
09241813 11057 if (dictFind(wk->db->dict, wk->key->ptr) != NULL)
9b30e1a2 11058 c->flags |= REDIS_DIRTY_CAS;
11059 }
11060 }
11061 }
11062}
11063
37ab76c9 11064static void watchCommand(redisClient *c) {
11065 int j;
11066
6531c94d 11067 if (c->flags & REDIS_MULTI) {
11068 addReplySds(c,sdsnew("-ERR WATCH inside MULTI is not allowed\r\n"));
11069 return;
11070 }
37ab76c9 11071 for (j = 1; j < c->argc; j++)
11072 watchForKey(c,c->argv[j]);
11073 addReply(c,shared.ok);
11074}
11075
11076static void unwatchCommand(redisClient *c) {
11077 unwatchAllKeys(c);
11078 c->flags &= (~REDIS_DIRTY_CAS);
11079 addReply(c,shared.ok);
11080}
11081
7f957c92 11082/* ================================= Debugging ============================== */
11083
ba798261 11084/* Compute the sha1 of string at 's' with 'len' bytes long.
11085 * The SHA1 is then xored againt the string pointed by digest.
11086 * Since xor is commutative, this operation is used in order to
11087 * "add" digests relative to unordered elements.
11088 *
11089 * So digest(a,b,c,d) will be the same of digest(b,a,c,d) */
11090static void xorDigest(unsigned char *digest, void *ptr, size_t len) {
11091 SHA1_CTX ctx;
11092 unsigned char hash[20], *s = ptr;
11093 int j;
11094
11095 SHA1Init(&ctx);
11096 SHA1Update(&ctx,s,len);
11097 SHA1Final(hash,&ctx);
11098
11099 for (j = 0; j < 20; j++)
11100 digest[j] ^= hash[j];
11101}
11102
11103static void xorObjectDigest(unsigned char *digest, robj *o) {
11104 o = getDecodedObject(o);
11105 xorDigest(digest,o->ptr,sdslen(o->ptr));
11106 decrRefCount(o);
11107}
11108
11109/* This function instead of just computing the SHA1 and xoring it
11110 * against diget, also perform the digest of "digest" itself and
11111 * replace the old value with the new one.
11112 *
11113 * So the final digest will be:
11114 *
11115 * digest = SHA1(digest xor SHA1(data))
11116 *
11117 * This function is used every time we want to preserve the order so
11118 * that digest(a,b,c,d) will be different than digest(b,c,d,a)
11119 *
11120 * Also note that mixdigest("foo") followed by mixdigest("bar")
11121 * will lead to a different digest compared to "fo", "obar".
11122 */
11123static void mixDigest(unsigned char *digest, void *ptr, size_t len) {
11124 SHA1_CTX ctx;
11125 char *s = ptr;
11126
11127 xorDigest(digest,s,len);
11128 SHA1Init(&ctx);
11129 SHA1Update(&ctx,digest,20);
11130 SHA1Final(digest,&ctx);
11131}
11132
11133static void mixObjectDigest(unsigned char *digest, robj *o) {
11134 o = getDecodedObject(o);
11135 mixDigest(digest,o->ptr,sdslen(o->ptr));
11136 decrRefCount(o);
11137}
11138
11139/* Compute the dataset digest. Since keys, sets elements, hashes elements
11140 * are not ordered, we use a trick: every aggregate digest is the xor
11141 * of the digests of their elements. This way the order will not change
11142 * the result. For list instead we use a feedback entering the output digest
11143 * as input in order to ensure that a different ordered list will result in
11144 * a different digest. */
11145static void computeDatasetDigest(unsigned char *final) {
11146 unsigned char digest[20];
11147 char buf[128];
11148 dictIterator *di = NULL;
11149 dictEntry *de;
11150 int j;
11151 uint32_t aux;
11152
11153 memset(final,0,20); /* Start with a clean result */
11154
11155 for (j = 0; j < server.dbnum; j++) {
11156 redisDb *db = server.db+j;
11157
11158 if (dictSize(db->dict) == 0) continue;
11159 di = dictGetIterator(db->dict);
11160
11161 /* hash the DB id, so the same dataset moved in a different
11162 * DB will lead to a different digest */
11163 aux = htonl(j);
11164 mixDigest(final,&aux,sizeof(aux));
11165
11166 /* Iterate this DB writing every entry */
11167 while((de = dictNext(di)) != NULL) {
09241813 11168 sds key;
11169 robj *keyobj, *o;
ba798261 11170 time_t expiretime;
11171
11172 memset(digest,0,20); /* This key-val digest */
11173 key = dictGetEntryKey(de);
09241813 11174 keyobj = createStringObject(key,sdslen(key));
11175
11176 mixDigest(digest,key,sdslen(key));
11177
11178 /* Make sure the key is loaded if VM is active */
11179 o = lookupKeyRead(db,keyobj);
cbae1d34 11180
ba798261 11181 aux = htonl(o->type);
11182 mixDigest(digest,&aux,sizeof(aux));
09241813 11183 expiretime = getExpire(db,keyobj);
ba798261 11184
11185 /* Save the key and associated value */
11186 if (o->type == REDIS_STRING) {
11187 mixObjectDigest(digest,o);
11188 } else if (o->type == REDIS_LIST) {
003f0840
PN
11189 listTypeIterator *li = listTypeInitIterator(o,0,REDIS_TAIL);
11190 listTypeEntry entry;
11191 while(listTypeNext(li,&entry)) {
11192 robj *eleobj = listTypeGet(&entry);
ba798261 11193 mixObjectDigest(digest,eleobj);
dc845730 11194 decrRefCount(eleobj);
ba798261 11195 }
003f0840 11196 listTypeReleaseIterator(li);
ba798261 11197 } else if (o->type == REDIS_SET) {
11198 dict *set = o->ptr;
11199 dictIterator *di = dictGetIterator(set);
11200 dictEntry *de;
11201
11202 while((de = dictNext(di)) != NULL) {
11203 robj *eleobj = dictGetEntryKey(de);
11204
11205 xorObjectDigest(digest,eleobj);
11206 }
11207 dictReleaseIterator(di);
11208 } else if (o->type == REDIS_ZSET) {
11209 zset *zs = o->ptr;
11210 dictIterator *di = dictGetIterator(zs->dict);
11211 dictEntry *de;
11212
11213 while((de = dictNext(di)) != NULL) {
11214 robj *eleobj = dictGetEntryKey(de);
11215 double *score = dictGetEntryVal(de);
11216 unsigned char eledigest[20];
11217
11218 snprintf(buf,sizeof(buf),"%.17g",*score);
11219 memset(eledigest,0,20);
11220 mixObjectDigest(eledigest,eleobj);
11221 mixDigest(eledigest,buf,strlen(buf));
11222 xorDigest(digest,eledigest,20);
11223 }
11224 dictReleaseIterator(di);
11225 } else if (o->type == REDIS_HASH) {
d1578a33 11226 hashTypeIterator *hi;
ba798261 11227 robj *obj;
11228
d1578a33
PN
11229 hi = hashTypeInitIterator(o);
11230 while (hashTypeNext(hi) != REDIS_ERR) {
ba798261 11231 unsigned char eledigest[20];
11232
11233 memset(eledigest,0,20);
d1578a33 11234 obj = hashTypeCurrent(hi,REDIS_HASH_KEY);
ba798261 11235 mixObjectDigest(eledigest,obj);
11236 decrRefCount(obj);
d1578a33 11237 obj = hashTypeCurrent(hi,REDIS_HASH_VALUE);
ba798261 11238 mixObjectDigest(eledigest,obj);
11239 decrRefCount(obj);
11240 xorDigest(digest,eledigest,20);
11241 }
d1578a33 11242 hashTypeReleaseIterator(hi);
ba798261 11243 } else {
11244 redisPanic("Unknown object type");
11245 }
ba798261 11246 /* If the key has an expire, add it to the mix */
11247 if (expiretime != -1) xorDigest(digest,"!!expire!!",10);
11248 /* We can finally xor the key-val digest to the final digest */
11249 xorDigest(final,digest,20);
09241813 11250 decrRefCount(keyobj);
ba798261 11251 }
11252 dictReleaseIterator(di);
11253 }
11254}
11255
7f957c92 11256static void debugCommand(redisClient *c) {
11257 if (!strcasecmp(c->argv[1]->ptr,"segfault")) {
11258 *((char*)-1) = 'x';
210e29f7 11259 } else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
11260 if (rdbSave(server.dbfilename) != REDIS_OK) {
11261 addReply(c,shared.err);
11262 return;
11263 }
11264 emptyDb();
11265 if (rdbLoad(server.dbfilename) != REDIS_OK) {
11266 addReply(c,shared.err);
11267 return;
11268 }
11269 redisLog(REDIS_WARNING,"DB reloaded by DEBUG RELOAD");
11270 addReply(c,shared.ok);
71c2b467 11271 } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) {
11272 emptyDb();
11273 if (loadAppendOnlyFile(server.appendfilename) != REDIS_OK) {
11274 addReply(c,shared.err);
11275 return;
11276 }
11277 redisLog(REDIS_WARNING,"Append Only File loaded by DEBUG LOADAOF");
11278 addReply(c,shared.ok);
333298da 11279 } else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
09241813 11280 dictEntry *de = dictFind(c->db->dict,c->argv[2]->ptr);
11281 robj *val;
333298da 11282
11283 if (!de) {
11284 addReply(c,shared.nokeyerr);
11285 return;
11286 }
333298da 11287 val = dictGetEntryVal(de);
560db612 11288 if (!server.vm_enabled || (val->storage == REDIS_VM_MEMORY ||
11289 val->storage == REDIS_VM_SWAPPING)) {
07efaf74 11290 char *strenc;
11291 char buf[128];
11292
11293 if (val->encoding < (sizeof(strencoding)/sizeof(char*))) {
11294 strenc = strencoding[val->encoding];
11295 } else {
11296 snprintf(buf,64,"unknown encoding %d\n", val->encoding);
11297 strenc = buf;
11298 }
ace06542 11299 addReplySds(c,sdscatprintf(sdsempty(),
09241813 11300 "+Value at:%p refcount:%d "
07efaf74 11301 "encoding:%s serializedlength:%lld\r\n",
09241813 11302 (void*)val, val->refcount,
07efaf74 11303 strenc, (long long) rdbSavedObjectLen(val,NULL)));
ace06542 11304 } else {
560db612 11305 vmpointer *vp = (vmpointer*) val;
ace06542 11306 addReplySds(c,sdscatprintf(sdsempty(),
09241813 11307 "+Value swapped at: page %llu "
ace06542 11308 "using %llu pages\r\n",
09241813 11309 (unsigned long long) vp->page,
560db612 11310 (unsigned long long) vp->usedpages));
ace06542 11311 }
78ebe4c8 11312 } else if (!strcasecmp(c->argv[1]->ptr,"swapin") && c->argc == 3) {
11313 lookupKeyRead(c->db,c->argv[2]);
11314 addReply(c,shared.ok);
7d30035d 11315 } else if (!strcasecmp(c->argv[1]->ptr,"swapout") && c->argc == 3) {
09241813 11316 dictEntry *de = dictFind(c->db->dict,c->argv[2]->ptr);
11317 robj *val;
560db612 11318 vmpointer *vp;
7d30035d 11319
11320 if (!server.vm_enabled) {
11321 addReplySds(c,sdsnew("-ERR Virtual Memory is disabled\r\n"));
11322 return;
11323 }
11324 if (!de) {
11325 addReply(c,shared.nokeyerr);
11326 return;
11327 }
7d30035d 11328 val = dictGetEntryVal(de);
4ef8de8a 11329 /* Swap it */
560db612 11330 if (val->storage != REDIS_VM_MEMORY) {
7d30035d 11331 addReplySds(c,sdsnew("-ERR This key is not in memory\r\n"));
560db612 11332 } else if (val->refcount != 1) {
11333 addReplySds(c,sdsnew("-ERR Object is shared\r\n"));
11334 } else if ((vp = vmSwapObjectBlocking(val)) != NULL) {
11335 dictGetEntryVal(de) = vp;
7d30035d 11336 addReply(c,shared.ok);
11337 } else {
11338 addReply(c,shared.err);
11339 }
59305dc7 11340 } else if (!strcasecmp(c->argv[1]->ptr,"populate") && c->argc == 3) {
11341 long keys, j;
11342 robj *key, *val;
11343 char buf[128];
11344
11345 if (getLongFromObjectOrReply(c, c->argv[2], &keys, NULL) != REDIS_OK)
11346 return;
11347 for (j = 0; j < keys; j++) {
11348 snprintf(buf,sizeof(buf),"key:%lu",j);
11349 key = createStringObject(buf,strlen(buf));
11350 if (lookupKeyRead(c->db,key) != NULL) {
11351 decrRefCount(key);
11352 continue;
11353 }
11354 snprintf(buf,sizeof(buf),"value:%lu",j);
11355 val = createStringObject(buf,strlen(buf));
09241813 11356 dbAdd(c->db,key,val);
11357 decrRefCount(key);
59305dc7 11358 }
11359 addReply(c,shared.ok);
ba798261 11360 } else if (!strcasecmp(c->argv[1]->ptr,"digest") && c->argc == 2) {
11361 unsigned char digest[20];
11362 sds d = sdsnew("+");
11363 int j;
11364
11365 computeDatasetDigest(digest);
11366 for (j = 0; j < 20; j++)
11367 d = sdscatprintf(d, "%02x",digest[j]);
11368
11369 d = sdscatlen(d,"\r\n",2);
11370 addReplySds(c,d);
7f957c92 11371 } else {
333298da 11372 addReplySds(c,sdsnew(
bdcb92f2 11373 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPIN <key>|SWAPOUT <key>|RELOAD]\r\n"));
7f957c92 11374 }
11375}
56906eef 11376
6c96ba7d 11377static void _redisAssert(char *estr, char *file, int line) {
dfc5e96c 11378 redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
fdfb02e7 11379 redisLog(REDIS_WARNING,"==> %s:%d '%s' is not true",file,line,estr);
dfc5e96c 11380#ifdef HAVE_BACKTRACE
11381 redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
11382 *((char*)-1) = 'x';
11383#endif
11384}
11385
c651fd9e 11386static void _redisPanic(char *msg, char *file, int line) {
11387 redisLog(REDIS_WARNING,"!!! Software Failure. Press left mouse button to continue");
17772754 11388 redisLog(REDIS_WARNING,"Guru Meditation: %s #%s:%d",msg,file,line);
c651fd9e 11389#ifdef HAVE_BACKTRACE
11390 redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
11391 *((char*)-1) = 'x';
11392#endif
11393}
11394
bcfc686d 11395/* =================================== Main! ================================ */
56906eef 11396
bcfc686d 11397#ifdef __linux__
11398int linuxOvercommitMemoryValue(void) {
11399 FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
11400 char buf[64];
56906eef 11401
bcfc686d 11402 if (!fp) return -1;
11403 if (fgets(buf,64,fp) == NULL) {
11404 fclose(fp);
11405 return -1;
11406 }
11407 fclose(fp);
56906eef 11408
bcfc686d 11409 return atoi(buf);
11410}
11411
11412void linuxOvercommitMemoryWarning(void) {
11413 if (linuxOvercommitMemoryValue() == 0) {
7ccd2d0a 11414 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 11415 }
11416}
11417#endif /* __linux__ */
11418
11419static void daemonize(void) {
11420 int fd;
11421 FILE *fp;
11422
11423 if (fork() != 0) exit(0); /* parent exits */
11424 setsid(); /* create a new session */
11425
11426 /* Every output goes to /dev/null. If Redis is daemonized but
11427 * the 'logfile' is set to 'stdout' in the configuration file
11428 * it will not log at all. */
11429 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
11430 dup2(fd, STDIN_FILENO);
11431 dup2(fd, STDOUT_FILENO);
11432 dup2(fd, STDERR_FILENO);
11433 if (fd > STDERR_FILENO) close(fd);
11434 }
11435 /* Try to write the pid file */
11436 fp = fopen(server.pidfile,"w");
11437 if (fp) {
11438 fprintf(fp,"%d\n",getpid());
11439 fclose(fp);
56906eef 11440 }
56906eef 11441}
11442
42ab0172 11443static void version() {
8a3b0d2d 11444 printf("Redis server version %s (%s:%d)\n", REDIS_VERSION,
7c4fc71c 11445 redisGitSHA1(), atoi(redisGitDirty()) > 0);
42ab0172
AO
11446 exit(0);
11447}
11448
723fb69b
AO
11449static void usage() {
11450 fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
e9409273 11451 fprintf(stderr," ./redis-server - (read config from stdin)\n");
723fb69b
AO
11452 exit(1);
11453}
11454
bcfc686d 11455int main(int argc, char **argv) {
9651a787 11456 time_t start;
11457
bcfc686d 11458 initServerConfig();
1a132bbc 11459 sortCommandTable();
bcfc686d 11460 if (argc == 2) {
44efe66e 11461 if (strcmp(argv[1], "-v") == 0 ||
11462 strcmp(argv[1], "--version") == 0) version();
11463 if (strcmp(argv[1], "--help") == 0) usage();
bcfc686d 11464 resetServerSaveParams();
11465 loadServerConfig(argv[1]);
723fb69b
AO
11466 } else if ((argc > 2)) {
11467 usage();
bcfc686d 11468 } else {
11469 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'");
11470 }
bcfc686d 11471 if (server.daemonize) daemonize();
71c54b21 11472 initServer();
bcfc686d 11473 redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
11474#ifdef __linux__
11475 linuxOvercommitMemoryWarning();
11476#endif
9651a787 11477 start = time(NULL);
bcfc686d 11478 if (server.appendonly) {
11479 if (loadAppendOnlyFile(server.appendfilename) == REDIS_OK)
9651a787 11480 redisLog(REDIS_NOTICE,"DB loaded from append only file: %ld seconds",time(NULL)-start);
bcfc686d 11481 } else {
11482 if (rdbLoad(server.dbfilename) == REDIS_OK)
9651a787 11483 redisLog(REDIS_NOTICE,"DB loaded from disk: %ld seconds",time(NULL)-start);
bcfc686d 11484 }
bcfc686d 11485 redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
d5d55fc3 11486 aeSetBeforeSleepProc(server.el,beforeSleep);
bcfc686d 11487 aeMain(server.el);
11488 aeDeleteEventLoop(server.el);
11489 return 0;
11490}
11491
11492/* ============================= Backtrace support ========================= */
11493
11494#ifdef HAVE_BACKTRACE
11495static char *findFuncName(void *pointer, unsigned long *offset);
11496
56906eef 11497static void *getMcontextEip(ucontext_t *uc) {
11498#if defined(__FreeBSD__)
11499 return (void*) uc->uc_mcontext.mc_eip;
11500#elif defined(__dietlibc__)
11501 return (void*) uc->uc_mcontext.eip;
06db1f50 11502#elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
da0a1620 11503 #if __x86_64__
11504 return (void*) uc->uc_mcontext->__ss.__rip;
11505 #else
56906eef 11506 return (void*) uc->uc_mcontext->__ss.__eip;
da0a1620 11507 #endif
06db1f50 11508#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
cb7e07cc 11509 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
06db1f50 11510 return (void*) uc->uc_mcontext->__ss.__rip;
cbc59b38 11511 #else
11512 return (void*) uc->uc_mcontext->__ss.__eip;
e0a62c7f 11513 #endif
54bac49d 11514#elif defined(__i386__) || defined(__X86_64__) || defined(__x86_64__)
c04c9ac9 11515 return (void*) uc->uc_mcontext.gregs[REG_EIP]; /* Linux 32/64 bit */
b91cf5ef 11516#elif defined(__ia64__) /* Linux IA64 */
11517 return (void*) uc->uc_mcontext.sc_ip;
11518#else
11519 return NULL;
56906eef 11520#endif
11521}
11522
11523static void segvHandler(int sig, siginfo_t *info, void *secret) {
11524 void *trace[100];
11525 char **messages = NULL;
11526 int i, trace_size = 0;
11527 unsigned long offset=0;
56906eef 11528 ucontext_t *uc = (ucontext_t*) secret;
1c85b79f 11529 sds infostring;
56906eef 11530 REDIS_NOTUSED(info);
11531
11532 redisLog(REDIS_WARNING,
11533 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION, sig);
1c85b79f 11534 infostring = genRedisInfoString();
11535 redisLog(REDIS_WARNING, "%s",infostring);
11536 /* It's not safe to sdsfree() the returned string under memory
11537 * corruption conditions. Let it leak as we are going to abort */
e0a62c7f 11538
56906eef 11539 trace_size = backtrace(trace, 100);
de96dbfe 11540 /* overwrite sigaction with caller's address */
b91cf5ef 11541 if (getMcontextEip(uc) != NULL) {
11542 trace[1] = getMcontextEip(uc);
11543 }
56906eef 11544 messages = backtrace_symbols(trace, trace_size);
fe3bbfbe 11545
d76412d1 11546 for (i=1; i<trace_size; ++i) {
56906eef 11547 char *fn = findFuncName(trace[i], &offset), *p;
11548
11549 p = strchr(messages[i],'+');
11550 if (!fn || (p && ((unsigned long)strtol(p+1,NULL,10)) < offset)) {
11551 redisLog(REDIS_WARNING,"%s", messages[i]);
11552 } else {
11553 redisLog(REDIS_WARNING,"%d redis-server %p %s + %d", i, trace[i], fn, (unsigned int)offset);
11554 }
11555 }
b177fd30 11556 /* free(messages); Don't call free() with possibly corrupted memory. */
478c2c6f 11557 _exit(0);
fe3bbfbe 11558}
56906eef 11559
fab43727 11560static void sigtermHandler(int sig) {
11561 REDIS_NOTUSED(sig);
b58ba105 11562
fab43727 11563 redisLog(REDIS_WARNING,"SIGTERM received, scheduling shutting down...");
11564 server.shutdown_asap = 1;
b58ba105
AM
11565}
11566
56906eef 11567static void setupSigSegvAction(void) {
11568 struct sigaction act;
11569
11570 sigemptyset (&act.sa_mask);
11571 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
11572 * is used. Otherwise, sa_handler is used */
11573 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
11574 act.sa_sigaction = segvHandler;
11575 sigaction (SIGSEGV, &act, NULL);
11576 sigaction (SIGBUS, &act, NULL);
12fea928 11577 sigaction (SIGFPE, &act, NULL);
11578 sigaction (SIGILL, &act, NULL);
11579 sigaction (SIGBUS, &act, NULL);
b58ba105
AM
11580
11581 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
fab43727 11582 act.sa_handler = sigtermHandler;
b58ba105 11583 sigaction (SIGTERM, &act, NULL);
e65fdc78 11584 return;
56906eef 11585}
e65fdc78 11586
bcfc686d 11587#include "staticsymbols.h"
11588/* This function try to convert a pointer into a function name. It's used in
11589 * oreder to provide a backtrace under segmentation fault that's able to
11590 * display functions declared as static (otherwise the backtrace is useless). */
11591static char *findFuncName(void *pointer, unsigned long *offset){
11592 int i, ret = -1;
11593 unsigned long off, minoff = 0;
ed9b544e 11594
bcfc686d 11595 /* Try to match against the Symbol with the smallest offset */
11596 for (i=0; symsTable[i].pointer; i++) {
11597 unsigned long lp = (unsigned long) pointer;
0bc03378 11598
bcfc686d 11599 if (lp != (unsigned long)-1 && lp >= symsTable[i].pointer) {
11600 off=lp-symsTable[i].pointer;
11601 if (ret < 0 || off < minoff) {
11602 minoff=off;
11603 ret=i;
11604 }
11605 }
0bc03378 11606 }
bcfc686d 11607 if (ret == -1) return NULL;
11608 *offset = minoff;
11609 return symsTable[ret].name;
0bc03378 11610}
bcfc686d 11611#else /* HAVE_BACKTRACE */
11612static void setupSigSegvAction(void) {
0bc03378 11613}
bcfc686d 11614#endif /* HAVE_BACKTRACE */
0bc03378 11615
ed9b544e 11616
ed9b544e 11617
bcfc686d 11618/* The End */
11619
11620
ed9b544e 11621