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