]> git.saurik.com Git - redis.git/blame - redis.c
VM tuning thanks to redis-stat vmstat. Now it performs much better under high load
[redis.git] / redis.c
CommitLineData
ed9b544e 1/*
2 * Copyright (c) 2006-2009, Salvatore Sanfilippo <antirez at gmail dot com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Redis nor the names of its contributors may be used
14 * to endorse or promote products derived from this software without
15 * specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
b0d8747d 30#define REDIS_VERSION "1.3.3"
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>
c9468bcf 40#define __USE_POSIX199309
ed9b544e 41#include <signal.h>
fbf9bcdb 42
43#ifdef HAVE_BACKTRACE
c9468bcf 44#include <execinfo.h>
45#include <ucontext.h>
fbf9bcdb 46#endif /* HAVE_BACKTRACE */
47
ed9b544e 48#include <sys/wait.h>
49#include <errno.h>
50#include <assert.h>
51#include <ctype.h>
52#include <stdarg.h>
53#include <inttypes.h>
54#include <arpa/inet.h>
55#include <sys/stat.h>
56#include <fcntl.h>
57#include <sys/time.h>
58#include <sys/resource.h>
2895e862 59#include <sys/uio.h>
f78fd11b 60#include <limits.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 */
ed9b544e 77
78/* Error codes */
79#define REDIS_OK 0
80#define REDIS_ERR -1
81
82/* Static server configuration */
83#define REDIS_SERVERPORT 6379 /* TCP port */
84#define REDIS_MAXIDLETIME (60*5) /* default client timeout */
6208b3a7 85#define REDIS_IOBUF_LEN 1024
ed9b544e 86#define REDIS_LOADBUF_LEN 1024
93ea3759 87#define REDIS_STATIC_ARGS 4
ed9b544e 88#define REDIS_DEFAULT_DBNUM 16
89#define REDIS_CONFIGLINE_MAX 1024
90#define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
91#define REDIS_MAX_SYNC_TIME 60 /* Slave can't take more to sync */
94754ccc 92#define REDIS_EXPIRELOOKUPS_PER_CRON 100 /* try to expire 100 keys/second */
6f376729 93#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
2895e862 94#define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
95
96/* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
97#define REDIS_WRITEV_THRESHOLD 3
98/* Max number of iovecs used for each writev call */
99#define REDIS_WRITEV_IOVEC_COUNT 256
ed9b544e 100
101/* Hash table parameters */
102#define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
ed9b544e 103
104/* Command flags */
3fd78bcd 105#define REDIS_CMD_BULK 1 /* Bulk write command */
106#define REDIS_CMD_INLINE 2 /* Inline command */
107/* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
108 this flags will return an error when the 'maxmemory' option is set in the
109 config file and the server is using more than maxmemory bytes of memory.
110 In short this commands are denied on low memory conditions. */
111#define REDIS_CMD_DENYOOM 4
ed9b544e 112
113/* Object types */
114#define REDIS_STRING 0
115#define REDIS_LIST 1
116#define REDIS_SET 2
1812e024 117#define REDIS_ZSET 3
118#define REDIS_HASH 4
f78fd11b 119
942a3961 120/* Objects encoding */
121#define REDIS_ENCODING_RAW 0 /* Raw representation */
122#define REDIS_ENCODING_INT 1 /* Encoded as integer */
123
f78fd11b 124/* Object types only used for dumping to disk */
bb32ede5 125#define REDIS_EXPIRETIME 253
ed9b544e 126#define REDIS_SELECTDB 254
127#define REDIS_EOF 255
128
f78fd11b 129/* Defines related to the dump file format. To store 32 bits lengths for short
130 * keys requires a lot of space, so we check the most significant 2 bits of
131 * the first byte to interpreter the length:
132 *
133 * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
134 * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
135 * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
a4d1ba9a 136 * 11|000000 this means: specially encoded object will follow. The six bits
137 * number specify the kind of object that follows.
138 * See the REDIS_RDB_ENC_* defines.
f78fd11b 139 *
10c43610 140 * Lenghts up to 63 are stored using a single byte, most DB keys, and may
141 * values, will fit inside. */
f78fd11b 142#define REDIS_RDB_6BITLEN 0
143#define REDIS_RDB_14BITLEN 1
144#define REDIS_RDB_32BITLEN 2
17be1a4a 145#define REDIS_RDB_ENCVAL 3
f78fd11b 146#define REDIS_RDB_LENERR UINT_MAX
147
a4d1ba9a 148/* When a length of a string object stored on disk has the first two bits
149 * set, the remaining two bits specify a special encoding for the object
150 * accordingly to the following defines: */
151#define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
152#define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
153#define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
774e3047 154#define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
a4d1ba9a 155
75680a3c 156/* Virtual memory object->where field. */
157#define REDIS_VM_MEMORY 0 /* The object is on memory */
158#define REDIS_VM_SWAPPED 1 /* The object is on disk */
159#define REDIS_VM_SWAPPING 2 /* Redis is swapping this object on disk */
160#define REDIS_VM_LOADING 3 /* Redis is loading this object from disk */
161
06224fec 162/* Virtual memory static configuration stuff.
163 * Check vmFindContiguousPages() to know more about this magic numbers. */
164#define REDIS_VM_MAX_NEAR_PAGES 65536
165#define REDIS_VM_MAX_RANDOM_JUMP 4096
92f8e882 166#define REDIS_VM_MAX_THREADS 32
bcaa7a4f 167#define REDIS_THREAD_STACK_SIZE (1024*1024*4)
f6c0bba8 168/* The following is the *percentage* of completed I/O jobs to process when the
169 * handelr is called. While Virtual Memory I/O operations are performed by
170 * threads, this operations must be processed by the main thread when completed
171 * in order to take effect. */
c953f24b 172#define REDIS_MAX_COMPLETED_JOBS_PROCESSED 1
06224fec 173
ed9b544e 174/* Client flags */
175#define REDIS_CLOSE 1 /* This client connection should be closed ASAP */
176#define REDIS_SLAVE 2 /* This client is a slave server */
177#define REDIS_MASTER 4 /* This client is a master server */
87eca727 178#define REDIS_MONITOR 8 /* This client is a slave monitor, see MONITOR */
6e469882 179#define REDIS_MULTI 16 /* This client is in a MULTI context */
4409877e 180#define REDIS_BLOCKED 32 /* The client is waiting in a blocking operation */
996cb5f7 181#define REDIS_IO_WAIT 64 /* The client is waiting for Virtual Memory I/O */
ed9b544e 182
40d224a9 183/* Slave replication state - slave side */
ed9b544e 184#define REDIS_REPL_NONE 0 /* No active replication */
185#define REDIS_REPL_CONNECT 1 /* Must connect to master */
186#define REDIS_REPL_CONNECTED 2 /* Connected to master */
187
40d224a9 188/* Slave replication state - from the point of view of master
189 * Note that in SEND_BULK and ONLINE state the slave receives new updates
190 * in its output queue. In the WAIT_BGSAVE state instead the server is waiting
191 * to start the next background saving in order to send updates to it. */
192#define REDIS_REPL_WAIT_BGSAVE_START 3 /* master waits bgsave to start feeding it */
193#define REDIS_REPL_WAIT_BGSAVE_END 4 /* master waits bgsave to start bulk DB transmission */
194#define REDIS_REPL_SEND_BULK 5 /* master is sending the bulk DB */
195#define REDIS_REPL_ONLINE 6 /* bulk DB already transmitted, receive updates */
196
ed9b544e 197/* List related stuff */
198#define REDIS_HEAD 0
199#define REDIS_TAIL 1
200
201/* Sort operations */
202#define REDIS_SORT_GET 0
443c6409 203#define REDIS_SORT_ASC 1
204#define REDIS_SORT_DESC 2
ed9b544e 205#define REDIS_SORTKEY_MAX 1024
206
207/* Log levels */
208#define REDIS_DEBUG 0
f870935d 209#define REDIS_VERBOSE 1
210#define REDIS_NOTICE 2
211#define REDIS_WARNING 3
ed9b544e 212
213/* Anti-warning macro... */
214#define REDIS_NOTUSED(V) ((void) V)
215
6b47e12e 216#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
217#define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
ed9b544e 218
48f0308a 219/* Append only defines */
220#define APPENDFSYNC_NO 0
221#define APPENDFSYNC_ALWAYS 1
222#define APPENDFSYNC_EVERYSEC 2
223
dfc5e96c 224/* We can print the stacktrace, so our assert is defined this way: */
6c96ba7d 225#define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),exit(1)))
226static void _redisAssert(char *estr, char *file, int line);
dfc5e96c 227
ed9b544e 228/*================================= Data types ============================== */
229
230/* A redis object, that is a type able to hold a string / list / set */
75680a3c 231
232/* The VM object structure */
233struct redisObjectVM {
3a66edc7 234 off_t page; /* the page at witch the object is stored on disk */
235 off_t usedpages; /* number of pages used on disk */
236 time_t atime; /* Last access time */
75680a3c 237} vm;
238
239/* The actual Redis Object */
ed9b544e 240typedef struct redisObject {
ed9b544e 241 void *ptr;
942a3961 242 unsigned char type;
243 unsigned char encoding;
d894161b 244 unsigned char storage; /* If this object is a key, where is the value?
245 * REDIS_VM_MEMORY, REDIS_VM_SWAPPED, ... */
246 unsigned char vtype; /* If this object is a key, and value is swapped out,
247 * this is the type of the swapped out object. */
ed9b544e 248 int refcount;
75680a3c 249 /* VM fields, this are only allocated if VM is active, otherwise the
250 * object allocation function will just allocate
251 * sizeof(redisObjct) minus sizeof(redisObjectVM), so using
252 * Redis without VM active will not have any overhead. */
253 struct redisObjectVM vm;
ed9b544e 254} robj;
255
dfc5e96c 256/* Macro used to initalize a Redis object allocated on the stack.
257 * Note that this macro is taken near the structure definition to make sure
258 * we'll update it when the structure is changed, to avoid bugs like
259 * bug #85 introduced exactly in this way. */
260#define initStaticStringObject(_var,_ptr) do { \
261 _var.refcount = 1; \
262 _var.type = REDIS_STRING; \
263 _var.encoding = REDIS_ENCODING_RAW; \
264 _var.ptr = _ptr; \
3a66edc7 265 if (server.vm_enabled) _var.storage = REDIS_VM_MEMORY; \
dfc5e96c 266} while(0);
267
3305306f 268typedef struct redisDb {
4409877e 269 dict *dict; /* The keyspace for this DB */
270 dict *expires; /* Timeout of keys with a timeout set */
271 dict *blockingkeys; /* Keys with clients waiting for data (BLPOP) */
3305306f 272 int id;
273} redisDb;
274
6e469882 275/* Client MULTI/EXEC state */
276typedef struct multiCmd {
277 robj **argv;
278 int argc;
279 struct redisCommand *cmd;
280} multiCmd;
281
282typedef struct multiState {
283 multiCmd *commands; /* Array of MULTI commands */
284 int count; /* Total number of MULTI commands */
285} multiState;
286
ed9b544e 287/* With multiplexing we need to take per-clinet state.
288 * Clients are taken in a liked list. */
289typedef struct redisClient {
290 int fd;
3305306f 291 redisDb *db;
ed9b544e 292 int dictid;
293 sds querybuf;
e8a74421 294 robj **argv, **mbargv;
295 int argc, mbargc;
40d224a9 296 int bulklen; /* bulk read len. -1 if not in bulk read mode */
e8a74421 297 int multibulk; /* multi bulk command format active */
ed9b544e 298 list *reply;
299 int sentlen;
300 time_t lastinteraction; /* time of the last interaction, used for timeout */
40d224a9 301 int flags; /* REDIS_CLOSE | REDIS_SLAVE | REDIS_MONITOR */
6e469882 302 /* REDIS_MULTI */
40d224a9 303 int slaveseldb; /* slave selected db, if this client is a slave */
304 int authenticated; /* when requirepass is non-NULL */
305 int replstate; /* replication state if this is a slave */
306 int repldbfd; /* replication DB file descriptor */
6e469882 307 long repldboff; /* replication DB file offset */
40d224a9 308 off_t repldbsize; /* replication DB file size */
6e469882 309 multiState mstate; /* MULTI/EXEC state */
b177fd30 310 robj **blockingkeys; /* The key we waiting to terminate a blocking
4409877e 311 * operation such as BLPOP. Otherwise NULL. */
b177fd30 312 int blockingkeysnum; /* Number of blocking keys */
4409877e 313 time_t blockingto; /* Blocking operation timeout. If UNIX current time
314 * is >= blockingto then the operation timed out. */
92f8e882 315 list *io_keys; /* Keys this client is waiting to be loaded from the
316 * swap file in order to continue. */
ed9b544e 317} redisClient;
318
319struct saveparam {
320 time_t seconds;
321 int changes;
322};
323
324/* Global server state structure */
325struct redisServer {
326 int port;
327 int fd;
3305306f 328 redisDb *db;
4409877e 329 dict *sharingpool; /* Poll used for object sharing */
10c43610 330 unsigned int sharingpoolsize;
ed9b544e 331 long long dirty; /* changes to DB from the last save */
332 list *clients;
87eca727 333 list *slaves, *monitors;
ed9b544e 334 char neterr[ANET_ERR_LEN];
335 aeEventLoop *el;
336 int cronloops; /* number of times the cron function run */
337 list *objfreelist; /* A list of freed objects to avoid malloc() */
338 time_t lastsave; /* Unix time of last save succeeede */
5fba9f71 339 size_t usedmemory; /* Used memory in megabytes */
ed9b544e 340 /* Fields used only for stats */
341 time_t stat_starttime; /* server start time */
342 long long stat_numcommands; /* number of processed commands */
343 long long stat_numconnections; /* number of connections received */
344 /* Configuration */
345 int verbosity;
346 int glueoutputbuf;
347 int maxidletime;
348 int dbnum;
349 int daemonize;
44b38ef4 350 int appendonly;
48f0308a 351 int appendfsync;
352 time_t lastfsync;
44b38ef4 353 int appendfd;
354 int appendseldb;
ed329fcf 355 char *pidfile;
9f3c422c 356 pid_t bgsavechildpid;
9d65a1bb 357 pid_t bgrewritechildpid;
358 sds bgrewritebuf; /* buffer taken by parent during oppend only rewrite */
ed9b544e 359 struct saveparam *saveparams;
360 int saveparamslen;
361 char *logfile;
362 char *bindaddr;
363 char *dbfilename;
44b38ef4 364 char *appendfilename;
abcb223e 365 char *requirepass;
10c43610 366 int shareobjects;
121f70cf 367 int rdbcompression;
ed9b544e 368 /* Replication related */
369 int isslave;
d0ccebcf 370 char *masterauth;
ed9b544e 371 char *masterhost;
372 int masterport;
40d224a9 373 redisClient *master; /* client that is master for this slave */
ed9b544e 374 int replstate;
285add55 375 unsigned int maxclients;
4ef8de8a 376 unsigned long long maxmemory;
f86a74e9 377 unsigned int blockedclients;
ed9b544e 378 /* Sort parameters - qsort_r() is only available under BSD so we
379 * have to take this state global, in order to pass it to sortCompare() */
380 int sort_desc;
381 int sort_alpha;
382 int sort_bypattern;
75680a3c 383 /* Virtual memory configuration */
384 int vm_enabled;
054e426d 385 char *vm_swap_file;
75680a3c 386 off_t vm_page_size;
387 off_t vm_pages;
4ef8de8a 388 unsigned long long vm_max_memory;
75680a3c 389 /* Virtual memory state */
390 FILE *vm_fp;
391 int vm_fd;
392 off_t vm_next_page; /* Next probably empty page */
393 off_t vm_near_pages; /* Number of pages allocated sequentially */
06224fec 394 unsigned char *vm_bitmap; /* Bitmap of free/used pages */
3a66edc7 395 time_t unixtime; /* Unix time sampled every second. */
92f8e882 396 /* Virtual memory I/O threads stuff */
92f8e882 397 /* An I/O thread process an element taken from the io_jobs queue and
996cb5f7 398 * put the result of the operation in the io_done list. While the
399 * job is being processed, it's put on io_processing queue. */
400 list *io_newjobs; /* List of VM I/O jobs yet to be processed */
401 list *io_processing; /* List of VM I/O jobs being processed */
402 list *io_processed; /* List of VM I/O jobs already processed */
92f8e882 403 list *io_clients; /* All the clients waiting for SWAP I/O operations */
996cb5f7 404 pthread_mutex_t io_mutex; /* lock to access io_jobs/io_done/io_thread_job */
a5819310 405 pthread_mutex_t obj_freelist_mutex; /* safe redis objects creation/free */
406 pthread_mutex_t io_swapfile_mutex; /* So we can lseek + write */
bcaa7a4f 407 pthread_attr_t io_threads_attr; /* attributes for threads creation */
92f8e882 408 int io_active_threads; /* Number of running I/O threads */
409 int vm_max_threads; /* Max number of I/O threads running at the same time */
996cb5f7 410 /* Our main thread is blocked on the event loop, locking for sockets ready
411 * to be read or written, so when a threaded I/O operation is ready to be
412 * processed by the main thread, the I/O thread will use a unix pipe to
413 * awake the main thread. The followings are the two pipe FDs. */
414 int io_ready_pipe_read;
415 int io_ready_pipe_write;
7d98e08c 416 /* Virtual memory stats */
417 unsigned long long vm_stats_used_pages;
418 unsigned long long vm_stats_swapped_objects;
419 unsigned long long vm_stats_swapouts;
420 unsigned long long vm_stats_swapins;
b9bc0eef 421 FILE *devnull;
ed9b544e 422};
423
424typedef void redisCommandProc(redisClient *c);
425struct redisCommand {
426 char *name;
427 redisCommandProc *proc;
428 int arity;
429 int flags;
430};
431
de96dbfe 432struct redisFunctionSym {
433 char *name;
56906eef 434 unsigned long pointer;
de96dbfe 435};
436
ed9b544e 437typedef struct _redisSortObject {
438 robj *obj;
439 union {
440 double score;
441 robj *cmpobj;
442 } u;
443} redisSortObject;
444
445typedef struct _redisSortOperation {
446 int type;
447 robj *pattern;
448} redisSortOperation;
449
6b47e12e 450/* ZSETs use a specialized version of Skiplists */
451
452typedef struct zskiplistNode {
453 struct zskiplistNode **forward;
e3870fab 454 struct zskiplistNode *backward;
6b47e12e 455 double score;
456 robj *obj;
457} zskiplistNode;
458
459typedef struct zskiplist {
e3870fab 460 struct zskiplistNode *header, *tail;
d13f767c 461 unsigned long length;
6b47e12e 462 int level;
463} zskiplist;
464
1812e024 465typedef struct zset {
466 dict *dict;
6b47e12e 467 zskiplist *zsl;
1812e024 468} zset;
469
6b47e12e 470/* Our shared "common" objects */
471
ed9b544e 472struct sharedObjectsStruct {
c937aa89 473 robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *pong, *space,
6e469882 474 *colon, *nullbulk, *nullmultibulk, *queued,
c937aa89 475 *emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr,
476 *outofrangeerr, *plus,
ed9b544e 477 *select0, *select1, *select2, *select3, *select4,
478 *select5, *select6, *select7, *select8, *select9;
479} shared;
480
a7866db6 481/* Global vars that are actally used as constants. The following double
482 * values are used for double on-disk serialization, and are initialized
483 * at runtime to avoid strange compiler optimizations. */
484
485static double R_Zero, R_PosInf, R_NegInf, R_Nan;
486
92f8e882 487/* VM threaded I/O request message */
b9bc0eef 488#define REDIS_IOJOB_LOAD 0 /* Load from disk to memory */
489#define REDIS_IOJOB_PREPARE_SWAP 1 /* Compute needed pages */
490#define REDIS_IOJOB_DO_SWAP 2 /* Swap from memory to disk */
996cb5f7 491typedef struct iojon {
492 int type; /* Request type, REDIS_IOJOB_* */
b9bc0eef 493 redisDb *db;/* Redis database */
92f8e882 494 robj *key; /* This I/O request is about swapping this key */
b9bc0eef 495 robj *val; /* the value to swap for REDIS_IOREQ_*_SWAP, otherwise this
92f8e882 496 * field is populated by the I/O thread for REDIS_IOREQ_LOAD. */
497 off_t page; /* Swap page where to read/write the object */
b9bc0eef 498 off_t pages; /* Swap pages needed to safe object. PREPARE_SWAP return val */
996cb5f7 499 int canceled; /* True if this command was canceled by blocking side of VM */
500 pthread_t thread; /* ID of the thread processing this entry */
501} iojob;
92f8e882 502
ed9b544e 503/*================================ Prototypes =============================== */
504
505static void freeStringObject(robj *o);
506static void freeListObject(robj *o);
507static void freeSetObject(robj *o);
508static void decrRefCount(void *o);
509static robj *createObject(int type, void *ptr);
510static void freeClient(redisClient *c);
f78fd11b 511static int rdbLoad(char *filename);
ed9b544e 512static void addReply(redisClient *c, robj *obj);
513static void addReplySds(redisClient *c, sds s);
514static void incrRefCount(robj *o);
f78fd11b 515static int rdbSaveBackground(char *filename);
ed9b544e 516static robj *createStringObject(char *ptr, size_t len);
4ef8de8a 517static robj *dupStringObject(robj *o);
87eca727 518static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc);
44b38ef4 519static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc);
ed9b544e 520static int syncWithMaster(void);
10c43610 521static robj *tryObjectSharing(robj *o);
942a3961 522static int tryObjectEncoding(robj *o);
9d65a1bb 523static robj *getDecodedObject(robj *o);
3305306f 524static int removeExpire(redisDb *db, robj *key);
525static int expireIfNeeded(redisDb *db, robj *key);
526static int deleteIfVolatile(redisDb *db, robj *key);
1b03836c 527static int deleteIfSwapped(redisDb *db, robj *key);
94754ccc 528static int deleteKey(redisDb *db, robj *key);
bb32ede5 529static time_t getExpire(redisDb *db, robj *key);
530static int setExpire(redisDb *db, robj *key, time_t when);
a3b21203 531static void updateSlavesWaitingBgsave(int bgsaveerr);
3fd78bcd 532static void freeMemoryIfNeeded(void);
de96dbfe 533static int processCommand(redisClient *c);
56906eef 534static void setupSigSegvAction(void);
a3b21203 535static void rdbRemoveTempFile(pid_t childpid);
9d65a1bb 536static void aofRemoveTempFile(pid_t childpid);
0ea663ea 537static size_t stringObjectLen(robj *o);
638e42ac 538static void processInputBuffer(redisClient *c);
6b47e12e 539static zskiplist *zslCreate(void);
fd8ccf44 540static void zslFree(zskiplist *zsl);
2b59cfdf 541static void zslInsert(zskiplist *zsl, double score, robj *obj);
2895e862 542static void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask);
6e469882 543static void initClientMultiState(redisClient *c);
544static void freeClientMultiState(redisClient *c);
545static void queueMultiCommand(redisClient *c, struct redisCommand *cmd);
b0d8747d 546static void unblockClientWaitingData(redisClient *c);
4409877e 547static int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele);
75680a3c 548static void vmInit(void);
a35ddf12 549static void vmMarkPagesFree(off_t page, off_t count);
55cf8433 550static robj *vmLoadObject(robj *key);
7e69548d 551static robj *vmPreviewObject(robj *key);
a69a0c9c 552static int vmSwapOneObjectBlocking(void);
553static int vmSwapOneObjectThreaded(void);
7e69548d 554static int vmCanSwapOut(void);
a5819310 555static int tryFreeOneObjectFromFreelist(void);
996cb5f7 556static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask);
557static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata, int mask);
558static void vmCancelThreadedIOJob(robj *o);
b9bc0eef 559static void lockThreadedIO(void);
560static void unlockThreadedIO(void);
561static int vmSwapObjectThreaded(robj *key, robj *val, redisDb *db);
562static void freeIOJob(iojob *j);
563static void queueIOJob(iojob *j);
a5819310 564static int vmWriteObjectOnSwap(robj *o, off_t page);
565static robj *vmReadObjectFromSwap(off_t page, int type);
054e426d 566static void waitEmptyIOJobsQueue(void);
567static void vmReopenSwapFile(void);
970e10bb 568static int vmFreePage(off_t page);
ed9b544e 569
abcb223e 570static void authCommand(redisClient *c);
ed9b544e 571static void pingCommand(redisClient *c);
572static void echoCommand(redisClient *c);
573static void setCommand(redisClient *c);
574static void setnxCommand(redisClient *c);
575static void getCommand(redisClient *c);
576static void delCommand(redisClient *c);
577static void existsCommand(redisClient *c);
578static void incrCommand(redisClient *c);
579static void decrCommand(redisClient *c);
580static void incrbyCommand(redisClient *c);
581static void decrbyCommand(redisClient *c);
582static void selectCommand(redisClient *c);
583static void randomkeyCommand(redisClient *c);
584static void keysCommand(redisClient *c);
585static void dbsizeCommand(redisClient *c);
586static void lastsaveCommand(redisClient *c);
587static void saveCommand(redisClient *c);
588static void bgsaveCommand(redisClient *c);
9d65a1bb 589static void bgrewriteaofCommand(redisClient *c);
ed9b544e 590static void shutdownCommand(redisClient *c);
591static void moveCommand(redisClient *c);
592static void renameCommand(redisClient *c);
593static void renamenxCommand(redisClient *c);
594static void lpushCommand(redisClient *c);
595static void rpushCommand(redisClient *c);
596static void lpopCommand(redisClient *c);
597static void rpopCommand(redisClient *c);
598static void llenCommand(redisClient *c);
599static void lindexCommand(redisClient *c);
600static void lrangeCommand(redisClient *c);
601static void ltrimCommand(redisClient *c);
602static void typeCommand(redisClient *c);
603static void lsetCommand(redisClient *c);
604static void saddCommand(redisClient *c);
605static void sremCommand(redisClient *c);
a4460ef4 606static void smoveCommand(redisClient *c);
ed9b544e 607static void sismemberCommand(redisClient *c);
608static void scardCommand(redisClient *c);
12fea928 609static void spopCommand(redisClient *c);
2abb95a9 610static void srandmemberCommand(redisClient *c);
ed9b544e 611static void sinterCommand(redisClient *c);
612static void sinterstoreCommand(redisClient *c);
40d224a9 613static void sunionCommand(redisClient *c);
614static void sunionstoreCommand(redisClient *c);
f4f56e1d 615static void sdiffCommand(redisClient *c);
616static void sdiffstoreCommand(redisClient *c);
ed9b544e 617static void syncCommand(redisClient *c);
618static void flushdbCommand(redisClient *c);
619static void flushallCommand(redisClient *c);
620static void sortCommand(redisClient *c);
621static void lremCommand(redisClient *c);
0f5f7e9a 622static void rpoplpushcommand(redisClient *c);
ed9b544e 623static void infoCommand(redisClient *c);
70003d28 624static void mgetCommand(redisClient *c);
87eca727 625static void monitorCommand(redisClient *c);
3305306f 626static void expireCommand(redisClient *c);
802e8373 627static void expireatCommand(redisClient *c);
f6b141c5 628static void getsetCommand(redisClient *c);
fd88489a 629static void ttlCommand(redisClient *c);
321b0e13 630static void slaveofCommand(redisClient *c);
7f957c92 631static void debugCommand(redisClient *c);
f6b141c5 632static void msetCommand(redisClient *c);
633static void msetnxCommand(redisClient *c);
fd8ccf44 634static void zaddCommand(redisClient *c);
7db723ad 635static void zincrbyCommand(redisClient *c);
cc812361 636static void zrangeCommand(redisClient *c);
50c55df5 637static void zrangebyscoreCommand(redisClient *c);
e3870fab 638static void zrevrangeCommand(redisClient *c);
3c41331e 639static void zcardCommand(redisClient *c);
1b7106e7 640static void zremCommand(redisClient *c);
6e333bbe 641static void zscoreCommand(redisClient *c);
1807985b 642static void zremrangebyscoreCommand(redisClient *c);
6e469882 643static void multiCommand(redisClient *c);
644static void execCommand(redisClient *c);
4409877e 645static void blpopCommand(redisClient *c);
646static void brpopCommand(redisClient *c);
f6b141c5 647
ed9b544e 648/*================================= Globals ================================= */
649
650/* Global vars */
651static struct redisServer server; /* server global state */
652static struct redisCommand cmdTable[] = {
653 {"get",getCommand,2,REDIS_CMD_INLINE},
3fd78bcd 654 {"set",setCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
655 {"setnx",setnxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
5109cdff 656 {"del",delCommand,-2,REDIS_CMD_INLINE},
ed9b544e 657 {"exists",existsCommand,2,REDIS_CMD_INLINE},
3fd78bcd 658 {"incr",incrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
659 {"decr",decrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
70003d28 660 {"mget",mgetCommand,-2,REDIS_CMD_INLINE},
3fd78bcd 661 {"rpush",rpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
662 {"lpush",lpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 663 {"rpop",rpopCommand,2,REDIS_CMD_INLINE},
664 {"lpop",lpopCommand,2,REDIS_CMD_INLINE},
b177fd30 665 {"brpop",brpopCommand,-3,REDIS_CMD_INLINE},
666 {"blpop",blpopCommand,-3,REDIS_CMD_INLINE},
ed9b544e 667 {"llen",llenCommand,2,REDIS_CMD_INLINE},
668 {"lindex",lindexCommand,3,REDIS_CMD_INLINE},
3fd78bcd 669 {"lset",lsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 670 {"lrange",lrangeCommand,4,REDIS_CMD_INLINE},
671 {"ltrim",ltrimCommand,4,REDIS_CMD_INLINE},
672 {"lrem",lremCommand,4,REDIS_CMD_BULK},
b0d8747d 673 {"rpoplpush",rpoplpushcommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
3fd78bcd 674 {"sadd",saddCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 675 {"srem",sremCommand,3,REDIS_CMD_BULK},
a4460ef4 676 {"smove",smoveCommand,4,REDIS_CMD_BULK},
ed9b544e 677 {"sismember",sismemberCommand,3,REDIS_CMD_BULK},
678 {"scard",scardCommand,2,REDIS_CMD_INLINE},
12fea928 679 {"spop",spopCommand,2,REDIS_CMD_INLINE},
2abb95a9 680 {"srandmember",srandmemberCommand,2,REDIS_CMD_INLINE},
3fd78bcd 681 {"sinter",sinterCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
682 {"sinterstore",sinterstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
683 {"sunion",sunionCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
684 {"sunionstore",sunionstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
685 {"sdiff",sdiffCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
686 {"sdiffstore",sdiffstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
ed9b544e 687 {"smembers",sinterCommand,2,REDIS_CMD_INLINE},
fd8ccf44 688 {"zadd",zaddCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
7db723ad 689 {"zincrby",zincrbyCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
1b7106e7 690 {"zrem",zremCommand,3,REDIS_CMD_BULK},
1807985b 691 {"zremrangebyscore",zremrangebyscoreCommand,4,REDIS_CMD_INLINE},
752da584 692 {"zrange",zrangeCommand,-4,REDIS_CMD_INLINE},
80181f78 693 {"zrangebyscore",zrangebyscoreCommand,-4,REDIS_CMD_INLINE},
752da584 694 {"zrevrange",zrevrangeCommand,-4,REDIS_CMD_INLINE},
3c41331e 695 {"zcard",zcardCommand,2,REDIS_CMD_INLINE},
6e333bbe 696 {"zscore",zscoreCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
3fd78bcd 697 {"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
698 {"decrby",decrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
f6b141c5 699 {"getset",getsetCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
700 {"mset",msetCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
701 {"msetnx",msetnxCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
ed9b544e 702 {"randomkey",randomkeyCommand,1,REDIS_CMD_INLINE},
703 {"select",selectCommand,2,REDIS_CMD_INLINE},
704 {"move",moveCommand,3,REDIS_CMD_INLINE},
705 {"rename",renameCommand,3,REDIS_CMD_INLINE},
706 {"renamenx",renamenxCommand,3,REDIS_CMD_INLINE},
321b0e13 707 {"expire",expireCommand,3,REDIS_CMD_INLINE},
802e8373 708 {"expireat",expireatCommand,3,REDIS_CMD_INLINE},
ed9b544e 709 {"keys",keysCommand,2,REDIS_CMD_INLINE},
710 {"dbsize",dbsizeCommand,1,REDIS_CMD_INLINE},
abcb223e 711 {"auth",authCommand,2,REDIS_CMD_INLINE},
ed9b544e 712 {"ping",pingCommand,1,REDIS_CMD_INLINE},
713 {"echo",echoCommand,2,REDIS_CMD_BULK},
714 {"save",saveCommand,1,REDIS_CMD_INLINE},
715 {"bgsave",bgsaveCommand,1,REDIS_CMD_INLINE},
9d65a1bb 716 {"bgrewriteaof",bgrewriteaofCommand,1,REDIS_CMD_INLINE},
ed9b544e 717 {"shutdown",shutdownCommand,1,REDIS_CMD_INLINE},
718 {"lastsave",lastsaveCommand,1,REDIS_CMD_INLINE},
719 {"type",typeCommand,2,REDIS_CMD_INLINE},
6e469882 720 {"multi",multiCommand,1,REDIS_CMD_INLINE},
721 {"exec",execCommand,1,REDIS_CMD_INLINE},
ed9b544e 722 {"sync",syncCommand,1,REDIS_CMD_INLINE},
723 {"flushdb",flushdbCommand,1,REDIS_CMD_INLINE},
724 {"flushall",flushallCommand,1,REDIS_CMD_INLINE},
3fd78bcd 725 {"sort",sortCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
ed9b544e 726 {"info",infoCommand,1,REDIS_CMD_INLINE},
87eca727 727 {"monitor",monitorCommand,1,REDIS_CMD_INLINE},
fd88489a 728 {"ttl",ttlCommand,2,REDIS_CMD_INLINE},
321b0e13 729 {"slaveof",slaveofCommand,3,REDIS_CMD_INLINE},
7f957c92 730 {"debug",debugCommand,-2,REDIS_CMD_INLINE},
ed9b544e 731 {NULL,NULL,0,0}
732};
bcfc686d 733
ed9b544e 734/*============================ Utility functions ============================ */
735
736/* Glob-style pattern matching. */
737int stringmatchlen(const char *pattern, int patternLen,
738 const char *string, int stringLen, int nocase)
739{
740 while(patternLen) {
741 switch(pattern[0]) {
742 case '*':
743 while (pattern[1] == '*') {
744 pattern++;
745 patternLen--;
746 }
747 if (patternLen == 1)
748 return 1; /* match */
749 while(stringLen) {
750 if (stringmatchlen(pattern+1, patternLen-1,
751 string, stringLen, nocase))
752 return 1; /* match */
753 string++;
754 stringLen--;
755 }
756 return 0; /* no match */
757 break;
758 case '?':
759 if (stringLen == 0)
760 return 0; /* no match */
761 string++;
762 stringLen--;
763 break;
764 case '[':
765 {
766 int not, match;
767
768 pattern++;
769 patternLen--;
770 not = pattern[0] == '^';
771 if (not) {
772 pattern++;
773 patternLen--;
774 }
775 match = 0;
776 while(1) {
777 if (pattern[0] == '\\') {
778 pattern++;
779 patternLen--;
780 if (pattern[0] == string[0])
781 match = 1;
782 } else if (pattern[0] == ']') {
783 break;
784 } else if (patternLen == 0) {
785 pattern--;
786 patternLen++;
787 break;
788 } else if (pattern[1] == '-' && patternLen >= 3) {
789 int start = pattern[0];
790 int end = pattern[2];
791 int c = string[0];
792 if (start > end) {
793 int t = start;
794 start = end;
795 end = t;
796 }
797 if (nocase) {
798 start = tolower(start);
799 end = tolower(end);
800 c = tolower(c);
801 }
802 pattern += 2;
803 patternLen -= 2;
804 if (c >= start && c <= end)
805 match = 1;
806 } else {
807 if (!nocase) {
808 if (pattern[0] == string[0])
809 match = 1;
810 } else {
811 if (tolower((int)pattern[0]) == tolower((int)string[0]))
812 match = 1;
813 }
814 }
815 pattern++;
816 patternLen--;
817 }
818 if (not)
819 match = !match;
820 if (!match)
821 return 0; /* no match */
822 string++;
823 stringLen--;
824 break;
825 }
826 case '\\':
827 if (patternLen >= 2) {
828 pattern++;
829 patternLen--;
830 }
831 /* fall through */
832 default:
833 if (!nocase) {
834 if (pattern[0] != string[0])
835 return 0; /* no match */
836 } else {
837 if (tolower((int)pattern[0]) != tolower((int)string[0]))
838 return 0; /* no match */
839 }
840 string++;
841 stringLen--;
842 break;
843 }
844 pattern++;
845 patternLen--;
846 if (stringLen == 0) {
847 while(*pattern == '*') {
848 pattern++;
849 patternLen--;
850 }
851 break;
852 }
853 }
854 if (patternLen == 0 && stringLen == 0)
855 return 1;
856 return 0;
857}
858
56906eef 859static void redisLog(int level, const char *fmt, ...) {
ed9b544e 860 va_list ap;
861 FILE *fp;
862
863 fp = (server.logfile == NULL) ? stdout : fopen(server.logfile,"a");
864 if (!fp) return;
865
866 va_start(ap, fmt);
867 if (level >= server.verbosity) {
868 char *c = ".-*";
1904ecc1 869 char buf[64];
870 time_t now;
871
872 now = time(NULL);
6c9385e0 873 strftime(buf,64,"%d %b %H:%M:%S",localtime(&now));
054e426d 874 fprintf(fp,"[%d] %s %c ",(int)getpid(),buf,c[level]);
ed9b544e 875 vfprintf(fp, fmt, ap);
876 fprintf(fp,"\n");
877 fflush(fp);
878 }
879 va_end(ap);
880
881 if (server.logfile) fclose(fp);
882}
883
884/*====================== Hash table type implementation ==================== */
885
886/* This is an hash table type that uses the SDS dynamic strings libary as
887 * keys and radis objects as values (objects can hold SDS strings,
888 * lists, sets). */
889
1812e024 890static void dictVanillaFree(void *privdata, void *val)
891{
892 DICT_NOTUSED(privdata);
893 zfree(val);
894}
895
4409877e 896static void dictListDestructor(void *privdata, void *val)
897{
898 DICT_NOTUSED(privdata);
899 listRelease((list*)val);
900}
901
ed9b544e 902static int sdsDictKeyCompare(void *privdata, const void *key1,
903 const void *key2)
904{
905 int l1,l2;
906 DICT_NOTUSED(privdata);
907
908 l1 = sdslen((sds)key1);
909 l2 = sdslen((sds)key2);
910 if (l1 != l2) return 0;
911 return memcmp(key1, key2, l1) == 0;
912}
913
914static void dictRedisObjectDestructor(void *privdata, void *val)
915{
916 DICT_NOTUSED(privdata);
917
a35ddf12 918 if (val == NULL) return; /* Values of swapped out keys as set to NULL */
ed9b544e 919 decrRefCount(val);
920}
921
942a3961 922static int dictObjKeyCompare(void *privdata, const void *key1,
ed9b544e 923 const void *key2)
924{
925 const robj *o1 = key1, *o2 = key2;
926 return sdsDictKeyCompare(privdata,o1->ptr,o2->ptr);
927}
928
942a3961 929static unsigned int dictObjHash(const void *key) {
ed9b544e 930 const robj *o = key;
931 return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
932}
933
942a3961 934static int dictEncObjKeyCompare(void *privdata, const void *key1,
935 const void *key2)
936{
9d65a1bb 937 robj *o1 = (robj*) key1, *o2 = (robj*) key2;
938 int cmp;
942a3961 939
9d65a1bb 940 o1 = getDecodedObject(o1);
941 o2 = getDecodedObject(o2);
942 cmp = sdsDictKeyCompare(privdata,o1->ptr,o2->ptr);
943 decrRefCount(o1);
944 decrRefCount(o2);
945 return cmp;
942a3961 946}
947
948static unsigned int dictEncObjHash(const void *key) {
9d65a1bb 949 robj *o = (robj*) key;
942a3961 950
9d65a1bb 951 o = getDecodedObject(o);
952 unsigned int hash = dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
953 decrRefCount(o);
954 return hash;
942a3961 955}
956
f2d9f50f 957/* Sets type and expires */
ed9b544e 958static dictType setDictType = {
942a3961 959 dictEncObjHash, /* hash function */
ed9b544e 960 NULL, /* key dup */
961 NULL, /* val dup */
942a3961 962 dictEncObjKeyCompare, /* key compare */
ed9b544e 963 dictRedisObjectDestructor, /* key destructor */
964 NULL /* val destructor */
965};
966
f2d9f50f 967/* Sorted sets hash (note: a skiplist is used in addition to the hash table) */
1812e024 968static dictType zsetDictType = {
969 dictEncObjHash, /* hash function */
970 NULL, /* key dup */
971 NULL, /* val dup */
972 dictEncObjKeyCompare, /* key compare */
973 dictRedisObjectDestructor, /* key destructor */
da0a1620 974 dictVanillaFree /* val destructor of malloc(sizeof(double)) */
1812e024 975};
976
f2d9f50f 977/* Db->dict */
ed9b544e 978static dictType hashDictType = {
942a3961 979 dictObjHash, /* hash function */
ed9b544e 980 NULL, /* key dup */
981 NULL, /* val dup */
942a3961 982 dictObjKeyCompare, /* key compare */
ed9b544e 983 dictRedisObjectDestructor, /* key destructor */
984 dictRedisObjectDestructor /* val destructor */
985};
986
f2d9f50f 987/* Db->expires */
988static dictType keyptrDictType = {
989 dictObjHash, /* hash function */
990 NULL, /* key dup */
991 NULL, /* val dup */
992 dictObjKeyCompare, /* key compare */
993 dictRedisObjectDestructor, /* key destructor */
994 NULL /* val destructor */
995};
996
4409877e 997/* Keylist hash table type has unencoded redis objects as keys and
998 * lists as values. It's used for blocking operations (BLPOP) */
999static dictType keylistDictType = {
1000 dictObjHash, /* hash function */
1001 NULL, /* key dup */
1002 NULL, /* val dup */
1003 dictObjKeyCompare, /* key compare */
1004 dictRedisObjectDestructor, /* key destructor */
1005 dictListDestructor /* val destructor */
1006};
1007
ed9b544e 1008/* ========================= Random utility functions ======================= */
1009
1010/* Redis generally does not try to recover from out of memory conditions
1011 * when allocating objects or strings, it is not clear if it will be possible
1012 * to report this condition to the client since the networking layer itself
1013 * is based on heap allocation for send buffers, so we simply abort.
1014 * At least the code will be simpler to read... */
1015static void oom(const char *msg) {
71c54b21 1016 redisLog(REDIS_WARNING, "%s: Out of memory\n",msg);
ed9b544e 1017 sleep(1);
1018 abort();
1019}
1020
1021/* ====================== Redis server networking stuff ===================== */
56906eef 1022static void closeTimedoutClients(void) {
ed9b544e 1023 redisClient *c;
ed9b544e 1024 listNode *ln;
1025 time_t now = time(NULL);
c7df85a4 1026 listIter li;
ed9b544e 1027
c7df85a4 1028 listRewind(server.clients,&li);
1029 while ((ln = listNext(&li)) != NULL) {
ed9b544e 1030 c = listNodeValue(ln);
f86a74e9 1031 if (server.maxidletime &&
1032 !(c->flags & REDIS_SLAVE) && /* no timeout for slaves */
c7cf2ec9 1033 !(c->flags & REDIS_MASTER) && /* no timeout for masters */
f86a74e9 1034 (now - c->lastinteraction > server.maxidletime))
1035 {
f870935d 1036 redisLog(REDIS_VERBOSE,"Closing idle client");
ed9b544e 1037 freeClient(c);
f86a74e9 1038 } else if (c->flags & REDIS_BLOCKED) {
58d976b8 1039 if (c->blockingto != 0 && c->blockingto < now) {
b177fd30 1040 addReply(c,shared.nullmultibulk);
b0d8747d 1041 unblockClientWaitingData(c);
f86a74e9 1042 }
ed9b544e 1043 }
1044 }
ed9b544e 1045}
1046
12fea928 1047static int htNeedsResize(dict *dict) {
1048 long long size, used;
1049
1050 size = dictSlots(dict);
1051 used = dictSize(dict);
1052 return (size && used && size > DICT_HT_INITIAL_SIZE &&
1053 (used*100/size < REDIS_HT_MINFILL));
1054}
1055
0bc03378 1056/* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL
1057 * we resize the hash table to save memory */
56906eef 1058static void tryResizeHashTables(void) {
0bc03378 1059 int j;
1060
1061 for (j = 0; j < server.dbnum; j++) {
12fea928 1062 if (htNeedsResize(server.db[j].dict)) {
f870935d 1063 redisLog(REDIS_VERBOSE,"The hash table %d is too sparse, resize it...",j);
0bc03378 1064 dictResize(server.db[j].dict);
f870935d 1065 redisLog(REDIS_VERBOSE,"Hash table %d resized.",j);
0bc03378 1066 }
12fea928 1067 if (htNeedsResize(server.db[j].expires))
1068 dictResize(server.db[j].expires);
0bc03378 1069 }
1070}
1071
9d65a1bb 1072/* A background saving child (BGSAVE) terminated its work. Handle this. */
1073void backgroundSaveDoneHandler(int statloc) {
1074 int exitcode = WEXITSTATUS(statloc);
1075 int bysignal = WIFSIGNALED(statloc);
1076
1077 if (!bysignal && exitcode == 0) {
1078 redisLog(REDIS_NOTICE,
1079 "Background saving terminated with success");
1080 server.dirty = 0;
1081 server.lastsave = time(NULL);
1082 } else if (!bysignal && exitcode != 0) {
1083 redisLog(REDIS_WARNING, "Background saving error");
1084 } else {
1085 redisLog(REDIS_WARNING,
1086 "Background saving terminated by signal");
1087 rdbRemoveTempFile(server.bgsavechildpid);
1088 }
1089 server.bgsavechildpid = -1;
1090 /* Possibly there are slaves waiting for a BGSAVE in order to be served
1091 * (the first stage of SYNC is a bulk transfer of dump.rdb) */
1092 updateSlavesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR);
1093}
1094
1095/* A background append only file rewriting (BGREWRITEAOF) terminated its work.
1096 * Handle this. */
1097void backgroundRewriteDoneHandler(int statloc) {
1098 int exitcode = WEXITSTATUS(statloc);
1099 int bysignal = WIFSIGNALED(statloc);
1100
1101 if (!bysignal && exitcode == 0) {
1102 int fd;
1103 char tmpfile[256];
1104
1105 redisLog(REDIS_NOTICE,
1106 "Background append only file rewriting terminated with success");
1107 /* Now it's time to flush the differences accumulated by the parent */
1108 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) server.bgrewritechildpid);
1109 fd = open(tmpfile,O_WRONLY|O_APPEND);
1110 if (fd == -1) {
1111 redisLog(REDIS_WARNING, "Not able to open the temp append only file produced by the child: %s", strerror(errno));
1112 goto cleanup;
1113 }
1114 /* Flush our data... */
1115 if (write(fd,server.bgrewritebuf,sdslen(server.bgrewritebuf)) !=
1116 (signed) sdslen(server.bgrewritebuf)) {
1117 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));
1118 close(fd);
1119 goto cleanup;
1120 }
b32627cd 1121 redisLog(REDIS_NOTICE,"Parent diff flushed into the new append log file with success (%lu bytes)",sdslen(server.bgrewritebuf));
9d65a1bb 1122 /* Now our work is to rename the temp file into the stable file. And
1123 * switch the file descriptor used by the server for append only. */
1124 if (rename(tmpfile,server.appendfilename) == -1) {
1125 redisLog(REDIS_WARNING,"Can't rename the temp append only file into the stable one: %s", strerror(errno));
1126 close(fd);
1127 goto cleanup;
1128 }
1129 /* Mission completed... almost */
1130 redisLog(REDIS_NOTICE,"Append only file successfully rewritten.");
1131 if (server.appendfd != -1) {
1132 /* If append only is actually enabled... */
1133 close(server.appendfd);
1134 server.appendfd = fd;
1135 fsync(fd);
85a83172 1136 server.appendseldb = -1; /* Make sure it will issue SELECT */
9d65a1bb 1137 redisLog(REDIS_NOTICE,"The new append only file was selected for future appends.");
1138 } else {
1139 /* If append only is disabled we just generate a dump in this
1140 * format. Why not? */
1141 close(fd);
1142 }
1143 } else if (!bysignal && exitcode != 0) {
1144 redisLog(REDIS_WARNING, "Background append only file rewriting error");
1145 } else {
1146 redisLog(REDIS_WARNING,
1147 "Background append only file rewriting terminated by signal");
1148 }
1149cleanup:
1150 sdsfree(server.bgrewritebuf);
1151 server.bgrewritebuf = sdsempty();
1152 aofRemoveTempFile(server.bgrewritechildpid);
1153 server.bgrewritechildpid = -1;
1154}
1155
56906eef 1156static int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
94754ccc 1157 int j, loops = server.cronloops++;
ed9b544e 1158 REDIS_NOTUSED(eventLoop);
1159 REDIS_NOTUSED(id);
1160 REDIS_NOTUSED(clientData);
1161
3a66edc7 1162 /* We take a cached value of the unix time in the global state because
1163 * with virtual memory and aging there is to store the current time
1164 * in objects at every object access, and accuracy is not needed.
1165 * To access a global var is faster than calling time(NULL) */
1166 server.unixtime = time(NULL);
1167
ed9b544e 1168 /* Update the global state with the amount of used memory */
1169 server.usedmemory = zmalloc_used_memory();
1170
0bc03378 1171 /* Show some info about non-empty databases */
ed9b544e 1172 for (j = 0; j < server.dbnum; j++) {
dec423d9 1173 long long size, used, vkeys;
94754ccc 1174
3305306f 1175 size = dictSlots(server.db[j].dict);
1176 used = dictSize(server.db[j].dict);
94754ccc 1177 vkeys = dictSize(server.db[j].expires);
c3cb078d 1178 if (!(loops % 5) && (used || vkeys)) {
f870935d 1179 redisLog(REDIS_VERBOSE,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j,used,vkeys,size);
a4d1ba9a 1180 /* dictPrintStats(server.dict); */
ed9b544e 1181 }
ed9b544e 1182 }
1183
0bc03378 1184 /* We don't want to resize the hash tables while a bacground saving
1185 * is in progress: the saving child is created using fork() that is
1186 * implemented with a copy-on-write semantic in most modern systems, so
1187 * if we resize the HT while there is the saving child at work actually
1188 * a lot of memory movements in the parent will cause a lot of pages
1189 * copied. */
9d65a1bb 1190 if (server.bgsavechildpid == -1) tryResizeHashTables();
0bc03378 1191
ed9b544e 1192 /* Show information about connected clients */
1193 if (!(loops % 5)) {
f870935d 1194 redisLog(REDIS_VERBOSE,"%d clients connected (%d slaves), %zu bytes in use, %d shared objects",
ed9b544e 1195 listLength(server.clients)-listLength(server.slaves),
1196 listLength(server.slaves),
10c43610 1197 server.usedmemory,
3305306f 1198 dictSize(server.sharingpool));
ed9b544e 1199 }
1200
1201 /* Close connections of timedout clients */
f86a74e9 1202 if ((server.maxidletime && !(loops % 10)) || server.blockedclients)
ed9b544e 1203 closeTimedoutClients();
1204
9d65a1bb 1205 /* Check if a background saving or AOF rewrite in progress terminated */
1206 if (server.bgsavechildpid != -1 || server.bgrewritechildpid != -1) {
ed9b544e 1207 int statloc;
9d65a1bb 1208 pid_t pid;
1209
1210 if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
1211 if (pid == server.bgsavechildpid) {
1212 backgroundSaveDoneHandler(statloc);
ed9b544e 1213 } else {
9d65a1bb 1214 backgroundRewriteDoneHandler(statloc);
ed9b544e 1215 }
ed9b544e 1216 }
1217 } else {
1218 /* If there is not a background saving in progress check if
1219 * we have to save now */
1220 time_t now = time(NULL);
1221 for (j = 0; j < server.saveparamslen; j++) {
1222 struct saveparam *sp = server.saveparams+j;
1223
1224 if (server.dirty >= sp->changes &&
1225 now-server.lastsave > sp->seconds) {
1226 redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...",
1227 sp->changes, sp->seconds);
f78fd11b 1228 rdbSaveBackground(server.dbfilename);
ed9b544e 1229 break;
1230 }
1231 }
1232 }
94754ccc 1233
f2324293 1234 /* Try to expire a few timed out keys. The algorithm used is adaptive and
1235 * will use few CPU cycles if there are few expiring keys, otherwise
1236 * it will get more aggressive to avoid that too much memory is used by
1237 * keys that can be removed from the keyspace. */
94754ccc 1238 for (j = 0; j < server.dbnum; j++) {
f2324293 1239 int expired;
94754ccc 1240 redisDb *db = server.db+j;
94754ccc 1241
f2324293 1242 /* Continue to expire if at the end of the cycle more than 25%
1243 * of the keys were expired. */
1244 do {
4ef8de8a 1245 long num = dictSize(db->expires);
94754ccc 1246 time_t now = time(NULL);
1247
f2324293 1248 expired = 0;
94754ccc 1249 if (num > REDIS_EXPIRELOOKUPS_PER_CRON)
1250 num = REDIS_EXPIRELOOKUPS_PER_CRON;
1251 while (num--) {
1252 dictEntry *de;
1253 time_t t;
1254
1255 if ((de = dictGetRandomKey(db->expires)) == NULL) break;
1256 t = (time_t) dictGetEntryVal(de);
1257 if (now > t) {
1258 deleteKey(db,dictGetEntryKey(de));
f2324293 1259 expired++;
94754ccc 1260 }
1261 }
f2324293 1262 } while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/4);
94754ccc 1263 }
1264
4ef8de8a 1265 /* Swap a few keys on disk if we are over the memory limit and VM
f870935d 1266 * is enbled. Try to free objects from the free list first. */
7e69548d 1267 if (vmCanSwapOut()) {
1268 while (server.vm_enabled && zmalloc_used_memory() >
f870935d 1269 server.vm_max_memory)
1270 {
72e9fd40 1271 int retval;
1272
a5819310 1273 if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
72e9fd40 1274 retval = (server.vm_max_threads == 0) ?
1275 vmSwapOneObjectBlocking() :
1276 vmSwapOneObjectThreaded();
1277 if (retval == REDIS_ERR && (loops % 30) == 0 &&
1278 zmalloc_used_memory() >
1279 (server.vm_max_memory+server.vm_max_memory/10))
1280 {
1281 redisLog(REDIS_WARNING,"WARNING: vm-max-memory limit exceeded by more than 10%% but unable to swap more objects out!");
7e69548d 1282 }
72e9fd40 1283 /* Note that when using threade I/O we free just one object,
1284 * because anyway when the I/O thread in charge to swap this
1285 * object out will finish, the handler of completed jobs
1286 * will try to swap more objects if we are still out of memory. */
1287 if (retval == REDIS_ERR || server.vm_max_threads > 0) break;
4ef8de8a 1288 }
1289 }
1290
ed9b544e 1291 /* Check if we should connect to a MASTER */
1292 if (server.replstate == REDIS_REPL_CONNECT) {
1293 redisLog(REDIS_NOTICE,"Connecting to MASTER...");
1294 if (syncWithMaster() == REDIS_OK) {
1295 redisLog(REDIS_NOTICE,"MASTER <-> SLAVE sync succeeded");
1296 }
1297 }
1298 return 1000;
1299}
1300
1301static void createSharedObjects(void) {
1302 shared.crlf = createObject(REDIS_STRING,sdsnew("\r\n"));
1303 shared.ok = createObject(REDIS_STRING,sdsnew("+OK\r\n"));
1304 shared.err = createObject(REDIS_STRING,sdsnew("-ERR\r\n"));
c937aa89 1305 shared.emptybulk = createObject(REDIS_STRING,sdsnew("$0\r\n\r\n"));
1306 shared.czero = createObject(REDIS_STRING,sdsnew(":0\r\n"));
1307 shared.cone = createObject(REDIS_STRING,sdsnew(":1\r\n"));
1308 shared.nullbulk = createObject(REDIS_STRING,sdsnew("$-1\r\n"));
1309 shared.nullmultibulk = createObject(REDIS_STRING,sdsnew("*-1\r\n"));
1310 shared.emptymultibulk = createObject(REDIS_STRING,sdsnew("*0\r\n"));
ed9b544e 1311 shared.pong = createObject(REDIS_STRING,sdsnew("+PONG\r\n"));
6e469882 1312 shared.queued = createObject(REDIS_STRING,sdsnew("+QUEUED\r\n"));
ed9b544e 1313 shared.wrongtypeerr = createObject(REDIS_STRING,sdsnew(
1314 "-ERR Operation against a key holding the wrong kind of value\r\n"));
ed9b544e 1315 shared.nokeyerr = createObject(REDIS_STRING,sdsnew(
1316 "-ERR no such key\r\n"));
ed9b544e 1317 shared.syntaxerr = createObject(REDIS_STRING,sdsnew(
1318 "-ERR syntax error\r\n"));
c937aa89 1319 shared.sameobjecterr = createObject(REDIS_STRING,sdsnew(
1320 "-ERR source and destination objects are the same\r\n"));
1321 shared.outofrangeerr = createObject(REDIS_STRING,sdsnew(
1322 "-ERR index out of range\r\n"));
ed9b544e 1323 shared.space = createObject(REDIS_STRING,sdsnew(" "));
c937aa89 1324 shared.colon = createObject(REDIS_STRING,sdsnew(":"));
1325 shared.plus = createObject(REDIS_STRING,sdsnew("+"));
ed9b544e 1326 shared.select0 = createStringObject("select 0\r\n",10);
1327 shared.select1 = createStringObject("select 1\r\n",10);
1328 shared.select2 = createStringObject("select 2\r\n",10);
1329 shared.select3 = createStringObject("select 3\r\n",10);
1330 shared.select4 = createStringObject("select 4\r\n",10);
1331 shared.select5 = createStringObject("select 5\r\n",10);
1332 shared.select6 = createStringObject("select 6\r\n",10);
1333 shared.select7 = createStringObject("select 7\r\n",10);
1334 shared.select8 = createStringObject("select 8\r\n",10);
1335 shared.select9 = createStringObject("select 9\r\n",10);
1336}
1337
1338static void appendServerSaveParams(time_t seconds, int changes) {
1339 server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));
ed9b544e 1340 server.saveparams[server.saveparamslen].seconds = seconds;
1341 server.saveparams[server.saveparamslen].changes = changes;
1342 server.saveparamslen++;
1343}
1344
bcfc686d 1345static void resetServerSaveParams() {
ed9b544e 1346 zfree(server.saveparams);
1347 server.saveparams = NULL;
1348 server.saveparamslen = 0;
1349}
1350
1351static void initServerConfig() {
1352 server.dbnum = REDIS_DEFAULT_DBNUM;
1353 server.port = REDIS_SERVERPORT;
f870935d 1354 server.verbosity = REDIS_VERBOSE;
ed9b544e 1355 server.maxidletime = REDIS_MAXIDLETIME;
1356 server.saveparams = NULL;
1357 server.logfile = NULL; /* NULL = log on standard output */
1358 server.bindaddr = NULL;
1359 server.glueoutputbuf = 1;
1360 server.daemonize = 0;
44b38ef4 1361 server.appendonly = 0;
4e141d5a 1362 server.appendfsync = APPENDFSYNC_ALWAYS;
48f0308a 1363 server.lastfsync = time(NULL);
44b38ef4 1364 server.appendfd = -1;
1365 server.appendseldb = -1; /* Make sure the first time will not match */
ed329fcf 1366 server.pidfile = "/var/run/redis.pid";
ed9b544e 1367 server.dbfilename = "dump.rdb";
9d65a1bb 1368 server.appendfilename = "appendonly.aof";
abcb223e 1369 server.requirepass = NULL;
10c43610 1370 server.shareobjects = 0;
b0553789 1371 server.rdbcompression = 1;
21aecf4b 1372 server.sharingpoolsize = 1024;
285add55 1373 server.maxclients = 0;
f86a74e9 1374 server.blockedclients = 0;
3fd78bcd 1375 server.maxmemory = 0;
75680a3c 1376 server.vm_enabled = 0;
054e426d 1377 server.vm_swap_file = zstrdup("/tmp/redis-%p.vm");
75680a3c 1378 server.vm_page_size = 256; /* 256 bytes per page */
1379 server.vm_pages = 1024*1024*100; /* 104 millions of pages */
1380 server.vm_max_memory = 1024LL*1024*1024*1; /* 1 GB of RAM */
92f8e882 1381 server.vm_max_threads = 4;
75680a3c 1382
bcfc686d 1383 resetServerSaveParams();
ed9b544e 1384
1385 appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
1386 appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
1387 appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1388 /* Replication related */
1389 server.isslave = 0;
d0ccebcf 1390 server.masterauth = NULL;
ed9b544e 1391 server.masterhost = NULL;
1392 server.masterport = 6379;
1393 server.master = NULL;
1394 server.replstate = REDIS_REPL_NONE;
a7866db6 1395
1396 /* Double constants initialization */
1397 R_Zero = 0.0;
1398 R_PosInf = 1.0/R_Zero;
1399 R_NegInf = -1.0/R_Zero;
1400 R_Nan = R_Zero/R_Zero;
ed9b544e 1401}
1402
1403static void initServer() {
1404 int j;
1405
1406 signal(SIGHUP, SIG_IGN);
1407 signal(SIGPIPE, SIG_IGN);
fe3bbfbe 1408 setupSigSegvAction();
ed9b544e 1409
b9bc0eef 1410 server.devnull = fopen("/dev/null","w");
1411 if (server.devnull == NULL) {
1412 redisLog(REDIS_WARNING, "Can't open /dev/null: %s", server.neterr);
1413 exit(1);
1414 }
ed9b544e 1415 server.clients = listCreate();
1416 server.slaves = listCreate();
87eca727 1417 server.monitors = listCreate();
ed9b544e 1418 server.objfreelist = listCreate();
1419 createSharedObjects();
1420 server.el = aeCreateEventLoop();
3305306f 1421 server.db = zmalloc(sizeof(redisDb)*server.dbnum);
10c43610 1422 server.sharingpool = dictCreate(&setDictType,NULL);
ed9b544e 1423 server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr);
1424 if (server.fd == -1) {
1425 redisLog(REDIS_WARNING, "Opening TCP port: %s", server.neterr);
1426 exit(1);
1427 }
3305306f 1428 for (j = 0; j < server.dbnum; j++) {
1429 server.db[j].dict = dictCreate(&hashDictType,NULL);
f2d9f50f 1430 server.db[j].expires = dictCreate(&keyptrDictType,NULL);
4409877e 1431 server.db[j].blockingkeys = dictCreate(&keylistDictType,NULL);
3305306f 1432 server.db[j].id = j;
1433 }
ed9b544e 1434 server.cronloops = 0;
9f3c422c 1435 server.bgsavechildpid = -1;
9d65a1bb 1436 server.bgrewritechildpid = -1;
1437 server.bgrewritebuf = sdsempty();
ed9b544e 1438 server.lastsave = time(NULL);
1439 server.dirty = 0;
1440 server.usedmemory = 0;
1441 server.stat_numcommands = 0;
1442 server.stat_numconnections = 0;
1443 server.stat_starttime = time(NULL);
3a66edc7 1444 server.unixtime = time(NULL);
d8f8b666 1445 aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL);
996cb5f7 1446 if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,
1447 acceptHandler, NULL) == AE_ERR) oom("creating file event");
44b38ef4 1448
1449 if (server.appendonly) {
71eba477 1450 server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
44b38ef4 1451 if (server.appendfd == -1) {
1452 redisLog(REDIS_WARNING, "Can't open the append-only file: %s",
1453 strerror(errno));
1454 exit(1);
1455 }
1456 }
75680a3c 1457
1458 if (server.vm_enabled) vmInit();
ed9b544e 1459}
1460
1461/* Empty the whole database */
ca37e9cd 1462static long long emptyDb() {
ed9b544e 1463 int j;
ca37e9cd 1464 long long removed = 0;
ed9b544e 1465
3305306f 1466 for (j = 0; j < server.dbnum; j++) {
ca37e9cd 1467 removed += dictSize(server.db[j].dict);
3305306f 1468 dictEmpty(server.db[j].dict);
1469 dictEmpty(server.db[j].expires);
1470 }
ca37e9cd 1471 return removed;
ed9b544e 1472}
1473
85dd2f3a 1474static int yesnotoi(char *s) {
1475 if (!strcasecmp(s,"yes")) return 1;
1476 else if (!strcasecmp(s,"no")) return 0;
1477 else return -1;
1478}
1479
ed9b544e 1480/* I agree, this is a very rudimental way to load a configuration...
1481 will improve later if the config gets more complex */
1482static void loadServerConfig(char *filename) {
c9a111ac 1483 FILE *fp;
ed9b544e 1484 char buf[REDIS_CONFIGLINE_MAX+1], *err = NULL;
1485 int linenum = 0;
1486 sds line = NULL;
c9a111ac 1487
1488 if (filename[0] == '-' && filename[1] == '\0')
1489 fp = stdin;
1490 else {
1491 if ((fp = fopen(filename,"r")) == NULL) {
1492 redisLog(REDIS_WARNING,"Fatal error, can't open config file");
1493 exit(1);
1494 }
ed9b544e 1495 }
c9a111ac 1496
ed9b544e 1497 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL) {
1498 sds *argv;
1499 int argc, j;
1500
1501 linenum++;
1502 line = sdsnew(buf);
1503 line = sdstrim(line," \t\r\n");
1504
1505 /* Skip comments and blank lines*/
1506 if (line[0] == '#' || line[0] == '\0') {
1507 sdsfree(line);
1508 continue;
1509 }
1510
1511 /* Split into arguments */
1512 argv = sdssplitlen(line,sdslen(line)," ",1,&argc);
1513 sdstolower(argv[0]);
1514
1515 /* Execute config directives */
bb0b03a3 1516 if (!strcasecmp(argv[0],"timeout") && argc == 2) {
ed9b544e 1517 server.maxidletime = atoi(argv[1]);
0150db36 1518 if (server.maxidletime < 0) {
ed9b544e 1519 err = "Invalid timeout value"; goto loaderr;
1520 }
bb0b03a3 1521 } else if (!strcasecmp(argv[0],"port") && argc == 2) {
ed9b544e 1522 server.port = atoi(argv[1]);
1523 if (server.port < 1 || server.port > 65535) {
1524 err = "Invalid port"; goto loaderr;
1525 }
bb0b03a3 1526 } else if (!strcasecmp(argv[0],"bind") && argc == 2) {
ed9b544e 1527 server.bindaddr = zstrdup(argv[1]);
bb0b03a3 1528 } else if (!strcasecmp(argv[0],"save") && argc == 3) {
ed9b544e 1529 int seconds = atoi(argv[1]);
1530 int changes = atoi(argv[2]);
1531 if (seconds < 1 || changes < 0) {
1532 err = "Invalid save parameters"; goto loaderr;
1533 }
1534 appendServerSaveParams(seconds,changes);
bb0b03a3 1535 } else if (!strcasecmp(argv[0],"dir") && argc == 2) {
ed9b544e 1536 if (chdir(argv[1]) == -1) {
1537 redisLog(REDIS_WARNING,"Can't chdir to '%s': %s",
1538 argv[1], strerror(errno));
1539 exit(1);
1540 }
bb0b03a3 1541 } else if (!strcasecmp(argv[0],"loglevel") && argc == 2) {
1542 if (!strcasecmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG;
f870935d 1543 else if (!strcasecmp(argv[1],"verbose")) server.verbosity = REDIS_VERBOSE;
bb0b03a3 1544 else if (!strcasecmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE;
1545 else if (!strcasecmp(argv[1],"warning")) server.verbosity = REDIS_WARNING;
ed9b544e 1546 else {
1547 err = "Invalid log level. Must be one of debug, notice, warning";
1548 goto loaderr;
1549 }
bb0b03a3 1550 } else if (!strcasecmp(argv[0],"logfile") && argc == 2) {
c9a111ac 1551 FILE *logfp;
ed9b544e 1552
1553 server.logfile = zstrdup(argv[1]);
bb0b03a3 1554 if (!strcasecmp(server.logfile,"stdout")) {
ed9b544e 1555 zfree(server.logfile);
1556 server.logfile = NULL;
1557 }
1558 if (server.logfile) {
1559 /* Test if we are able to open the file. The server will not
1560 * be able to abort just for this problem later... */
c9a111ac 1561 logfp = fopen(server.logfile,"a");
1562 if (logfp == NULL) {
ed9b544e 1563 err = sdscatprintf(sdsempty(),
1564 "Can't open the log file: %s", strerror(errno));
1565 goto loaderr;
1566 }
c9a111ac 1567 fclose(logfp);
ed9b544e 1568 }
bb0b03a3 1569 } else if (!strcasecmp(argv[0],"databases") && argc == 2) {
ed9b544e 1570 server.dbnum = atoi(argv[1]);
1571 if (server.dbnum < 1) {
1572 err = "Invalid number of databases"; goto loaderr;
1573 }
285add55 1574 } else if (!strcasecmp(argv[0],"maxclients") && argc == 2) {
1575 server.maxclients = atoi(argv[1]);
3fd78bcd 1576 } else if (!strcasecmp(argv[0],"maxmemory") && argc == 2) {
d4465900 1577 server.maxmemory = strtoll(argv[1], NULL, 10);
bb0b03a3 1578 } else if (!strcasecmp(argv[0],"slaveof") && argc == 3) {
ed9b544e 1579 server.masterhost = sdsnew(argv[1]);
1580 server.masterport = atoi(argv[2]);
1581 server.replstate = REDIS_REPL_CONNECT;
d0ccebcf 1582 } else if (!strcasecmp(argv[0],"masterauth") && argc == 2) {
1583 server.masterauth = zstrdup(argv[1]);
bb0b03a3 1584 } else if (!strcasecmp(argv[0],"glueoutputbuf") && argc == 2) {
85dd2f3a 1585 if ((server.glueoutputbuf = yesnotoi(argv[1])) == -1) {
ed9b544e 1586 err = "argument must be 'yes' or 'no'"; goto loaderr;
1587 }
bb0b03a3 1588 } else if (!strcasecmp(argv[0],"shareobjects") && argc == 2) {
85dd2f3a 1589 if ((server.shareobjects = yesnotoi(argv[1])) == -1) {
10c43610 1590 err = "argument must be 'yes' or 'no'"; goto loaderr;
1591 }
121f70cf 1592 } else if (!strcasecmp(argv[0],"rdbcompression") && argc == 2) {
1593 if ((server.rdbcompression = yesnotoi(argv[1])) == -1) {
1594 err = "argument must be 'yes' or 'no'"; goto loaderr;
1595 }
e52c65b9 1596 } else if (!strcasecmp(argv[0],"shareobjectspoolsize") && argc == 2) {
1597 server.sharingpoolsize = atoi(argv[1]);
1598 if (server.sharingpoolsize < 1) {
1599 err = "invalid object sharing pool size"; goto loaderr;
1600 }
bb0b03a3 1601 } else if (!strcasecmp(argv[0],"daemonize") && argc == 2) {
85dd2f3a 1602 if ((server.daemonize = yesnotoi(argv[1])) == -1) {
ed9b544e 1603 err = "argument must be 'yes' or 'no'"; goto loaderr;
1604 }
44b38ef4 1605 } else if (!strcasecmp(argv[0],"appendonly") && argc == 2) {
1606 if ((server.appendonly = yesnotoi(argv[1])) == -1) {
1607 err = "argument must be 'yes' or 'no'"; goto loaderr;
1608 }
48f0308a 1609 } else if (!strcasecmp(argv[0],"appendfsync") && argc == 2) {
1766c6da 1610 if (!strcasecmp(argv[1],"no")) {
48f0308a 1611 server.appendfsync = APPENDFSYNC_NO;
1766c6da 1612 } else if (!strcasecmp(argv[1],"always")) {
48f0308a 1613 server.appendfsync = APPENDFSYNC_ALWAYS;
1766c6da 1614 } else if (!strcasecmp(argv[1],"everysec")) {
48f0308a 1615 server.appendfsync = APPENDFSYNC_EVERYSEC;
1616 } else {
1617 err = "argument must be 'no', 'always' or 'everysec'";
1618 goto loaderr;
1619 }
bb0b03a3 1620 } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
054e426d 1621 server.requirepass = zstrdup(argv[1]);
bb0b03a3 1622 } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
054e426d 1623 server.pidfile = zstrdup(argv[1]);
bb0b03a3 1624 } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) {
054e426d 1625 server.dbfilename = zstrdup(argv[1]);
75680a3c 1626 } else if (!strcasecmp(argv[0],"vm-enabled") && argc == 2) {
1627 if ((server.vm_enabled = yesnotoi(argv[1])) == -1) {
1628 err = "argument must be 'yes' or 'no'"; goto loaderr;
1629 }
054e426d 1630 } else if (!strcasecmp(argv[0],"vm-swap-file") && argc == 2) {
fefed597 1631 zfree(server.vm_swap_file);
054e426d 1632 server.vm_swap_file = zstrdup(argv[1]);
4ef8de8a 1633 } else if (!strcasecmp(argv[0],"vm-max-memory") && argc == 2) {
1634 server.vm_max_memory = strtoll(argv[1], NULL, 10);
1635 } else if (!strcasecmp(argv[0],"vm-page-size") && argc == 2) {
1636 server.vm_page_size = strtoll(argv[1], NULL, 10);
1637 } else if (!strcasecmp(argv[0],"vm-pages") && argc == 2) {
1638 server.vm_pages = strtoll(argv[1], NULL, 10);
92f8e882 1639 } else if (!strcasecmp(argv[0],"vm-max-threads") && argc == 2) {
1640 server.vm_max_threads = strtoll(argv[1], NULL, 10);
ed9b544e 1641 } else {
1642 err = "Bad directive or wrong number of arguments"; goto loaderr;
1643 }
1644 for (j = 0; j < argc; j++)
1645 sdsfree(argv[j]);
1646 zfree(argv);
1647 sdsfree(line);
1648 }
c9a111ac 1649 if (fp != stdin) fclose(fp);
ed9b544e 1650 return;
1651
1652loaderr:
1653 fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n");
1654 fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
1655 fprintf(stderr, ">>> '%s'\n", line);
1656 fprintf(stderr, "%s\n", err);
1657 exit(1);
1658}
1659
1660static void freeClientArgv(redisClient *c) {
1661 int j;
1662
1663 for (j = 0; j < c->argc; j++)
1664 decrRefCount(c->argv[j]);
e8a74421 1665 for (j = 0; j < c->mbargc; j++)
1666 decrRefCount(c->mbargv[j]);
ed9b544e 1667 c->argc = 0;
e8a74421 1668 c->mbargc = 0;
ed9b544e 1669}
1670
1671static void freeClient(redisClient *c) {
1672 listNode *ln;
1673
4409877e 1674 /* Note that if the client we are freeing is blocked into a blocking
b0d8747d 1675 * call, we have to set querybuf to NULL *before* to call
1676 * unblockClientWaitingData() to avoid processInputBuffer() will get
1677 * called. Also it is important to remove the file events after
1678 * this, because this call adds the READABLE event. */
4409877e 1679 sdsfree(c->querybuf);
1680 c->querybuf = NULL;
1681 if (c->flags & REDIS_BLOCKED)
b0d8747d 1682 unblockClientWaitingData(c);
4409877e 1683
ed9b544e 1684 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
1685 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
ed9b544e 1686 listRelease(c->reply);
1687 freeClientArgv(c);
1688 close(c->fd);
92f8e882 1689 /* Remove from the list of clients */
ed9b544e 1690 ln = listSearchKey(server.clients,c);
dfc5e96c 1691 redisAssert(ln != NULL);
ed9b544e 1692 listDelNode(server.clients,ln);
92f8e882 1693 /* Remove from the list of clients waiting for VM operations */
1694 if (server.vm_enabled && listLength(c->io_keys)) {
1695 ln = listSearchKey(server.io_clients,c);
1696 if (ln) listDelNode(server.io_clients,ln);
1697 listRelease(c->io_keys);
1698 }
b3e3d0d7 1699 listRelease(c->io_keys);
92f8e882 1700 /* Other cleanup */
ed9b544e 1701 if (c->flags & REDIS_SLAVE) {
6208b3a7 1702 if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1)
1703 close(c->repldbfd);
87eca727 1704 list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
1705 ln = listSearchKey(l,c);
dfc5e96c 1706 redisAssert(ln != NULL);
87eca727 1707 listDelNode(l,ln);
ed9b544e 1708 }
1709 if (c->flags & REDIS_MASTER) {
1710 server.master = NULL;
1711 server.replstate = REDIS_REPL_CONNECT;
1712 }
93ea3759 1713 zfree(c->argv);
e8a74421 1714 zfree(c->mbargv);
6e469882 1715 freeClientMultiState(c);
ed9b544e 1716 zfree(c);
1717}
1718
cc30e368 1719#define GLUEREPLY_UP_TO (1024)
ed9b544e 1720static void glueReplyBuffersIfNeeded(redisClient *c) {
c28b42ac 1721 int copylen = 0;
1722 char buf[GLUEREPLY_UP_TO];
6208b3a7 1723 listNode *ln;
c7df85a4 1724 listIter li;
ed9b544e 1725 robj *o;
1726
c7df85a4 1727 listRewind(c->reply,&li);
1728 while((ln = listNext(&li))) {
c28b42ac 1729 int objlen;
1730
ed9b544e 1731 o = ln->value;
c28b42ac 1732 objlen = sdslen(o->ptr);
1733 if (copylen + objlen <= GLUEREPLY_UP_TO) {
1734 memcpy(buf+copylen,o->ptr,objlen);
1735 copylen += objlen;
ed9b544e 1736 listDelNode(c->reply,ln);
c28b42ac 1737 } else {
1738 if (copylen == 0) return;
1739 break;
ed9b544e 1740 }
ed9b544e 1741 }
c28b42ac 1742 /* Now the output buffer is empty, add the new single element */
1743 o = createObject(REDIS_STRING,sdsnewlen(buf,copylen));
1744 listAddNodeHead(c->reply,o);
ed9b544e 1745}
1746
1747static void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
1748 redisClient *c = privdata;
1749 int nwritten = 0, totwritten = 0, objlen;
1750 robj *o;
1751 REDIS_NOTUSED(el);
1752 REDIS_NOTUSED(mask);
1753
2895e862 1754 /* Use writev() if we have enough buffers to send */
7ea870c0 1755 if (!server.glueoutputbuf &&
1756 listLength(c->reply) > REDIS_WRITEV_THRESHOLD &&
1757 !(c->flags & REDIS_MASTER))
2895e862 1758 {
1759 sendReplyToClientWritev(el, fd, privdata, mask);
1760 return;
1761 }
2895e862 1762
ed9b544e 1763 while(listLength(c->reply)) {
c28b42ac 1764 if (server.glueoutputbuf && listLength(c->reply) > 1)
1765 glueReplyBuffersIfNeeded(c);
1766
ed9b544e 1767 o = listNodeValue(listFirst(c->reply));
1768 objlen = sdslen(o->ptr);
1769
1770 if (objlen == 0) {
1771 listDelNode(c->reply,listFirst(c->reply));
1772 continue;
1773 }
1774
1775 if (c->flags & REDIS_MASTER) {
6f376729 1776 /* Don't reply to a master */
ed9b544e 1777 nwritten = objlen - c->sentlen;
1778 } else {
a4d1ba9a 1779 nwritten = write(fd, ((char*)o->ptr)+c->sentlen, objlen - c->sentlen);
ed9b544e 1780 if (nwritten <= 0) break;
1781 }
1782 c->sentlen += nwritten;
1783 totwritten += nwritten;
1784 /* If we fully sent the object on head go to the next one */
1785 if (c->sentlen == objlen) {
1786 listDelNode(c->reply,listFirst(c->reply));
1787 c->sentlen = 0;
1788 }
6f376729 1789 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
12f9d551 1790 * bytes, in a single threaded server it's a good idea to serve
6f376729 1791 * other clients as well, even if a very large request comes from
1792 * super fast link that is always able to accept data (in real world
12f9d551 1793 * scenario think about 'KEYS *' against the loopback interfae) */
6f376729 1794 if (totwritten > REDIS_MAX_WRITE_PER_EVENT) break;
ed9b544e 1795 }
1796 if (nwritten == -1) {
1797 if (errno == EAGAIN) {
1798 nwritten = 0;
1799 } else {
f870935d 1800 redisLog(REDIS_VERBOSE,
ed9b544e 1801 "Error writing to client: %s", strerror(errno));
1802 freeClient(c);
1803 return;
1804 }
1805 }
1806 if (totwritten > 0) c->lastinteraction = time(NULL);
1807 if (listLength(c->reply) == 0) {
1808 c->sentlen = 0;
1809 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
1810 }
1811}
1812
2895e862 1813static void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask)
1814{
1815 redisClient *c = privdata;
1816 int nwritten = 0, totwritten = 0, objlen, willwrite;
1817 robj *o;
1818 struct iovec iov[REDIS_WRITEV_IOVEC_COUNT];
1819 int offset, ion = 0;
1820 REDIS_NOTUSED(el);
1821 REDIS_NOTUSED(mask);
1822
1823 listNode *node;
1824 while (listLength(c->reply)) {
1825 offset = c->sentlen;
1826 ion = 0;
1827 willwrite = 0;
1828
1829 /* fill-in the iov[] array */
1830 for(node = listFirst(c->reply); node; node = listNextNode(node)) {
1831 o = listNodeValue(node);
1832 objlen = sdslen(o->ptr);
1833
1834 if (totwritten + objlen - offset > REDIS_MAX_WRITE_PER_EVENT)
1835 break;
1836
1837 if(ion == REDIS_WRITEV_IOVEC_COUNT)
1838 break; /* no more iovecs */
1839
1840 iov[ion].iov_base = ((char*)o->ptr) + offset;
1841 iov[ion].iov_len = objlen - offset;
1842 willwrite += objlen - offset;
1843 offset = 0; /* just for the first item */
1844 ion++;
1845 }
1846
1847 if(willwrite == 0)
1848 break;
1849
1850 /* write all collected blocks at once */
1851 if((nwritten = writev(fd, iov, ion)) < 0) {
1852 if (errno != EAGAIN) {
f870935d 1853 redisLog(REDIS_VERBOSE,
2895e862 1854 "Error writing to client: %s", strerror(errno));
1855 freeClient(c);
1856 return;
1857 }
1858 break;
1859 }
1860
1861 totwritten += nwritten;
1862 offset = c->sentlen;
1863
1864 /* remove written robjs from c->reply */
1865 while (nwritten && listLength(c->reply)) {
1866 o = listNodeValue(listFirst(c->reply));
1867 objlen = sdslen(o->ptr);
1868
1869 if(nwritten >= objlen - offset) {
1870 listDelNode(c->reply, listFirst(c->reply));
1871 nwritten -= objlen - offset;
1872 c->sentlen = 0;
1873 } else {
1874 /* partial write */
1875 c->sentlen += nwritten;
1876 break;
1877 }
1878 offset = 0;
1879 }
1880 }
1881
1882 if (totwritten > 0)
1883 c->lastinteraction = time(NULL);
1884
1885 if (listLength(c->reply) == 0) {
1886 c->sentlen = 0;
1887 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
1888 }
1889}
1890
ed9b544e 1891static struct redisCommand *lookupCommand(char *name) {
1892 int j = 0;
1893 while(cmdTable[j].name != NULL) {
bb0b03a3 1894 if (!strcasecmp(name,cmdTable[j].name)) return &cmdTable[j];
ed9b544e 1895 j++;
1896 }
1897 return NULL;
1898}
1899
1900/* resetClient prepare the client to process the next command */
1901static void resetClient(redisClient *c) {
1902 freeClientArgv(c);
1903 c->bulklen = -1;
e8a74421 1904 c->multibulk = 0;
ed9b544e 1905}
1906
6e469882 1907/* Call() is the core of Redis execution of a command */
1908static void call(redisClient *c, struct redisCommand *cmd) {
1909 long long dirty;
1910
1911 dirty = server.dirty;
1912 cmd->proc(c);
1913 if (server.appendonly && server.dirty-dirty)
1914 feedAppendOnlyFile(cmd,c->db->id,c->argv,c->argc);
1915 if (server.dirty-dirty && listLength(server.slaves))
1916 replicationFeedSlaves(server.slaves,cmd,c->db->id,c->argv,c->argc);
1917 if (listLength(server.monitors))
1918 replicationFeedSlaves(server.monitors,cmd,c->db->id,c->argv,c->argc);
1919 server.stat_numcommands++;
1920}
1921
ed9b544e 1922/* If this function gets called we already read a whole
1923 * command, argments are in the client argv/argc fields.
1924 * processCommand() execute the command or prepare the
1925 * server for a bulk read from the client.
1926 *
1927 * If 1 is returned the client is still alive and valid and
1928 * and other operations can be performed by the caller. Otherwise
1929 * if 0 is returned the client was destroied (i.e. after QUIT). */
1930static int processCommand(redisClient *c) {
1931 struct redisCommand *cmd;
ed9b544e 1932
3fd78bcd 1933 /* Free some memory if needed (maxmemory setting) */
1934 if (server.maxmemory) freeMemoryIfNeeded();
1935
e8a74421 1936 /* Handle the multi bulk command type. This is an alternative protocol
1937 * supported by Redis in order to receive commands that are composed of
1938 * multiple binary-safe "bulk" arguments. The latency of processing is
1939 * a bit higher but this allows things like multi-sets, so if this
1940 * protocol is used only for MSET and similar commands this is a big win. */
1941 if (c->multibulk == 0 && c->argc == 1 && ((char*)(c->argv[0]->ptr))[0] == '*') {
1942 c->multibulk = atoi(((char*)c->argv[0]->ptr)+1);
1943 if (c->multibulk <= 0) {
1944 resetClient(c);
1945 return 1;
1946 } else {
1947 decrRefCount(c->argv[c->argc-1]);
1948 c->argc--;
1949 return 1;
1950 }
1951 } else if (c->multibulk) {
1952 if (c->bulklen == -1) {
1953 if (((char*)c->argv[0]->ptr)[0] != '$') {
1954 addReplySds(c,sdsnew("-ERR multi bulk protocol error\r\n"));
1955 resetClient(c);
1956 return 1;
1957 } else {
1958 int bulklen = atoi(((char*)c->argv[0]->ptr)+1);
1959 decrRefCount(c->argv[0]);
1960 if (bulklen < 0 || bulklen > 1024*1024*1024) {
1961 c->argc--;
1962 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
1963 resetClient(c);
1964 return 1;
1965 }
1966 c->argc--;
1967 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
1968 return 1;
1969 }
1970 } else {
1971 c->mbargv = zrealloc(c->mbargv,(sizeof(robj*))*(c->mbargc+1));
1972 c->mbargv[c->mbargc] = c->argv[0];
1973 c->mbargc++;
1974 c->argc--;
1975 c->multibulk--;
1976 if (c->multibulk == 0) {
1977 robj **auxargv;
1978 int auxargc;
1979
1980 /* Here we need to swap the multi-bulk argc/argv with the
1981 * normal argc/argv of the client structure. */
1982 auxargv = c->argv;
1983 c->argv = c->mbargv;
1984 c->mbargv = auxargv;
1985
1986 auxargc = c->argc;
1987 c->argc = c->mbargc;
1988 c->mbargc = auxargc;
1989
1990 /* We need to set bulklen to something different than -1
1991 * in order for the code below to process the command without
1992 * to try to read the last argument of a bulk command as
1993 * a special argument. */
1994 c->bulklen = 0;
1995 /* continue below and process the command */
1996 } else {
1997 c->bulklen = -1;
1998 return 1;
1999 }
2000 }
2001 }
2002 /* -- end of multi bulk commands processing -- */
2003
ed9b544e 2004 /* The QUIT command is handled as a special case. Normal command
2005 * procs are unable to close the client connection safely */
bb0b03a3 2006 if (!strcasecmp(c->argv[0]->ptr,"quit")) {
ed9b544e 2007 freeClient(c);
2008 return 0;
2009 }
2010 cmd = lookupCommand(c->argv[0]->ptr);
2011 if (!cmd) {
2c14807b 2012 addReplySds(c,
2013 sdscatprintf(sdsempty(), "-ERR unknown command '%s'\r\n",
2014 (char*)c->argv[0]->ptr));
ed9b544e 2015 resetClient(c);
2016 return 1;
2017 } else if ((cmd->arity > 0 && cmd->arity != c->argc) ||
2018 (c->argc < -cmd->arity)) {
454d4e43 2019 addReplySds(c,
2020 sdscatprintf(sdsempty(),
2021 "-ERR wrong number of arguments for '%s' command\r\n",
2022 cmd->name));
ed9b544e 2023 resetClient(c);
2024 return 1;
3fd78bcd 2025 } else if (server.maxmemory && cmd->flags & REDIS_CMD_DENYOOM && zmalloc_used_memory() > server.maxmemory) {
2026 addReplySds(c,sdsnew("-ERR command not allowed when used memory > 'maxmemory'\r\n"));
2027 resetClient(c);
2028 return 1;
ed9b544e 2029 } else if (cmd->flags & REDIS_CMD_BULK && c->bulklen == -1) {
2030 int bulklen = atoi(c->argv[c->argc-1]->ptr);
2031
2032 decrRefCount(c->argv[c->argc-1]);
2033 if (bulklen < 0 || bulklen > 1024*1024*1024) {
2034 c->argc--;
2035 addReplySds(c,sdsnew("-ERR invalid bulk write count\r\n"));
2036 resetClient(c);
2037 return 1;
2038 }
2039 c->argc--;
2040 c->bulklen = bulklen+2; /* add two bytes for CR+LF */
2041 /* It is possible that the bulk read is already in the
8d0490e7 2042 * buffer. Check this condition and handle it accordingly.
2043 * This is just a fast path, alternative to call processInputBuffer().
2044 * It's a good idea since the code is small and this condition
2045 * happens most of the times. */
ed9b544e 2046 if ((signed)sdslen(c->querybuf) >= c->bulklen) {
2047 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
2048 c->argc++;
2049 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
2050 } else {
2051 return 1;
2052 }
2053 }
10c43610 2054 /* Let's try to share objects on the command arguments vector */
2055 if (server.shareobjects) {
2056 int j;
2057 for(j = 1; j < c->argc; j++)
2058 c->argv[j] = tryObjectSharing(c->argv[j]);
2059 }
942a3961 2060 /* Let's try to encode the bulk object to save space. */
2061 if (cmd->flags & REDIS_CMD_BULK)
2062 tryObjectEncoding(c->argv[c->argc-1]);
2063
e63943a4 2064 /* Check if the user is authenticated */
2065 if (server.requirepass && !c->authenticated && cmd->proc != authCommand) {
2066 addReplySds(c,sdsnew("-ERR operation not permitted\r\n"));
2067 resetClient(c);
2068 return 1;
2069 }
2070
ed9b544e 2071 /* Exec the command */
6e469882 2072 if (c->flags & REDIS_MULTI && cmd->proc != execCommand) {
2073 queueMultiCommand(c,cmd);
2074 addReply(c,shared.queued);
2075 } else {
2076 call(c,cmd);
2077 }
ed9b544e 2078
2079 /* Prepare the client for the next command */
2080 if (c->flags & REDIS_CLOSE) {
2081 freeClient(c);
2082 return 0;
2083 }
2084 resetClient(c);
2085 return 1;
2086}
2087
87eca727 2088static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc) {
6208b3a7 2089 listNode *ln;
c7df85a4 2090 listIter li;
ed9b544e 2091 int outc = 0, j;
93ea3759 2092 robj **outv;
2093 /* (args*2)+1 is enough room for args, spaces, newlines */
2094 robj *static_outv[REDIS_STATIC_ARGS*2+1];
2095
2096 if (argc <= REDIS_STATIC_ARGS) {
2097 outv = static_outv;
2098 } else {
2099 outv = zmalloc(sizeof(robj*)*(argc*2+1));
93ea3759 2100 }
ed9b544e 2101
2102 for (j = 0; j < argc; j++) {
2103 if (j != 0) outv[outc++] = shared.space;
2104 if ((cmd->flags & REDIS_CMD_BULK) && j == argc-1) {
2105 robj *lenobj;
2106
2107 lenobj = createObject(REDIS_STRING,
682ac724 2108 sdscatprintf(sdsempty(),"%lu\r\n",
83c6a618 2109 (unsigned long) stringObjectLen(argv[j])));
ed9b544e 2110 lenobj->refcount = 0;
2111 outv[outc++] = lenobj;
2112 }
2113 outv[outc++] = argv[j];
2114 }
2115 outv[outc++] = shared.crlf;
2116
40d224a9 2117 /* Increment all the refcounts at start and decrement at end in order to
2118 * be sure to free objects if there is no slave in a replication state
2119 * able to be feed with commands */
2120 for (j = 0; j < outc; j++) incrRefCount(outv[j]);
c7df85a4 2121 listRewind(slaves,&li);
2122 while((ln = listNext(&li))) {
ed9b544e 2123 redisClient *slave = ln->value;
40d224a9 2124
2125 /* Don't feed slaves that are still waiting for BGSAVE to start */
6208b3a7 2126 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) continue;
40d224a9 2127
2128 /* Feed all the other slaves, MONITORs and so on */
ed9b544e 2129 if (slave->slaveseldb != dictid) {
2130 robj *selectcmd;
2131
2132 switch(dictid) {
2133 case 0: selectcmd = shared.select0; break;
2134 case 1: selectcmd = shared.select1; break;
2135 case 2: selectcmd = shared.select2; break;
2136 case 3: selectcmd = shared.select3; break;
2137 case 4: selectcmd = shared.select4; break;
2138 case 5: selectcmd = shared.select5; break;
2139 case 6: selectcmd = shared.select6; break;
2140 case 7: selectcmd = shared.select7; break;
2141 case 8: selectcmd = shared.select8; break;
2142 case 9: selectcmd = shared.select9; break;
2143 default:
2144 selectcmd = createObject(REDIS_STRING,
2145 sdscatprintf(sdsempty(),"select %d\r\n",dictid));
2146 selectcmd->refcount = 0;
2147 break;
2148 }
2149 addReply(slave,selectcmd);
2150 slave->slaveseldb = dictid;
2151 }
2152 for (j = 0; j < outc; j++) addReply(slave,outv[j]);
ed9b544e 2153 }
40d224a9 2154 for (j = 0; j < outc; j++) decrRefCount(outv[j]);
93ea3759 2155 if (outv != static_outv) zfree(outv);
ed9b544e 2156}
2157
638e42ac 2158static void processInputBuffer(redisClient *c) {
ed9b544e 2159again:
4409877e 2160 /* Before to process the input buffer, make sure the client is not
2161 * waitig for a blocking operation such as BLPOP. Note that the first
2162 * iteration the client is never blocked, otherwise the processInputBuffer
2163 * would not be called at all, but after the execution of the first commands
2164 * in the input buffer the client may be blocked, and the "goto again"
2165 * will try to reiterate. The following line will make it return asap. */
92f8e882 2166 if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return;
ed9b544e 2167 if (c->bulklen == -1) {
2168 /* Read the first line of the query */
2169 char *p = strchr(c->querybuf,'\n');
2170 size_t querylen;
644fafa3 2171
ed9b544e 2172 if (p) {
2173 sds query, *argv;
2174 int argc, j;
2175
2176 query = c->querybuf;
2177 c->querybuf = sdsempty();
2178 querylen = 1+(p-(query));
2179 if (sdslen(query) > querylen) {
2180 /* leave data after the first line of the query in the buffer */
2181 c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
2182 }
2183 *p = '\0'; /* remove "\n" */
2184 if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
2185 sdsupdatelen(query);
2186
2187 /* Now we can split the query in arguments */
ed9b544e 2188 argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
93ea3759 2189 sdsfree(query);
2190
2191 if (c->argv) zfree(c->argv);
2192 c->argv = zmalloc(sizeof(robj*)*argc);
93ea3759 2193
2194 for (j = 0; j < argc; j++) {
ed9b544e 2195 if (sdslen(argv[j])) {
2196 c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
2197 c->argc++;
2198 } else {
2199 sdsfree(argv[j]);
2200 }
2201 }
2202 zfree(argv);
7c49733c 2203 if (c->argc) {
2204 /* Execute the command. If the client is still valid
2205 * after processCommand() return and there is something
2206 * on the query buffer try to process the next command. */
2207 if (processCommand(c) && sdslen(c->querybuf)) goto again;
2208 } else {
2209 /* Nothing to process, argc == 0. Just process the query
2210 * buffer if it's not empty or return to the caller */
2211 if (sdslen(c->querybuf)) goto again;
2212 }
ed9b544e 2213 return;
644fafa3 2214 } else if (sdslen(c->querybuf) >= REDIS_REQUEST_MAX_SIZE) {
f870935d 2215 redisLog(REDIS_VERBOSE, "Client protocol error");
ed9b544e 2216 freeClient(c);
2217 return;
2218 }
2219 } else {
2220 /* Bulk read handling. Note that if we are at this point
2221 the client already sent a command terminated with a newline,
2222 we are reading the bulk data that is actually the last
2223 argument of the command. */
2224 int qbl = sdslen(c->querybuf);
2225
2226 if (c->bulklen <= qbl) {
2227 /* Copy everything but the final CRLF as final argument */
2228 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
2229 c->argc++;
2230 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
638e42ac 2231 /* Process the command. If the client is still valid after
2232 * the processing and there is more data in the buffer
2233 * try to parse it. */
2234 if (processCommand(c) && sdslen(c->querybuf)) goto again;
ed9b544e 2235 return;
2236 }
2237 }
2238}
2239
638e42ac 2240static void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
2241 redisClient *c = (redisClient*) privdata;
2242 char buf[REDIS_IOBUF_LEN];
2243 int nread;
2244 REDIS_NOTUSED(el);
2245 REDIS_NOTUSED(mask);
2246
2247 nread = read(fd, buf, REDIS_IOBUF_LEN);
2248 if (nread == -1) {
2249 if (errno == EAGAIN) {
2250 nread = 0;
2251 } else {
f870935d 2252 redisLog(REDIS_VERBOSE, "Reading from client: %s",strerror(errno));
638e42ac 2253 freeClient(c);
2254 return;
2255 }
2256 } else if (nread == 0) {
f870935d 2257 redisLog(REDIS_VERBOSE, "Client closed connection");
638e42ac 2258 freeClient(c);
2259 return;
2260 }
2261 if (nread) {
2262 c->querybuf = sdscatlen(c->querybuf, buf, nread);
2263 c->lastinteraction = time(NULL);
2264 } else {
2265 return;
2266 }
2267 processInputBuffer(c);
2268}
2269
ed9b544e 2270static int selectDb(redisClient *c, int id) {
2271 if (id < 0 || id >= server.dbnum)
2272 return REDIS_ERR;
3305306f 2273 c->db = &server.db[id];
ed9b544e 2274 return REDIS_OK;
2275}
2276
40d224a9 2277static void *dupClientReplyValue(void *o) {
2278 incrRefCount((robj*)o);
2279 return 0;
2280}
2281
ed9b544e 2282static redisClient *createClient(int fd) {
2283 redisClient *c = zmalloc(sizeof(*c));
2284
2285 anetNonBlock(NULL,fd);
2286 anetTcpNoDelay(NULL,fd);
2287 if (!c) return NULL;
2288 selectDb(c,0);
2289 c->fd = fd;
2290 c->querybuf = sdsempty();
2291 c->argc = 0;
93ea3759 2292 c->argv = NULL;
ed9b544e 2293 c->bulklen = -1;
e8a74421 2294 c->multibulk = 0;
2295 c->mbargc = 0;
2296 c->mbargv = NULL;
ed9b544e 2297 c->sentlen = 0;
2298 c->flags = 0;
2299 c->lastinteraction = time(NULL);
abcb223e 2300 c->authenticated = 0;
40d224a9 2301 c->replstate = REDIS_REPL_NONE;
6b47e12e 2302 c->reply = listCreate();
ed9b544e 2303 listSetFreeMethod(c->reply,decrRefCount);
40d224a9 2304 listSetDupMethod(c->reply,dupClientReplyValue);
92f8e882 2305 c->blockingkeys = NULL;
2306 c->blockingkeysnum = 0;
2307 c->io_keys = listCreate();
2308 listSetFreeMethod(c->io_keys,decrRefCount);
ed9b544e 2309 if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
266373b2 2310 readQueryFromClient, c) == AE_ERR) {
ed9b544e 2311 freeClient(c);
2312 return NULL;
2313 }
6b47e12e 2314 listAddNodeTail(server.clients,c);
6e469882 2315 initClientMultiState(c);
ed9b544e 2316 return c;
2317}
2318
2319static void addReply(redisClient *c, robj *obj) {
2320 if (listLength(c->reply) == 0 &&
6208b3a7 2321 (c->replstate == REDIS_REPL_NONE ||
2322 c->replstate == REDIS_REPL_ONLINE) &&
ed9b544e 2323 aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
266373b2 2324 sendReplyToClient, c) == AE_ERR) return;
e3cadb8a 2325
2326 if (server.vm_enabled && obj->storage != REDIS_VM_MEMORY) {
2327 obj = dupStringObject(obj);
2328 obj->refcount = 0; /* getDecodedObject() will increment the refcount */
2329 }
9d65a1bb 2330 listAddNodeTail(c->reply,getDecodedObject(obj));
ed9b544e 2331}
2332
2333static void addReplySds(redisClient *c, sds s) {
2334 robj *o = createObject(REDIS_STRING,s);
2335 addReply(c,o);
2336 decrRefCount(o);
2337}
2338
e2665397 2339static void addReplyDouble(redisClient *c, double d) {
2340 char buf[128];
2341
2342 snprintf(buf,sizeof(buf),"%.17g",d);
682ac724 2343 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n%s\r\n",
83c6a618 2344 (unsigned long) strlen(buf),buf));
e2665397 2345}
2346
942a3961 2347static void addReplyBulkLen(redisClient *c, robj *obj) {
2348 size_t len;
2349
2350 if (obj->encoding == REDIS_ENCODING_RAW) {
2351 len = sdslen(obj->ptr);
2352 } else {
2353 long n = (long)obj->ptr;
2354
e054afda 2355 /* Compute how many bytes will take this integer as a radix 10 string */
942a3961 2356 len = 1;
2357 if (n < 0) {
2358 len++;
2359 n = -n;
2360 }
2361 while((n = n/10) != 0) {
2362 len++;
2363 }
2364 }
83c6a618 2365 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n",(unsigned long)len));
942a3961 2366}
2367
ed9b544e 2368static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
2369 int cport, cfd;
2370 char cip[128];
285add55 2371 redisClient *c;
ed9b544e 2372 REDIS_NOTUSED(el);
2373 REDIS_NOTUSED(mask);
2374 REDIS_NOTUSED(privdata);
2375
2376 cfd = anetAccept(server.neterr, fd, cip, &cport);
2377 if (cfd == AE_ERR) {
f870935d 2378 redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr);
ed9b544e 2379 return;
2380 }
f870935d 2381 redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport);
285add55 2382 if ((c = createClient(cfd)) == NULL) {
ed9b544e 2383 redisLog(REDIS_WARNING,"Error allocating resoures for the client");
2384 close(cfd); /* May be already closed, just ingore errors */
2385 return;
2386 }
285add55 2387 /* If maxclient directive is set and this is one client more... close the
2388 * connection. Note that we create the client instead to check before
2389 * for this condition, since now the socket is already set in nonblocking
2390 * mode and we can send an error for free using the Kernel I/O */
2391 if (server.maxclients && listLength(server.clients) > server.maxclients) {
2392 char *err = "-ERR max number of clients reached\r\n";
2393
2394 /* That's a best effort error message, don't check write errors */
fee803ba 2395 if (write(c->fd,err,strlen(err)) == -1) {
2396 /* Nothing to do, Just to avoid the warning... */
2397 }
285add55 2398 freeClient(c);
2399 return;
2400 }
ed9b544e 2401 server.stat_numconnections++;
2402}
2403
2404/* ======================= Redis objects implementation ===================== */
2405
2406static robj *createObject(int type, void *ptr) {
2407 robj *o;
2408
a5819310 2409 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
ed9b544e 2410 if (listLength(server.objfreelist)) {
2411 listNode *head = listFirst(server.objfreelist);
2412 o = listNodeValue(head);
2413 listDelNode(server.objfreelist,head);
a5819310 2414 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
ed9b544e 2415 } else {
75680a3c 2416 if (server.vm_enabled) {
a5819310 2417 pthread_mutex_unlock(&server.obj_freelist_mutex);
75680a3c 2418 o = zmalloc(sizeof(*o));
2419 } else {
2420 o = zmalloc(sizeof(*o)-sizeof(struct redisObjectVM));
2421 }
ed9b544e 2422 }
ed9b544e 2423 o->type = type;
942a3961 2424 o->encoding = REDIS_ENCODING_RAW;
ed9b544e 2425 o->ptr = ptr;
2426 o->refcount = 1;
3a66edc7 2427 if (server.vm_enabled) {
1064ef87 2428 /* Note that this code may run in the context of an I/O thread
2429 * and accessing to server.unixtime in theory is an error
2430 * (no locks). But in practice this is safe, and even if we read
2431 * garbage Redis will not fail, as it's just a statistical info */
3a66edc7 2432 o->vm.atime = server.unixtime;
2433 o->storage = REDIS_VM_MEMORY;
2434 }
ed9b544e 2435 return o;
2436}
2437
2438static robj *createStringObject(char *ptr, size_t len) {
2439 return createObject(REDIS_STRING,sdsnewlen(ptr,len));
2440}
2441
4ef8de8a 2442static robj *dupStringObject(robj *o) {
b9bc0eef 2443 assert(o->encoding == REDIS_ENCODING_RAW);
4ef8de8a 2444 return createStringObject(o->ptr,sdslen(o->ptr));
2445}
2446
ed9b544e 2447static robj *createListObject(void) {
2448 list *l = listCreate();
2449
ed9b544e 2450 listSetFreeMethod(l,decrRefCount);
2451 return createObject(REDIS_LIST,l);
2452}
2453
2454static robj *createSetObject(void) {
2455 dict *d = dictCreate(&setDictType,NULL);
ed9b544e 2456 return createObject(REDIS_SET,d);
2457}
2458
1812e024 2459static robj *createZsetObject(void) {
6b47e12e 2460 zset *zs = zmalloc(sizeof(*zs));
2461
2462 zs->dict = dictCreate(&zsetDictType,NULL);
2463 zs->zsl = zslCreate();
2464 return createObject(REDIS_ZSET,zs);
1812e024 2465}
2466
ed9b544e 2467static void freeStringObject(robj *o) {
942a3961 2468 if (o->encoding == REDIS_ENCODING_RAW) {
2469 sdsfree(o->ptr);
2470 }
ed9b544e 2471}
2472
2473static void freeListObject(robj *o) {
2474 listRelease((list*) o->ptr);
2475}
2476
2477static void freeSetObject(robj *o) {
2478 dictRelease((dict*) o->ptr);
2479}
2480
fd8ccf44 2481static void freeZsetObject(robj *o) {
2482 zset *zs = o->ptr;
2483
2484 dictRelease(zs->dict);
2485 zslFree(zs->zsl);
2486 zfree(zs);
2487}
2488
ed9b544e 2489static void freeHashObject(robj *o) {
2490 dictRelease((dict*) o->ptr);
2491}
2492
2493static void incrRefCount(robj *o) {
f2b8ab34 2494 redisAssert(!server.vm_enabled || o->storage == REDIS_VM_MEMORY);
ed9b544e 2495 o->refcount++;
2496}
2497
2498static void decrRefCount(void *obj) {
2499 robj *o = obj;
94754ccc 2500
970e10bb 2501 /* Object is a key of a swapped out value, or in the process of being
2502 * loaded. */
996cb5f7 2503 if (server.vm_enabled &&
2504 (o->storage == REDIS_VM_SWAPPED || o->storage == REDIS_VM_LOADING))
2505 {
2506 if (o->storage == REDIS_VM_SWAPPED || o->storage == REDIS_VM_LOADING) {
2507 redisAssert(o->refcount == 1);
2508 }
2509 if (o->storage == REDIS_VM_LOADING) vmCancelThreadedIOJob(obj);
f2b8ab34 2510 redisAssert(o->type == REDIS_STRING);
a35ddf12 2511 freeStringObject(o);
2512 vmMarkPagesFree(o->vm.page,o->vm.usedpages);
a5819310 2513 pthread_mutex_lock(&server.obj_freelist_mutex);
a35ddf12 2514 if (listLength(server.objfreelist) > REDIS_OBJFREELIST_MAX ||
2515 !listAddNodeHead(server.objfreelist,o))
2516 zfree(o);
a5819310 2517 pthread_mutex_unlock(&server.obj_freelist_mutex);
7d98e08c 2518 server.vm_stats_swapped_objects--;
a35ddf12 2519 return;
2520 }
996cb5f7 2521 /* Object is in memory, or in the process of being swapped out. */
ed9b544e 2522 if (--(o->refcount) == 0) {
996cb5f7 2523 if (server.vm_enabled && o->storage == REDIS_VM_SWAPPING)
2524 vmCancelThreadedIOJob(obj);
ed9b544e 2525 switch(o->type) {
2526 case REDIS_STRING: freeStringObject(o); break;
2527 case REDIS_LIST: freeListObject(o); break;
2528 case REDIS_SET: freeSetObject(o); break;
fd8ccf44 2529 case REDIS_ZSET: freeZsetObject(o); break;
ed9b544e 2530 case REDIS_HASH: freeHashObject(o); break;
dfc5e96c 2531 default: redisAssert(0 != 0); break;
ed9b544e 2532 }
a5819310 2533 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
ed9b544e 2534 if (listLength(server.objfreelist) > REDIS_OBJFREELIST_MAX ||
2535 !listAddNodeHead(server.objfreelist,o))
2536 zfree(o);
a5819310 2537 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
ed9b544e 2538 }
2539}
2540
942a3961 2541static robj *lookupKey(redisDb *db, robj *key) {
2542 dictEntry *de = dictFind(db->dict,key);
3a66edc7 2543 if (de) {
55cf8433 2544 robj *key = dictGetEntryKey(de);
2545 robj *val = dictGetEntryVal(de);
3a66edc7 2546
55cf8433 2547 if (server.vm_enabled) {
996cb5f7 2548 if (key->storage == REDIS_VM_MEMORY ||
2549 key->storage == REDIS_VM_SWAPPING)
2550 {
2551 /* If we were swapping the object out, stop it, this key
2552 * was requested. */
2553 if (key->storage == REDIS_VM_SWAPPING)
2554 vmCancelThreadedIOJob(key);
55cf8433 2555 /* Update the access time of the key for the aging algorithm. */
2556 key->vm.atime = server.unixtime;
2557 } else {
2558 /* Our value was swapped on disk. Bring it at home. */
f2b8ab34 2559 redisAssert(val == NULL);
55cf8433 2560 val = vmLoadObject(key);
2561 dictGetEntryVal(de) = val;
2562 }
2563 }
2564 return val;
3a66edc7 2565 } else {
2566 return NULL;
2567 }
942a3961 2568}
2569
2570static robj *lookupKeyRead(redisDb *db, robj *key) {
2571 expireIfNeeded(db,key);
2572 return lookupKey(db,key);
2573}
2574
2575static robj *lookupKeyWrite(redisDb *db, robj *key) {
2576 deleteIfVolatile(db,key);
2577 return lookupKey(db,key);
2578}
2579
2580static int deleteKey(redisDb *db, robj *key) {
2581 int retval;
2582
2583 /* We need to protect key from destruction: after the first dictDelete()
2584 * it may happen that 'key' is no longer valid if we don't increment
2585 * it's count. This may happen when we get the object reference directly
2586 * from the hash table with dictRandomKey() or dict iterators */
2587 incrRefCount(key);
2588 if (dictSize(db->expires)) dictDelete(db->expires,key);
2589 retval = dictDelete(db->dict,key);
2590 decrRefCount(key);
2591
2592 return retval == DICT_OK;
2593}
2594
10c43610 2595/* Try to share an object against the shared objects pool */
2596static robj *tryObjectSharing(robj *o) {
2597 struct dictEntry *de;
2598 unsigned long c;
2599
3305306f 2600 if (o == NULL || server.shareobjects == 0) return o;
10c43610 2601
dfc5e96c 2602 redisAssert(o->type == REDIS_STRING);
10c43610 2603 de = dictFind(server.sharingpool,o);
2604 if (de) {
2605 robj *shared = dictGetEntryKey(de);
2606
2607 c = ((unsigned long) dictGetEntryVal(de))+1;
2608 dictGetEntryVal(de) = (void*) c;
2609 incrRefCount(shared);
2610 decrRefCount(o);
2611 return shared;
2612 } else {
2613 /* Here we are using a stream algorihtm: Every time an object is
2614 * shared we increment its count, everytime there is a miss we
2615 * recrement the counter of a random object. If this object reaches
2616 * zero we remove the object and put the current object instead. */
3305306f 2617 if (dictSize(server.sharingpool) >=
10c43610 2618 server.sharingpoolsize) {
2619 de = dictGetRandomKey(server.sharingpool);
dfc5e96c 2620 redisAssert(de != NULL);
10c43610 2621 c = ((unsigned long) dictGetEntryVal(de))-1;
2622 dictGetEntryVal(de) = (void*) c;
2623 if (c == 0) {
2624 dictDelete(server.sharingpool,de->key);
2625 }
2626 } else {
2627 c = 0; /* If the pool is empty we want to add this object */
2628 }
2629 if (c == 0) {
2630 int retval;
2631
2632 retval = dictAdd(server.sharingpool,o,(void*)1);
dfc5e96c 2633 redisAssert(retval == DICT_OK);
10c43610 2634 incrRefCount(o);
2635 }
2636 return o;
2637 }
2638}
2639
724a51b1 2640/* Check if the nul-terminated string 's' can be represented by a long
2641 * (that is, is a number that fits into long without any other space or
2642 * character before or after the digits).
2643 *
2644 * If so, the function returns REDIS_OK and *longval is set to the value
2645 * of the number. Otherwise REDIS_ERR is returned */
f69f2cba 2646static int isStringRepresentableAsLong(sds s, long *longval) {
724a51b1 2647 char buf[32], *endptr;
2648 long value;
2649 int slen;
2650
2651 value = strtol(s, &endptr, 10);
2652 if (endptr[0] != '\0') return REDIS_ERR;
2653 slen = snprintf(buf,32,"%ld",value);
2654
2655 /* If the number converted back into a string is not identical
2656 * then it's not possible to encode the string as integer */
f69f2cba 2657 if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR;
724a51b1 2658 if (longval) *longval = value;
2659 return REDIS_OK;
2660}
2661
942a3961 2662/* Try to encode a string object in order to save space */
2663static int tryObjectEncoding(robj *o) {
2664 long value;
942a3961 2665 sds s = o->ptr;
3305306f 2666
942a3961 2667 if (o->encoding != REDIS_ENCODING_RAW)
2668 return REDIS_ERR; /* Already encoded */
3305306f 2669
942a3961 2670 /* It's not save to encode shared objects: shared objects can be shared
2671 * everywhere in the "object space" of Redis. Encoded objects can only
2672 * appear as "values" (and not, for instance, as keys) */
2673 if (o->refcount > 1) return REDIS_ERR;
3305306f 2674
942a3961 2675 /* Currently we try to encode only strings */
dfc5e96c 2676 redisAssert(o->type == REDIS_STRING);
94754ccc 2677
724a51b1 2678 /* Check if we can represent this string as a long integer */
2679 if (isStringRepresentableAsLong(s,&value) == REDIS_ERR) return REDIS_ERR;
942a3961 2680
2681 /* Ok, this object can be encoded */
2682 o->encoding = REDIS_ENCODING_INT;
2683 sdsfree(o->ptr);
2684 o->ptr = (void*) value;
2685 return REDIS_OK;
2686}
2687
9d65a1bb 2688/* Get a decoded version of an encoded object (returned as a new object).
2689 * If the object is already raw-encoded just increment the ref count. */
2690static robj *getDecodedObject(robj *o) {
942a3961 2691 robj *dec;
2692
9d65a1bb 2693 if (o->encoding == REDIS_ENCODING_RAW) {
2694 incrRefCount(o);
2695 return o;
2696 }
942a3961 2697 if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) {
2698 char buf[32];
2699
2700 snprintf(buf,32,"%ld",(long)o->ptr);
2701 dec = createStringObject(buf,strlen(buf));
2702 return dec;
2703 } else {
dfc5e96c 2704 redisAssert(1 != 1);
942a3961 2705 }
3305306f 2706}
2707
d7f43c08 2708/* Compare two string objects via strcmp() or alike.
2709 * Note that the objects may be integer-encoded. In such a case we
2710 * use snprintf() to get a string representation of the numbers on the stack
1fd9bc8a 2711 * and compare the strings, it's much faster than calling getDecodedObject().
2712 *
2713 * Important note: if objects are not integer encoded, but binary-safe strings,
2714 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
2715 * binary safe. */
724a51b1 2716static int compareStringObjects(robj *a, robj *b) {
dfc5e96c 2717 redisAssert(a->type == REDIS_STRING && b->type == REDIS_STRING);
d7f43c08 2718 char bufa[128], bufb[128], *astr, *bstr;
2719 int bothsds = 1;
724a51b1 2720
e197b441 2721 if (a == b) return 0;
d7f43c08 2722 if (a->encoding != REDIS_ENCODING_RAW) {
2723 snprintf(bufa,sizeof(bufa),"%ld",(long) a->ptr);
2724 astr = bufa;
2725 bothsds = 0;
724a51b1 2726 } else {
d7f43c08 2727 astr = a->ptr;
724a51b1 2728 }
d7f43c08 2729 if (b->encoding != REDIS_ENCODING_RAW) {
2730 snprintf(bufb,sizeof(bufb),"%ld",(long) b->ptr);
2731 bstr = bufb;
2732 bothsds = 0;
2733 } else {
2734 bstr = b->ptr;
2735 }
2736 return bothsds ? sdscmp(astr,bstr) : strcmp(astr,bstr);
724a51b1 2737}
2738
0ea663ea 2739static size_t stringObjectLen(robj *o) {
dfc5e96c 2740 redisAssert(o->type == REDIS_STRING);
0ea663ea 2741 if (o->encoding == REDIS_ENCODING_RAW) {
2742 return sdslen(o->ptr);
2743 } else {
2744 char buf[32];
2745
2746 return snprintf(buf,32,"%ld",(long)o->ptr);
2747 }
2748}
2749
06233c45 2750/*============================ RDB saving/loading =========================== */
ed9b544e 2751
f78fd11b 2752static int rdbSaveType(FILE *fp, unsigned char type) {
2753 if (fwrite(&type,1,1,fp) == 0) return -1;
2754 return 0;
2755}
2756
bb32ede5 2757static int rdbSaveTime(FILE *fp, time_t t) {
2758 int32_t t32 = (int32_t) t;
2759 if (fwrite(&t32,4,1,fp) == 0) return -1;
2760 return 0;
2761}
2762
e3566d4b 2763/* check rdbLoadLen() comments for more info */
f78fd11b 2764static int rdbSaveLen(FILE *fp, uint32_t len) {
2765 unsigned char buf[2];
2766
2767 if (len < (1<<6)) {
2768 /* Save a 6 bit len */
10c43610 2769 buf[0] = (len&0xFF)|(REDIS_RDB_6BITLEN<<6);
f78fd11b 2770 if (fwrite(buf,1,1,fp) == 0) return -1;
2771 } else if (len < (1<<14)) {
2772 /* Save a 14 bit len */
10c43610 2773 buf[0] = ((len>>8)&0xFF)|(REDIS_RDB_14BITLEN<<6);
f78fd11b 2774 buf[1] = len&0xFF;
17be1a4a 2775 if (fwrite(buf,2,1,fp) == 0) return -1;
f78fd11b 2776 } else {
2777 /* Save a 32 bit len */
10c43610 2778 buf[0] = (REDIS_RDB_32BITLEN<<6);
f78fd11b 2779 if (fwrite(buf,1,1,fp) == 0) return -1;
2780 len = htonl(len);
2781 if (fwrite(&len,4,1,fp) == 0) return -1;
2782 }
2783 return 0;
2784}
2785
e3566d4b 2786/* String objects in the form "2391" "-100" without any space and with a
2787 * range of values that can fit in an 8, 16 or 32 bit signed value can be
2788 * encoded as integers to save space */
56906eef 2789static int rdbTryIntegerEncoding(sds s, unsigned char *enc) {
e3566d4b 2790 long long value;
2791 char *endptr, buf[32];
2792
2793 /* Check if it's possible to encode this value as a number */
2794 value = strtoll(s, &endptr, 10);
2795 if (endptr[0] != '\0') return 0;
2796 snprintf(buf,32,"%lld",value);
2797
2798 /* If the number converted back into a string is not identical
2799 * then it's not possible to encode the string as integer */
2800 if (strlen(buf) != sdslen(s) || memcmp(buf,s,sdslen(s))) return 0;
2801
2802 /* Finally check if it fits in our ranges */
2803 if (value >= -(1<<7) && value <= (1<<7)-1) {
2804 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT8;
2805 enc[1] = value&0xFF;
2806 return 2;
2807 } else if (value >= -(1<<15) && value <= (1<<15)-1) {
2808 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT16;
2809 enc[1] = value&0xFF;
2810 enc[2] = (value>>8)&0xFF;
2811 return 3;
2812 } else if (value >= -((long long)1<<31) && value <= ((long long)1<<31)-1) {
2813 enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT32;
2814 enc[1] = value&0xFF;
2815 enc[2] = (value>>8)&0xFF;
2816 enc[3] = (value>>16)&0xFF;
2817 enc[4] = (value>>24)&0xFF;
2818 return 5;
2819 } else {
2820 return 0;
2821 }
2822}
2823
774e3047 2824static int rdbSaveLzfStringObject(FILE *fp, robj *obj) {
2825 unsigned int comprlen, outlen;
2826 unsigned char byte;
2827 void *out;
2828
2829 /* We require at least four bytes compression for this to be worth it */
2830 outlen = sdslen(obj->ptr)-4;
2831 if (outlen <= 0) return 0;
3a2694c4 2832 if ((out = zmalloc(outlen+1)) == NULL) return 0;
774e3047 2833 comprlen = lzf_compress(obj->ptr, sdslen(obj->ptr), out, outlen);
2834 if (comprlen == 0) {
88e85998 2835 zfree(out);
774e3047 2836 return 0;
2837 }
2838 /* Data compressed! Let's save it on disk */
2839 byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF;
2840 if (fwrite(&byte,1,1,fp) == 0) goto writeerr;
2841 if (rdbSaveLen(fp,comprlen) == -1) goto writeerr;
2842 if (rdbSaveLen(fp,sdslen(obj->ptr)) == -1) goto writeerr;
2843 if (fwrite(out,comprlen,1,fp) == 0) goto writeerr;
88e85998 2844 zfree(out);
774e3047 2845 return comprlen;
2846
2847writeerr:
88e85998 2848 zfree(out);
774e3047 2849 return -1;
2850}
2851
e3566d4b 2852/* Save a string objet as [len][data] on disk. If the object is a string
2853 * representation of an integer value we try to safe it in a special form */
942a3961 2854static int rdbSaveStringObjectRaw(FILE *fp, robj *obj) {
2855 size_t len;
e3566d4b 2856 int enclen;
10c43610 2857
942a3961 2858 len = sdslen(obj->ptr);
2859
774e3047 2860 /* Try integer encoding */
e3566d4b 2861 if (len <= 11) {
2862 unsigned char buf[5];
2863 if ((enclen = rdbTryIntegerEncoding(obj->ptr,buf)) > 0) {
2864 if (fwrite(buf,enclen,1,fp) == 0) return -1;
2865 return 0;
2866 }
2867 }
774e3047 2868
2869 /* Try LZF compression - under 20 bytes it's unable to compress even
88e85998 2870 * aaaaaaaaaaaaaaaaaa so skip it */
121f70cf 2871 if (server.rdbcompression && len > 20) {
774e3047 2872 int retval;
2873
2874 retval = rdbSaveLzfStringObject(fp,obj);
2875 if (retval == -1) return -1;
2876 if (retval > 0) return 0;
2877 /* retval == 0 means data can't be compressed, save the old way */
2878 }
2879
2880 /* Store verbatim */
10c43610 2881 if (rdbSaveLen(fp,len) == -1) return -1;
2882 if (len && fwrite(obj->ptr,len,1,fp) == 0) return -1;
2883 return 0;
2884}
2885
942a3961 2886/* Like rdbSaveStringObjectRaw() but handle encoded objects */
2887static int rdbSaveStringObject(FILE *fp, robj *obj) {
2888 int retval;
942a3961 2889
f2d9f50f 2890 /* Avoid incr/decr ref count business when possible.
2891 * This plays well with copy-on-write given that we are probably
2892 * in a child process (BGSAVE). Also this makes sure key objects
2893 * of swapped objects are not incRefCount-ed (an assert does not allow
2894 * this in order to avoid bugs) */
2895 if (obj->encoding != REDIS_ENCODING_RAW) {
996cb5f7 2896 obj = getDecodedObject(obj);
2897 retval = rdbSaveStringObjectRaw(fp,obj);
2898 decrRefCount(obj);
2899 } else {
996cb5f7 2900 retval = rdbSaveStringObjectRaw(fp,obj);
2901 }
9d65a1bb 2902 return retval;
942a3961 2903}
2904
a7866db6 2905/* Save a double value. Doubles are saved as strings prefixed by an unsigned
2906 * 8 bit integer specifing the length of the representation.
2907 * This 8 bit integer has special values in order to specify the following
2908 * conditions:
2909 * 253: not a number
2910 * 254: + inf
2911 * 255: - inf
2912 */
2913static int rdbSaveDoubleValue(FILE *fp, double val) {
2914 unsigned char buf[128];
2915 int len;
2916
2917 if (isnan(val)) {
2918 buf[0] = 253;
2919 len = 1;
2920 } else if (!isfinite(val)) {
2921 len = 1;
2922 buf[0] = (val < 0) ? 255 : 254;
2923 } else {
eaa256ad 2924 snprintf((char*)buf+1,sizeof(buf)-1,"%.17g",val);
6c446631 2925 buf[0] = strlen((char*)buf+1);
a7866db6 2926 len = buf[0]+1;
2927 }
2928 if (fwrite(buf,len,1,fp) == 0) return -1;
2929 return 0;
2930}
2931
06233c45 2932/* Save a Redis object. */
2933static int rdbSaveObject(FILE *fp, robj *o) {
2934 if (o->type == REDIS_STRING) {
2935 /* Save a string value */
2936 if (rdbSaveStringObject(fp,o) == -1) return -1;
2937 } else if (o->type == REDIS_LIST) {
2938 /* Save a list value */
2939 list *list = o->ptr;
c7df85a4 2940 listIter li;
06233c45 2941 listNode *ln;
2942
06233c45 2943 if (rdbSaveLen(fp,listLength(list)) == -1) return -1;
c7df85a4 2944 listRewind(list,&li);
2945 while((ln = listNext(&li))) {
06233c45 2946 robj *eleobj = listNodeValue(ln);
2947
2948 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
2949 }
2950 } else if (o->type == REDIS_SET) {
2951 /* Save a set value */
2952 dict *set = o->ptr;
2953 dictIterator *di = dictGetIterator(set);
2954 dictEntry *de;
2955
2956 if (rdbSaveLen(fp,dictSize(set)) == -1) return -1;
2957 while((de = dictNext(di)) != NULL) {
2958 robj *eleobj = dictGetEntryKey(de);
2959
2960 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
2961 }
2962 dictReleaseIterator(di);
2963 } else if (o->type == REDIS_ZSET) {
2964 /* Save a set value */
2965 zset *zs = o->ptr;
2966 dictIterator *di = dictGetIterator(zs->dict);
2967 dictEntry *de;
2968
2969 if (rdbSaveLen(fp,dictSize(zs->dict)) == -1) return -1;
2970 while((de = dictNext(di)) != NULL) {
2971 robj *eleobj = dictGetEntryKey(de);
2972 double *score = dictGetEntryVal(de);
2973
2974 if (rdbSaveStringObject(fp,eleobj) == -1) return -1;
2975 if (rdbSaveDoubleValue(fp,*score) == -1) return -1;
2976 }
2977 dictReleaseIterator(di);
2978 } else {
2979 redisAssert(0 != 0);
2980 }
2981 return 0;
2982}
2983
2984/* Return the length the object will have on disk if saved with
2985 * the rdbSaveObject() function. Currently we use a trick to get
2986 * this length with very little changes to the code. In the future
2987 * we could switch to a faster solution. */
b9bc0eef 2988static off_t rdbSavedObjectLen(robj *o, FILE *fp) {
2989 if (fp == NULL) fp = server.devnull;
06233c45 2990 rewind(fp);
2991 assert(rdbSaveObject(fp,o) != 1);
2992 return ftello(fp);
2993}
2994
06224fec 2995/* Return the number of pages required to save this object in the swap file */
b9bc0eef 2996static off_t rdbSavedObjectPages(robj *o, FILE *fp) {
2997 off_t bytes = rdbSavedObjectLen(o,fp);
06224fec 2998
2999 return (bytes+(server.vm_page_size-1))/server.vm_page_size;
3000}
3001
ed9b544e 3002/* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
f78fd11b 3003static int rdbSave(char *filename) {
ed9b544e 3004 dictIterator *di = NULL;
3005 dictEntry *de;
ed9b544e 3006 FILE *fp;
3007 char tmpfile[256];
3008 int j;
bb32ede5 3009 time_t now = time(NULL);
ed9b544e 3010
2316bb3b 3011 /* Wait for I/O therads to terminate, just in case this is a
3012 * foreground-saving, to avoid seeking the swap file descriptor at the
3013 * same time. */
3014 if (server.vm_enabled)
3015 waitEmptyIOJobsQueue();
3016
a3b21203 3017 snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
ed9b544e 3018 fp = fopen(tmpfile,"w");
3019 if (!fp) {
3020 redisLog(REDIS_WARNING, "Failed saving the DB: %s", strerror(errno));
3021 return REDIS_ERR;
3022 }
f78fd11b 3023 if (fwrite("REDIS0001",9,1,fp) == 0) goto werr;
ed9b544e 3024 for (j = 0; j < server.dbnum; j++) {
bb32ede5 3025 redisDb *db = server.db+j;
3026 dict *d = db->dict;
3305306f 3027 if (dictSize(d) == 0) continue;
ed9b544e 3028 di = dictGetIterator(d);
3029 if (!di) {
3030 fclose(fp);
3031 return REDIS_ERR;
3032 }
3033
3034 /* Write the SELECT DB opcode */
f78fd11b 3035 if (rdbSaveType(fp,REDIS_SELECTDB) == -1) goto werr;
3036 if (rdbSaveLen(fp,j) == -1) goto werr;
ed9b544e 3037
3038 /* Iterate this DB writing every entry */
3039 while((de = dictNext(di)) != NULL) {
3040 robj *key = dictGetEntryKey(de);
3041 robj *o = dictGetEntryVal(de);
bb32ede5 3042 time_t expiretime = getExpire(db,key);
3043
3044 /* Save the expire time */
3045 if (expiretime != -1) {
3046 /* If this key is already expired skip it */
3047 if (expiretime < now) continue;
3048 if (rdbSaveType(fp,REDIS_EXPIRETIME) == -1) goto werr;
3049 if (rdbSaveTime(fp,expiretime) == -1) goto werr;
3050 }
7e69548d 3051 /* Save the key and associated value. This requires special
3052 * handling if the value is swapped out. */
996cb5f7 3053 if (!server.vm_enabled || key->storage == REDIS_VM_MEMORY ||
3054 key->storage == REDIS_VM_SWAPPING) {
7e69548d 3055 /* Save type, key, value */
3056 if (rdbSaveType(fp,o->type) == -1) goto werr;
3057 if (rdbSaveStringObject(fp,key) == -1) goto werr;
3058 if (rdbSaveObject(fp,o) == -1) goto werr;
3059 } else {
996cb5f7 3060 /* REDIS_VM_SWAPPED or REDIS_VM_LOADING */
b9bc0eef 3061 robj *po;
7e69548d 3062 /* Get a preview of the object in memory */
3063 po = vmPreviewObject(key);
7e69548d 3064 /* Save type, key, value */
3065 if (rdbSaveType(fp,key->vtype) == -1) goto werr;
b9bc0eef 3066 if (rdbSaveStringObject(fp,key) == -1) goto werr;
7e69548d 3067 if (rdbSaveObject(fp,po) == -1) goto werr;
3068 /* Remove the loaded object from memory */
3069 decrRefCount(po);
7e69548d 3070 }
ed9b544e 3071 }
3072 dictReleaseIterator(di);
3073 }
3074 /* EOF opcode */
f78fd11b 3075 if (rdbSaveType(fp,REDIS_EOF) == -1) goto werr;
3076
3077 /* Make sure data will not remain on the OS's output buffers */
ed9b544e 3078 fflush(fp);
3079 fsync(fileno(fp));
3080 fclose(fp);
3081
3082 /* Use RENAME to make sure the DB file is changed atomically only
3083 * if the generate DB file is ok. */
3084 if (rename(tmpfile,filename) == -1) {
325d1eb4 3085 redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
ed9b544e 3086 unlink(tmpfile);
3087 return REDIS_ERR;
3088 }
3089 redisLog(REDIS_NOTICE,"DB saved on disk");
3090 server.dirty = 0;
3091 server.lastsave = time(NULL);
3092 return REDIS_OK;
3093
3094werr:
3095 fclose(fp);
3096 unlink(tmpfile);
3097 redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
3098 if (di) dictReleaseIterator(di);
3099 return REDIS_ERR;
3100}
3101
f78fd11b 3102static int rdbSaveBackground(char *filename) {
ed9b544e 3103 pid_t childpid;
3104
9d65a1bb 3105 if (server.bgsavechildpid != -1) return REDIS_ERR;
054e426d 3106 if (server.vm_enabled) waitEmptyIOJobsQueue();
ed9b544e 3107 if ((childpid = fork()) == 0) {
3108 /* Child */
054e426d 3109 if (server.vm_enabled) vmReopenSwapFile();
ed9b544e 3110 close(server.fd);
f78fd11b 3111 if (rdbSave(filename) == REDIS_OK) {
ed9b544e 3112 exit(0);
3113 } else {
3114 exit(1);
3115 }
3116 } else {
3117 /* Parent */
5a7c647e 3118 if (childpid == -1) {
3119 redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
3120 strerror(errno));
3121 return REDIS_ERR;
3122 }
ed9b544e 3123 redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
9f3c422c 3124 server.bgsavechildpid = childpid;
ed9b544e 3125 return REDIS_OK;
3126 }
3127 return REDIS_OK; /* unreached */
3128}
3129
a3b21203 3130static void rdbRemoveTempFile(pid_t childpid) {
3131 char tmpfile[256];
3132
3133 snprintf(tmpfile,256,"temp-%d.rdb", (int) childpid);
3134 unlink(tmpfile);
3135}
3136
f78fd11b 3137static int rdbLoadType(FILE *fp) {
3138 unsigned char type;
7b45bfb2 3139 if (fread(&type,1,1,fp) == 0) return -1;
3140 return type;
3141}
3142
bb32ede5 3143static time_t rdbLoadTime(FILE *fp) {
3144 int32_t t32;
3145 if (fread(&t32,4,1,fp) == 0) return -1;
3146 return (time_t) t32;
3147}
3148
e3566d4b 3149/* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
3150 * of this file for a description of how this are stored on disk.
3151 *
3152 * isencoded is set to 1 if the readed length is not actually a length but
3153 * an "encoding type", check the above comments for more info */
c78a8ccc 3154static uint32_t rdbLoadLen(FILE *fp, int *isencoded) {
f78fd11b 3155 unsigned char buf[2];
3156 uint32_t len;
c78a8ccc 3157 int type;
f78fd11b 3158
e3566d4b 3159 if (isencoded) *isencoded = 0;
c78a8ccc 3160 if (fread(buf,1,1,fp) == 0) return REDIS_RDB_LENERR;
3161 type = (buf[0]&0xC0)>>6;
3162 if (type == REDIS_RDB_6BITLEN) {
3163 /* Read a 6 bit len */
3164 return buf[0]&0x3F;
3165 } else if (type == REDIS_RDB_ENCVAL) {
3166 /* Read a 6 bit len encoding type */
3167 if (isencoded) *isencoded = 1;
3168 return buf[0]&0x3F;
3169 } else if (type == REDIS_RDB_14BITLEN) {
3170 /* Read a 14 bit len */
3171 if (fread(buf+1,1,1,fp) == 0) return REDIS_RDB_LENERR;
3172 return ((buf[0]&0x3F)<<8)|buf[1];
3173 } else {
3174 /* Read a 32 bit len */
f78fd11b 3175 if (fread(&len,4,1,fp) == 0) return REDIS_RDB_LENERR;
3176 return ntohl(len);
f78fd11b 3177 }
f78fd11b 3178}
3179
e3566d4b 3180static robj *rdbLoadIntegerObject(FILE *fp, int enctype) {
3181 unsigned char enc[4];
3182 long long val;
3183
3184 if (enctype == REDIS_RDB_ENC_INT8) {
3185 if (fread(enc,1,1,fp) == 0) return NULL;
3186 val = (signed char)enc[0];
3187 } else if (enctype == REDIS_RDB_ENC_INT16) {
3188 uint16_t v;
3189 if (fread(enc,2,1,fp) == 0) return NULL;
3190 v = enc[0]|(enc[1]<<8);
3191 val = (int16_t)v;
3192 } else if (enctype == REDIS_RDB_ENC_INT32) {
3193 uint32_t v;
3194 if (fread(enc,4,1,fp) == 0) return NULL;
3195 v = enc[0]|(enc[1]<<8)|(enc[2]<<16)|(enc[3]<<24);
3196 val = (int32_t)v;
3197 } else {
3198 val = 0; /* anti-warning */
dfc5e96c 3199 redisAssert(0!=0);
e3566d4b 3200 }
3201 return createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",val));
3202}
3203
c78a8ccc 3204static robj *rdbLoadLzfStringObject(FILE*fp) {
88e85998 3205 unsigned int len, clen;
3206 unsigned char *c = NULL;
3207 sds val = NULL;
3208
c78a8ccc 3209 if ((clen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
3210 if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
88e85998 3211 if ((c = zmalloc(clen)) == NULL) goto err;
3212 if ((val = sdsnewlen(NULL,len)) == NULL) goto err;
3213 if (fread(c,clen,1,fp) == 0) goto err;
3214 if (lzf_decompress(c,clen,val,len) == 0) goto err;
5109cdff 3215 zfree(c);
88e85998 3216 return createObject(REDIS_STRING,val);
3217err:
3218 zfree(c);
3219 sdsfree(val);
3220 return NULL;
3221}
3222
c78a8ccc 3223static robj *rdbLoadStringObject(FILE*fp) {
e3566d4b 3224 int isencoded;
3225 uint32_t len;
f78fd11b 3226 sds val;
3227
c78a8ccc 3228 len = rdbLoadLen(fp,&isencoded);
e3566d4b 3229 if (isencoded) {
3230 switch(len) {
3231 case REDIS_RDB_ENC_INT8:
3232 case REDIS_RDB_ENC_INT16:
3233 case REDIS_RDB_ENC_INT32:
3305306f 3234 return tryObjectSharing(rdbLoadIntegerObject(fp,len));
88e85998 3235 case REDIS_RDB_ENC_LZF:
c78a8ccc 3236 return tryObjectSharing(rdbLoadLzfStringObject(fp));
e3566d4b 3237 default:
dfc5e96c 3238 redisAssert(0!=0);
e3566d4b 3239 }
3240 }
3241
f78fd11b 3242 if (len == REDIS_RDB_LENERR) return NULL;
3243 val = sdsnewlen(NULL,len);
3244 if (len && fread(val,len,1,fp) == 0) {
3245 sdsfree(val);
3246 return NULL;
3247 }
10c43610 3248 return tryObjectSharing(createObject(REDIS_STRING,val));
f78fd11b 3249}
3250
a7866db6 3251/* For information about double serialization check rdbSaveDoubleValue() */
3252static int rdbLoadDoubleValue(FILE *fp, double *val) {
3253 char buf[128];
3254 unsigned char len;
3255
3256 if (fread(&len,1,1,fp) == 0) return -1;
3257 switch(len) {
3258 case 255: *val = R_NegInf; return 0;
3259 case 254: *val = R_PosInf; return 0;
3260 case 253: *val = R_Nan; return 0;
3261 default:
3262 if (fread(buf,len,1,fp) == 0) return -1;
231d758e 3263 buf[len] = '\0';
a7866db6 3264 sscanf(buf, "%lg", val);
3265 return 0;
3266 }
3267}
3268
c78a8ccc 3269/* Load a Redis object of the specified type from the specified file.
3270 * On success a newly allocated object is returned, otherwise NULL. */
3271static robj *rdbLoadObject(int type, FILE *fp) {
3272 robj *o;
3273
3274 if (type == REDIS_STRING) {
3275 /* Read string value */
3276 if ((o = rdbLoadStringObject(fp)) == NULL) return NULL;
3277 tryObjectEncoding(o);
3278 } else if (type == REDIS_LIST || type == REDIS_SET) {
3279 /* Read list/set value */
3280 uint32_t listlen;
3281
3282 if ((listlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
3283 o = (type == REDIS_LIST) ? createListObject() : createSetObject();
3284 /* Load every single element of the list/set */
3285 while(listlen--) {
3286 robj *ele;
3287
3288 if ((ele = rdbLoadStringObject(fp)) == NULL) return NULL;
3289 tryObjectEncoding(ele);
3290 if (type == REDIS_LIST) {
3291 listAddNodeTail((list*)o->ptr,ele);
3292 } else {
3293 dictAdd((dict*)o->ptr,ele,NULL);
3294 }
3295 }
3296 } else if (type == REDIS_ZSET) {
3297 /* Read list/set value */
3298 uint32_t zsetlen;
3299 zset *zs;
3300
3301 if ((zsetlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
3302 o = createZsetObject();
3303 zs = o->ptr;
3304 /* Load every single element of the list/set */
3305 while(zsetlen--) {
3306 robj *ele;
3307 double *score = zmalloc(sizeof(double));
3308
3309 if ((ele = rdbLoadStringObject(fp)) == NULL) return NULL;
3310 tryObjectEncoding(ele);
3311 if (rdbLoadDoubleValue(fp,score) == -1) return NULL;
3312 dictAdd(zs->dict,ele,score);
3313 zslInsert(zs->zsl,*score,ele);
3314 incrRefCount(ele); /* added to skiplist */
3315 }
3316 } else {
3317 redisAssert(0 != 0);
3318 }
3319 return o;
3320}
3321
f78fd11b 3322static int rdbLoad(char *filename) {
ed9b544e 3323 FILE *fp;
f78fd11b 3324 robj *keyobj = NULL;
3325 uint32_t dbid;
bb32ede5 3326 int type, retval, rdbver;
3305306f 3327 dict *d = server.db[0].dict;
bb32ede5 3328 redisDb *db = server.db+0;
f78fd11b 3329 char buf[1024];
bb32ede5 3330 time_t expiretime = -1, now = time(NULL);
b492cf00 3331 long long loadedkeys = 0;
bb32ede5 3332
ed9b544e 3333 fp = fopen(filename,"r");
3334 if (!fp) return REDIS_ERR;
3335 if (fread(buf,9,1,fp) == 0) goto eoferr;
f78fd11b 3336 buf[9] = '\0';
3337 if (memcmp(buf,"REDIS",5) != 0) {
ed9b544e 3338 fclose(fp);
3339 redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
3340 return REDIS_ERR;
3341 }
f78fd11b 3342 rdbver = atoi(buf+5);
c78a8ccc 3343 if (rdbver != 1) {
f78fd11b 3344 fclose(fp);
3345 redisLog(REDIS_WARNING,"Can't handle RDB format version %d",rdbver);
3346 return REDIS_ERR;
3347 }
ed9b544e 3348 while(1) {
3349 robj *o;
3350
3351 /* Read type. */
f78fd11b 3352 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
bb32ede5 3353 if (type == REDIS_EXPIRETIME) {
3354 if ((expiretime = rdbLoadTime(fp)) == -1) goto eoferr;
3355 /* We read the time so we need to read the object type again */
3356 if ((type = rdbLoadType(fp)) == -1) goto eoferr;
3357 }
ed9b544e 3358 if (type == REDIS_EOF) break;
3359 /* Handle SELECT DB opcode as a special case */
3360 if (type == REDIS_SELECTDB) {
c78a8ccc 3361 if ((dbid = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR)
e3566d4b 3362 goto eoferr;
ed9b544e 3363 if (dbid >= (unsigned)server.dbnum) {
f78fd11b 3364 redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum);
ed9b544e 3365 exit(1);
3366 }
bb32ede5 3367 db = server.db+dbid;
3368 d = db->dict;
ed9b544e 3369 continue;
3370 }
3371 /* Read key */
c78a8ccc 3372 if ((keyobj = rdbLoadStringObject(fp)) == NULL) goto eoferr;
3373 /* Read value */
3374 if ((o = rdbLoadObject(type,fp)) == NULL) goto eoferr;
ed9b544e 3375 /* Add the new object in the hash table */
f78fd11b 3376 retval = dictAdd(d,keyobj,o);
ed9b544e 3377 if (retval == DICT_ERR) {
f78fd11b 3378 redisLog(REDIS_WARNING,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", keyobj->ptr);
ed9b544e 3379 exit(1);
3380 }
bb32ede5 3381 /* Set the expire time if needed */
3382 if (expiretime != -1) {
3383 setExpire(db,keyobj,expiretime);
3384 /* Delete this key if already expired */
3385 if (expiretime < now) deleteKey(db,keyobj);
3386 expiretime = -1;
3387 }
f78fd11b 3388 keyobj = o = NULL;
b492cf00 3389 /* Handle swapping while loading big datasets when VM is on */
3390 loadedkeys++;
3391 if (server.vm_enabled && (loadedkeys % 5000) == 0) {
3392 while (zmalloc_used_memory() > server.vm_max_memory) {
a69a0c9c 3393 if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
b492cf00 3394 }
3395 }
ed9b544e 3396 }
3397 fclose(fp);
3398 return REDIS_OK;
3399
3400eoferr: /* unexpected end of file is handled here with a fatal exit */
e3566d4b 3401 if (keyobj) decrRefCount(keyobj);
f80dff62 3402 redisLog(REDIS_WARNING,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
ed9b544e 3403 exit(1);
3404 return REDIS_ERR; /* Just to avoid warning */
3405}
3406
3407/*================================== Commands =============================== */
3408
abcb223e 3409static void authCommand(redisClient *c) {
2e77c2ee 3410 if (!server.requirepass || !strcmp(c->argv[1]->ptr, server.requirepass)) {
abcb223e
BH
3411 c->authenticated = 1;
3412 addReply(c,shared.ok);
3413 } else {
3414 c->authenticated = 0;
fa4c0aba 3415 addReplySds(c,sdscatprintf(sdsempty(),"-ERR invalid password\r\n"));
abcb223e
BH
3416 }
3417}
3418
ed9b544e 3419static void pingCommand(redisClient *c) {
3420 addReply(c,shared.pong);
3421}
3422
3423static void echoCommand(redisClient *c) {
942a3961 3424 addReplyBulkLen(c,c->argv[1]);
ed9b544e 3425 addReply(c,c->argv[1]);
3426 addReply(c,shared.crlf);
3427}
3428
3429/*=================================== Strings =============================== */
3430
3431static void setGenericCommand(redisClient *c, int nx) {
3432 int retval;
3433
333fd216 3434 if (nx) deleteIfVolatile(c->db,c->argv[1]);
3305306f 3435 retval = dictAdd(c->db->dict,c->argv[1],c->argv[2]);
ed9b544e 3436 if (retval == DICT_ERR) {
3437 if (!nx) {
1b03836c 3438 /* If the key is about a swapped value, we want a new key object
3439 * to overwrite the old. So we delete the old key in the database.
3440 * This will also make sure that swap pages about the old object
3441 * will be marked as free. */
3442 if (deleteIfSwapped(c->db,c->argv[1]))
3443 incrRefCount(c->argv[1]);
3305306f 3444 dictReplace(c->db->dict,c->argv[1],c->argv[2]);
ed9b544e 3445 incrRefCount(c->argv[2]);
3446 } else {
c937aa89 3447 addReply(c,shared.czero);
ed9b544e 3448 return;
3449 }
3450 } else {
3451 incrRefCount(c->argv[1]);
3452 incrRefCount(c->argv[2]);
3453 }
3454 server.dirty++;
3305306f 3455 removeExpire(c->db,c->argv[1]);
c937aa89 3456 addReply(c, nx ? shared.cone : shared.ok);
ed9b544e 3457}
3458
3459static void setCommand(redisClient *c) {
a4d1ba9a 3460 setGenericCommand(c,0);
ed9b544e 3461}
3462
3463static void setnxCommand(redisClient *c) {
a4d1ba9a 3464 setGenericCommand(c,1);
ed9b544e 3465}
3466
322fc7d8 3467static int getGenericCommand(redisClient *c) {
3305306f 3468 robj *o = lookupKeyRead(c->db,c->argv[1]);
3469
3470 if (o == NULL) {
c937aa89 3471 addReply(c,shared.nullbulk);
322fc7d8 3472 return REDIS_OK;
ed9b544e 3473 } else {
ed9b544e 3474 if (o->type != REDIS_STRING) {
c937aa89 3475 addReply(c,shared.wrongtypeerr);
322fc7d8 3476 return REDIS_ERR;
ed9b544e 3477 } else {
942a3961 3478 addReplyBulkLen(c,o);
ed9b544e 3479 addReply(c,o);
3480 addReply(c,shared.crlf);
322fc7d8 3481 return REDIS_OK;
ed9b544e 3482 }
3483 }
3484}
3485
322fc7d8 3486static void getCommand(redisClient *c) {
3487 getGenericCommand(c);
3488}
3489
f6b141c5 3490static void getsetCommand(redisClient *c) {
322fc7d8 3491 if (getGenericCommand(c) == REDIS_ERR) return;
a431eb74 3492 if (dictAdd(c->db->dict,c->argv[1],c->argv[2]) == DICT_ERR) {
3493 dictReplace(c->db->dict,c->argv[1],c->argv[2]);
3494 } else {
3495 incrRefCount(c->argv[1]);
3496 }
3497 incrRefCount(c->argv[2]);
3498 server.dirty++;
3499 removeExpire(c->db,c->argv[1]);
3500}
3501
70003d28 3502static void mgetCommand(redisClient *c) {
70003d28 3503 int j;
3504
c937aa89 3505 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-1));
70003d28 3506 for (j = 1; j < c->argc; j++) {
3305306f 3507 robj *o = lookupKeyRead(c->db,c->argv[j]);
3508 if (o == NULL) {
c937aa89 3509 addReply(c,shared.nullbulk);
70003d28 3510 } else {
70003d28 3511 if (o->type != REDIS_STRING) {
c937aa89 3512 addReply(c,shared.nullbulk);
70003d28 3513 } else {
942a3961 3514 addReplyBulkLen(c,o);
70003d28 3515 addReply(c,o);
3516 addReply(c,shared.crlf);
3517 }
3518 }
3519 }
3520}
3521
6c446631 3522static void msetGenericCommand(redisClient *c, int nx) {
906573e7 3523 int j, busykeys = 0;
6c446631 3524
3525 if ((c->argc % 2) == 0) {
454d4e43 3526 addReplySds(c,sdsnew("-ERR wrong number of arguments for MSET\r\n"));
6c446631 3527 return;
3528 }
3529 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
3530 * set nothing at all if at least one already key exists. */
3531 if (nx) {
3532 for (j = 1; j < c->argc; j += 2) {
906573e7 3533 if (lookupKeyWrite(c->db,c->argv[j]) != NULL) {
3534 busykeys++;
6c446631 3535 }
3536 }
3537 }
906573e7 3538 if (busykeys) {
3539 addReply(c, shared.czero);
3540 return;
3541 }
6c446631 3542
3543 for (j = 1; j < c->argc; j += 2) {
3544 int retval;
3545
17511391 3546 tryObjectEncoding(c->argv[j+1]);
6c446631 3547 retval = dictAdd(c->db->dict,c->argv[j],c->argv[j+1]);
3548 if (retval == DICT_ERR) {
3549 dictReplace(c->db->dict,c->argv[j],c->argv[j+1]);
3550 incrRefCount(c->argv[j+1]);
3551 } else {
3552 incrRefCount(c->argv[j]);
3553 incrRefCount(c->argv[j+1]);
3554 }
3555 removeExpire(c->db,c->argv[j]);
3556 }
3557 server.dirty += (c->argc-1)/2;
3558 addReply(c, nx ? shared.cone : shared.ok);
3559}
3560
3561static void msetCommand(redisClient *c) {
3562 msetGenericCommand(c,0);
3563}
3564
3565static void msetnxCommand(redisClient *c) {
3566 msetGenericCommand(c,1);
3567}
3568
d68ed120 3569static void incrDecrCommand(redisClient *c, long long incr) {
ed9b544e 3570 long long value;
3571 int retval;
3572 robj *o;
3573
3305306f 3574 o = lookupKeyWrite(c->db,c->argv[1]);
3575 if (o == NULL) {
ed9b544e 3576 value = 0;
3577 } else {
ed9b544e 3578 if (o->type != REDIS_STRING) {
3579 value = 0;
3580 } else {
3581 char *eptr;
3582
942a3961 3583 if (o->encoding == REDIS_ENCODING_RAW)
3584 value = strtoll(o->ptr, &eptr, 10);
3585 else if (o->encoding == REDIS_ENCODING_INT)
3586 value = (long)o->ptr;
3587 else
dfc5e96c 3588 redisAssert(1 != 1);
ed9b544e 3589 }
3590 }
3591
3592 value += incr;
3593 o = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
942a3961 3594 tryObjectEncoding(o);
3305306f 3595 retval = dictAdd(c->db->dict,c->argv[1],o);
ed9b544e 3596 if (retval == DICT_ERR) {
3305306f 3597 dictReplace(c->db->dict,c->argv[1],o);
3598 removeExpire(c->db,c->argv[1]);
ed9b544e 3599 } else {
3600 incrRefCount(c->argv[1]);
3601 }
3602 server.dirty++;
c937aa89 3603 addReply(c,shared.colon);
ed9b544e 3604 addReply(c,o);
3605 addReply(c,shared.crlf);
3606}
3607
3608static void incrCommand(redisClient *c) {
a4d1ba9a 3609 incrDecrCommand(c,1);
ed9b544e 3610}
3611
3612static void decrCommand(redisClient *c) {
a4d1ba9a 3613 incrDecrCommand(c,-1);
ed9b544e 3614}
3615
3616static void incrbyCommand(redisClient *c) {
d68ed120 3617 long long incr = strtoll(c->argv[2]->ptr, NULL, 10);
a4d1ba9a 3618 incrDecrCommand(c,incr);
ed9b544e 3619}
3620
3621static void decrbyCommand(redisClient *c) {
d68ed120 3622 long long incr = strtoll(c->argv[2]->ptr, NULL, 10);
a4d1ba9a 3623 incrDecrCommand(c,-incr);
ed9b544e 3624}
3625
3626/* ========================= Type agnostic commands ========================= */
3627
3628static void delCommand(redisClient *c) {
5109cdff 3629 int deleted = 0, j;
3630
3631 for (j = 1; j < c->argc; j++) {
3632 if (deleteKey(c->db,c->argv[j])) {
3633 server.dirty++;
3634 deleted++;
3635 }
3636 }
3637 switch(deleted) {
3638 case 0:
c937aa89 3639 addReply(c,shared.czero);
5109cdff 3640 break;
3641 case 1:
3642 addReply(c,shared.cone);
3643 break;
3644 default:
3645 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",deleted));
3646 break;
ed9b544e 3647 }
3648}
3649
3650static void existsCommand(redisClient *c) {
3305306f 3651 addReply(c,lookupKeyRead(c->db,c->argv[1]) ? shared.cone : shared.czero);
ed9b544e 3652}
3653
3654static void selectCommand(redisClient *c) {
3655 int id = atoi(c->argv[1]->ptr);
3656
3657 if (selectDb(c,id) == REDIS_ERR) {
774e3047 3658 addReplySds(c,sdsnew("-ERR invalid DB index\r\n"));
ed9b544e 3659 } else {
3660 addReply(c,shared.ok);
3661 }
3662}
3663
3664static void randomkeyCommand(redisClient *c) {
3665 dictEntry *de;
3305306f 3666
3667 while(1) {
3668 de = dictGetRandomKey(c->db->dict);
ce7bef07 3669 if (!de || expireIfNeeded(c->db,dictGetEntryKey(de)) == 0) break;
3305306f 3670 }
ed9b544e 3671 if (de == NULL) {
ce7bef07 3672 addReply(c,shared.plus);
ed9b544e 3673 addReply(c,shared.crlf);
3674 } else {
c937aa89 3675 addReply(c,shared.plus);
ed9b544e 3676 addReply(c,dictGetEntryKey(de));
3677 addReply(c,shared.crlf);
3678 }
3679}
3680
3681static void keysCommand(redisClient *c) {
3682 dictIterator *di;
3683 dictEntry *de;
3684 sds pattern = c->argv[1]->ptr;
3685 int plen = sdslen(pattern);
682ac724 3686 unsigned long numkeys = 0, keyslen = 0;
ed9b544e 3687 robj *lenobj = createObject(REDIS_STRING,NULL);
3688
3305306f 3689 di = dictGetIterator(c->db->dict);
ed9b544e 3690 addReply(c,lenobj);
3691 decrRefCount(lenobj);
3692 while((de = dictNext(di)) != NULL) {
3693 robj *keyobj = dictGetEntryKey(de);
3305306f 3694
ed9b544e 3695 sds key = keyobj->ptr;
3696 if ((pattern[0] == '*' && pattern[1] == '\0') ||
3697 stringmatchlen(pattern,plen,key,sdslen(key),0)) {
3305306f 3698 if (expireIfNeeded(c->db,keyobj) == 0) {
3699 if (numkeys != 0)
3700 addReply(c,shared.space);
3701 addReply(c,keyobj);
3702 numkeys++;
3703 keyslen += sdslen(key);
3704 }
ed9b544e 3705 }
3706 }
3707 dictReleaseIterator(di);
c937aa89 3708 lenobj->ptr = sdscatprintf(sdsempty(),"$%lu\r\n",keyslen+(numkeys ? (numkeys-1) : 0));
ed9b544e 3709 addReply(c,shared.crlf);
3710}
3711
3712static void dbsizeCommand(redisClient *c) {
3713 addReplySds(c,
3305306f 3714 sdscatprintf(sdsempty(),":%lu\r\n",dictSize(c->db->dict)));
ed9b544e 3715}
3716
3717static void lastsaveCommand(redisClient *c) {
3718 addReplySds(c,
c937aa89 3719 sdscatprintf(sdsempty(),":%lu\r\n",server.lastsave));
ed9b544e 3720}
3721
3722static void typeCommand(redisClient *c) {
3305306f 3723 robj *o;
ed9b544e 3724 char *type;
3305306f 3725
3726 o = lookupKeyRead(c->db,c->argv[1]);
3727 if (o == NULL) {
c937aa89 3728 type = "+none";
ed9b544e 3729 } else {
ed9b544e 3730 switch(o->type) {
c937aa89 3731 case REDIS_STRING: type = "+string"; break;
3732 case REDIS_LIST: type = "+list"; break;
3733 case REDIS_SET: type = "+set"; break;
412a8bce 3734 case REDIS_ZSET: type = "+zset"; break;
ed9b544e 3735 default: type = "unknown"; break;
3736 }
3737 }
3738 addReplySds(c,sdsnew(type));
3739 addReply(c,shared.crlf);
3740}
3741
3742static void saveCommand(redisClient *c) {
9d65a1bb 3743 if (server.bgsavechildpid != -1) {
05557f6d 3744 addReplySds(c,sdsnew("-ERR background save in progress\r\n"));
3745 return;
3746 }
f78fd11b 3747 if (rdbSave(server.dbfilename) == REDIS_OK) {
ed9b544e 3748 addReply(c,shared.ok);
3749 } else {
3750 addReply(c,shared.err);
3751 }
3752}
3753
3754static void bgsaveCommand(redisClient *c) {
9d65a1bb 3755 if (server.bgsavechildpid != -1) {
ed9b544e 3756 addReplySds(c,sdsnew("-ERR background save already in progress\r\n"));
3757 return;
3758 }
f78fd11b 3759 if (rdbSaveBackground(server.dbfilename) == REDIS_OK) {
49b99ab4 3760 char *status = "+Background saving started\r\n";
3761 addReplySds(c,sdsnew(status));
ed9b544e 3762 } else {
3763 addReply(c,shared.err);
3764 }
3765}
3766
3767static void shutdownCommand(redisClient *c) {
3768 redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
a3b21203 3769 /* Kill the saving child if there is a background saving in progress.
3770 We want to avoid race conditions, for instance our saving child may
3771 overwrite the synchronous saving did by SHUTDOWN. */
9d65a1bb 3772 if (server.bgsavechildpid != -1) {
9f3c422c 3773 redisLog(REDIS_WARNING,"There is a live saving child. Killing it!");
3774 kill(server.bgsavechildpid,SIGKILL);
a3b21203 3775 rdbRemoveTempFile(server.bgsavechildpid);
9f3c422c 3776 }
ac945e2d 3777 if (server.appendonly) {
3778 /* Append only file: fsync() the AOF and exit */
3779 fsync(server.appendfd);
054e426d 3780 if (server.vm_enabled) unlink(server.vm_swap_file);
ac945e2d 3781 exit(0);
ed9b544e 3782 } else {
ac945e2d 3783 /* Snapshotting. Perform a SYNC SAVE and exit */
3784 if (rdbSave(server.dbfilename) == REDIS_OK) {
3785 if (server.daemonize)
3786 unlink(server.pidfile);
3787 redisLog(REDIS_WARNING,"%zu bytes used at exit",zmalloc_used_memory());
3788 redisLog(REDIS_WARNING,"Server exit now, bye bye...");
054e426d 3789 if (server.vm_enabled) unlink(server.vm_swap_file);
ac945e2d 3790 exit(0);
3791 } else {
3792 /* Ooops.. error saving! The best we can do is to continue operating.
3793 * Note that if there was a background saving process, in the next
3794 * cron() Redis will be notified that the background saving aborted,
3795 * handling special stuff like slaves pending for synchronization... */
3796 redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
3797 addReplySds(c,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
3798 }
ed9b544e 3799 }
3800}
3801
3802static void renameGenericCommand(redisClient *c, int nx) {
ed9b544e 3803 robj *o;
3804
3805 /* To use the same key as src and dst is probably an error */
3806 if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) {
c937aa89 3807 addReply(c,shared.sameobjecterr);
ed9b544e 3808 return;
3809 }
3810
3305306f 3811 o = lookupKeyWrite(c->db,c->argv[1]);
3812 if (o == NULL) {
c937aa89 3813 addReply(c,shared.nokeyerr);
ed9b544e 3814 return;
3815 }
ed9b544e 3816 incrRefCount(o);
3305306f 3817 deleteIfVolatile(c->db,c->argv[2]);
3818 if (dictAdd(c->db->dict,c->argv[2],o) == DICT_ERR) {
ed9b544e 3819 if (nx) {
3820 decrRefCount(o);
c937aa89 3821 addReply(c,shared.czero);
ed9b544e 3822 return;
3823 }
3305306f 3824 dictReplace(c->db->dict,c->argv[2],o);
ed9b544e 3825 } else {
3826 incrRefCount(c->argv[2]);
3827 }
3305306f 3828 deleteKey(c->db,c->argv[1]);
ed9b544e 3829 server.dirty++;
c937aa89 3830 addReply(c,nx ? shared.cone : shared.ok);
ed9b544e 3831}
3832
3833static void renameCommand(redisClient *c) {
3834 renameGenericCommand(c,0);
3835}
3836
3837static void renamenxCommand(redisClient *c) {
3838 renameGenericCommand(c,1);
3839}
3840
3841static void moveCommand(redisClient *c) {
3305306f 3842 robj *o;
3843 redisDb *src, *dst;
ed9b544e 3844 int srcid;
3845
3846 /* Obtain source and target DB pointers */
3305306f 3847 src = c->db;
3848 srcid = c->db->id;
ed9b544e 3849 if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) {
c937aa89 3850 addReply(c,shared.outofrangeerr);
ed9b544e 3851 return;
3852 }
3305306f 3853 dst = c->db;
3854 selectDb(c,srcid); /* Back to the source DB */
ed9b544e 3855
3856 /* If the user is moving using as target the same
3857 * DB as the source DB it is probably an error. */
3858 if (src == dst) {
c937aa89 3859 addReply(c,shared.sameobjecterr);
ed9b544e 3860 return;
3861 }
3862
3863 /* Check if the element exists and get a reference */
3305306f 3864 o = lookupKeyWrite(c->db,c->argv[1]);
3865 if (!o) {
c937aa89 3866 addReply(c,shared.czero);
ed9b544e 3867 return;
3868 }
3869
3870 /* Try to add the element to the target DB */
3305306f 3871 deleteIfVolatile(dst,c->argv[1]);
3872 if (dictAdd(dst->dict,c->argv[1],o) == DICT_ERR) {
c937aa89 3873 addReply(c,shared.czero);
ed9b544e 3874 return;
3875 }
3305306f 3876 incrRefCount(c->argv[1]);
ed9b544e 3877 incrRefCount(o);
3878
3879 /* OK! key moved, free the entry in the source DB */
3305306f 3880 deleteKey(src,c->argv[1]);
ed9b544e 3881 server.dirty++;
c937aa89 3882 addReply(c,shared.cone);
ed9b544e 3883}
3884
3885/* =================================== Lists ================================ */
3886static void pushGenericCommand(redisClient *c, int where) {
3887 robj *lobj;
ed9b544e 3888 list *list;
3305306f 3889
3890 lobj = lookupKeyWrite(c->db,c->argv[1]);
3891 if (lobj == NULL) {
95242ab5 3892 if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) {
3893 addReply(c,shared.ok);
3894 return;
3895 }
ed9b544e 3896 lobj = createListObject();
3897 list = lobj->ptr;
3898 if (where == REDIS_HEAD) {
6b47e12e 3899 listAddNodeHead(list,c->argv[2]);
ed9b544e 3900 } else {
6b47e12e 3901 listAddNodeTail(list,c->argv[2]);
ed9b544e 3902 }
3305306f 3903 dictAdd(c->db->dict,c->argv[1],lobj);
ed9b544e 3904 incrRefCount(c->argv[1]);
3905 incrRefCount(c->argv[2]);
3906 } else {
ed9b544e 3907 if (lobj->type != REDIS_LIST) {
3908 addReply(c,shared.wrongtypeerr);
3909 return;
3910 }
95242ab5 3911 if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) {
3912 addReply(c,shared.ok);
3913 return;
3914 }
ed9b544e 3915 list = lobj->ptr;
3916 if (where == REDIS_HEAD) {
6b47e12e 3917 listAddNodeHead(list,c->argv[2]);
ed9b544e 3918 } else {
6b47e12e 3919 listAddNodeTail(list,c->argv[2]);
ed9b544e 3920 }
3921 incrRefCount(c->argv[2]);
3922 }
3923 server.dirty++;
3924 addReply(c,shared.ok);
3925}
3926
3927static void lpushCommand(redisClient *c) {
3928 pushGenericCommand(c,REDIS_HEAD);
3929}
3930
3931static void rpushCommand(redisClient *c) {
3932 pushGenericCommand(c,REDIS_TAIL);
3933}
3934
3935static void llenCommand(redisClient *c) {
3305306f 3936 robj *o;
ed9b544e 3937 list *l;
3938
3305306f 3939 o = lookupKeyRead(c->db,c->argv[1]);
3940 if (o == NULL) {
c937aa89 3941 addReply(c,shared.czero);
ed9b544e 3942 return;
3943 } else {
ed9b544e 3944 if (o->type != REDIS_LIST) {
c937aa89 3945 addReply(c,shared.wrongtypeerr);
ed9b544e 3946 } else {
3947 l = o->ptr;
c937aa89 3948 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",listLength(l)));
ed9b544e 3949 }
3950 }
3951}
3952
3953static void lindexCommand(redisClient *c) {
3305306f 3954 robj *o;
ed9b544e 3955 int index = atoi(c->argv[2]->ptr);
3956
3305306f 3957 o = lookupKeyRead(c->db,c->argv[1]);
3958 if (o == NULL) {
c937aa89 3959 addReply(c,shared.nullbulk);
ed9b544e 3960 } else {
ed9b544e 3961 if (o->type != REDIS_LIST) {
c937aa89 3962 addReply(c,shared.wrongtypeerr);
ed9b544e 3963 } else {
3964 list *list = o->ptr;
3965 listNode *ln;
3966
3967 ln = listIndex(list, index);
3968 if (ln == NULL) {
c937aa89 3969 addReply(c,shared.nullbulk);
ed9b544e 3970 } else {
3971 robj *ele = listNodeValue(ln);
942a3961 3972 addReplyBulkLen(c,ele);
ed9b544e 3973 addReply(c,ele);
3974 addReply(c,shared.crlf);
3975 }
3976 }
3977 }
3978}
3979
3980static void lsetCommand(redisClient *c) {
3305306f 3981 robj *o;
ed9b544e 3982 int index = atoi(c->argv[2]->ptr);
3983
3305306f 3984 o = lookupKeyWrite(c->db,c->argv[1]);
3985 if (o == NULL) {
ed9b544e 3986 addReply(c,shared.nokeyerr);
3987 } else {
ed9b544e 3988 if (o->type != REDIS_LIST) {
3989 addReply(c,shared.wrongtypeerr);
3990 } else {
3991 list *list = o->ptr;
3992 listNode *ln;
3993
3994 ln = listIndex(list, index);
3995 if (ln == NULL) {
c937aa89 3996 addReply(c,shared.outofrangeerr);
ed9b544e 3997 } else {
3998 robj *ele = listNodeValue(ln);
3999
4000 decrRefCount(ele);
4001 listNodeValue(ln) = c->argv[3];
4002 incrRefCount(c->argv[3]);
4003 addReply(c,shared.ok);
4004 server.dirty++;
4005 }
4006 }
4007 }
4008}
4009
4010static void popGenericCommand(redisClient *c, int where) {
3305306f 4011 robj *o;
4012
4013 o = lookupKeyWrite(c->db,c->argv[1]);
4014 if (o == NULL) {
c937aa89 4015 addReply(c,shared.nullbulk);
ed9b544e 4016 } else {
ed9b544e 4017 if (o->type != REDIS_LIST) {
c937aa89 4018 addReply(c,shared.wrongtypeerr);
ed9b544e 4019 } else {
4020 list *list = o->ptr;
4021 listNode *ln;
4022
4023 if (where == REDIS_HEAD)
4024 ln = listFirst(list);
4025 else
4026 ln = listLast(list);
4027
4028 if (ln == NULL) {
c937aa89 4029 addReply(c,shared.nullbulk);
ed9b544e 4030 } else {
4031 robj *ele = listNodeValue(ln);
942a3961 4032 addReplyBulkLen(c,ele);
ed9b544e 4033 addReply(c,ele);
4034 addReply(c,shared.crlf);
4035 listDelNode(list,ln);
4036 server.dirty++;
4037 }
4038 }
4039 }
4040}
4041
4042static void lpopCommand(redisClient *c) {
4043 popGenericCommand(c,REDIS_HEAD);
4044}
4045
4046static void rpopCommand(redisClient *c) {
4047 popGenericCommand(c,REDIS_TAIL);
4048}
4049
4050static void lrangeCommand(redisClient *c) {
3305306f 4051 robj *o;
ed9b544e 4052 int start = atoi(c->argv[2]->ptr);
4053 int end = atoi(c->argv[3]->ptr);
3305306f 4054
4055 o = lookupKeyRead(c->db,c->argv[1]);
4056 if (o == NULL) {
c937aa89 4057 addReply(c,shared.nullmultibulk);
ed9b544e 4058 } else {
ed9b544e 4059 if (o->type != REDIS_LIST) {
c937aa89 4060 addReply(c,shared.wrongtypeerr);
ed9b544e 4061 } else {
4062 list *list = o->ptr;
4063 listNode *ln;
4064 int llen = listLength(list);
4065 int rangelen, j;
4066 robj *ele;
4067
4068 /* convert negative indexes */
4069 if (start < 0) start = llen+start;
4070 if (end < 0) end = llen+end;
4071 if (start < 0) start = 0;
4072 if (end < 0) end = 0;
4073
4074 /* indexes sanity checks */
4075 if (start > end || start >= llen) {
4076 /* Out of range start or start > end result in empty list */
c937aa89 4077 addReply(c,shared.emptymultibulk);
ed9b544e 4078 return;
4079 }
4080 if (end >= llen) end = llen-1;
4081 rangelen = (end-start)+1;
4082
4083 /* Return the result in form of a multi-bulk reply */
4084 ln = listIndex(list, start);
c937aa89 4085 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen));
ed9b544e 4086 for (j = 0; j < rangelen; j++) {
4087 ele = listNodeValue(ln);
942a3961 4088 addReplyBulkLen(c,ele);
ed9b544e 4089 addReply(c,ele);
4090 addReply(c,shared.crlf);
4091 ln = ln->next;
4092 }
4093 }
4094 }
4095}
4096
4097static void ltrimCommand(redisClient *c) {
3305306f 4098 robj *o;
ed9b544e 4099 int start = atoi(c->argv[2]->ptr);
4100 int end = atoi(c->argv[3]->ptr);
4101
3305306f 4102 o = lookupKeyWrite(c->db,c->argv[1]);
4103 if (o == NULL) {
ab9d4cb1 4104 addReply(c,shared.ok);
ed9b544e 4105 } else {
ed9b544e 4106 if (o->type != REDIS_LIST) {
4107 addReply(c,shared.wrongtypeerr);
4108 } else {
4109 list *list = o->ptr;
4110 listNode *ln;
4111 int llen = listLength(list);
4112 int j, ltrim, rtrim;
4113
4114 /* convert negative indexes */
4115 if (start < 0) start = llen+start;
4116 if (end < 0) end = llen+end;
4117 if (start < 0) start = 0;
4118 if (end < 0) end = 0;
4119
4120 /* indexes sanity checks */
4121 if (start > end || start >= llen) {
4122 /* Out of range start or start > end result in empty list */
4123 ltrim = llen;
4124 rtrim = 0;
4125 } else {
4126 if (end >= llen) end = llen-1;
4127 ltrim = start;
4128 rtrim = llen-end-1;
4129 }
4130
4131 /* Remove list elements to perform the trim */
4132 for (j = 0; j < ltrim; j++) {
4133 ln = listFirst(list);
4134 listDelNode(list,ln);
4135 }
4136 for (j = 0; j < rtrim; j++) {
4137 ln = listLast(list);
4138 listDelNode(list,ln);
4139 }
ed9b544e 4140 server.dirty++;
e59229a2 4141 addReply(c,shared.ok);
ed9b544e 4142 }
4143 }
4144}
4145
4146static void lremCommand(redisClient *c) {
3305306f 4147 robj *o;
ed9b544e 4148
3305306f 4149 o = lookupKeyWrite(c->db,c->argv[1]);
4150 if (o == NULL) {
33c08b39 4151 addReply(c,shared.czero);
ed9b544e 4152 } else {
ed9b544e 4153 if (o->type != REDIS_LIST) {
c937aa89 4154 addReply(c,shared.wrongtypeerr);
ed9b544e 4155 } else {
4156 list *list = o->ptr;
4157 listNode *ln, *next;
4158 int toremove = atoi(c->argv[2]->ptr);
4159 int removed = 0;
4160 int fromtail = 0;
4161
4162 if (toremove < 0) {
4163 toremove = -toremove;
4164 fromtail = 1;
4165 }
4166 ln = fromtail ? list->tail : list->head;
4167 while (ln) {
ed9b544e 4168 robj *ele = listNodeValue(ln);
a4d1ba9a 4169
4170 next = fromtail ? ln->prev : ln->next;
724a51b1 4171 if (compareStringObjects(ele,c->argv[3]) == 0) {
ed9b544e 4172 listDelNode(list,ln);
4173 server.dirty++;
4174 removed++;
4175 if (toremove && removed == toremove) break;
4176 }
4177 ln = next;
4178 }
c937aa89 4179 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",removed));
ed9b544e 4180 }
4181 }
4182}
4183
12f9d551 4184/* This is the semantic of this command:
0f5f7e9a 4185 * RPOPLPUSH srclist dstlist:
12f9d551 4186 * IF LLEN(srclist) > 0
4187 * element = RPOP srclist
4188 * LPUSH dstlist element
4189 * RETURN element
4190 * ELSE
4191 * RETURN nil
4192 * END
4193 * END
4194 *
4195 * The idea is to be able to get an element from a list in a reliable way
4196 * since the element is not just returned but pushed against another list
4197 * as well. This command was originally proposed by Ezra Zygmuntowicz.
4198 */
0f5f7e9a 4199static void rpoplpushcommand(redisClient *c) {
12f9d551 4200 robj *sobj;
4201
4202 sobj = lookupKeyWrite(c->db,c->argv[1]);
4203 if (sobj == NULL) {
4204 addReply(c,shared.nullbulk);
4205 } else {
4206 if (sobj->type != REDIS_LIST) {
4207 addReply(c,shared.wrongtypeerr);
4208 } else {
4209 list *srclist = sobj->ptr;
4210 listNode *ln = listLast(srclist);
4211
4212 if (ln == NULL) {
4213 addReply(c,shared.nullbulk);
4214 } else {
4215 robj *dobj = lookupKeyWrite(c->db,c->argv[2]);
4216 robj *ele = listNodeValue(ln);
4217 list *dstlist;
4218
e20fb74f 4219 if (dobj && dobj->type != REDIS_LIST) {
12f9d551 4220 addReply(c,shared.wrongtypeerr);
4221 return;
4222 }
e20fb74f 4223
4224 /* Add the element to the target list (unless it's directly
4225 * passed to some BLPOP-ing client */
4226 if (!handleClientsWaitingListPush(c,c->argv[2],ele)) {
4227 if (dobj == NULL) {
4228 /* Create the list if the key does not exist */
4229 dobj = createListObject();
4230 dictAdd(c->db->dict,c->argv[2],dobj);
4231 incrRefCount(c->argv[2]);
4232 }
4233 dstlist = dobj->ptr;
4234 listAddNodeHead(dstlist,ele);
4235 incrRefCount(ele);
4236 }
12f9d551 4237
4238 /* Send the element to the client as reply as well */
4239 addReplyBulkLen(c,ele);
4240 addReply(c,ele);
4241 addReply(c,shared.crlf);
4242
4243 /* Finally remove the element from the source list */
4244 listDelNode(srclist,ln);
4245 server.dirty++;
4246 }
4247 }
4248 }
4249}
4250
4251
ed9b544e 4252/* ==================================== Sets ================================ */
4253
4254static void saddCommand(redisClient *c) {
ed9b544e 4255 robj *set;
4256
3305306f 4257 set = lookupKeyWrite(c->db,c->argv[1]);
4258 if (set == NULL) {
ed9b544e 4259 set = createSetObject();
3305306f 4260 dictAdd(c->db->dict,c->argv[1],set);
ed9b544e 4261 incrRefCount(c->argv[1]);
4262 } else {
ed9b544e 4263 if (set->type != REDIS_SET) {
c937aa89 4264 addReply(c,shared.wrongtypeerr);
ed9b544e 4265 return;
4266 }
4267 }
4268 if (dictAdd(set->ptr,c->argv[2],NULL) == DICT_OK) {
4269 incrRefCount(c->argv[2]);
4270 server.dirty++;
c937aa89 4271 addReply(c,shared.cone);
ed9b544e 4272 } else {
c937aa89 4273 addReply(c,shared.czero);
ed9b544e 4274 }
4275}
4276
4277static void sremCommand(redisClient *c) {
3305306f 4278 robj *set;
ed9b544e 4279
3305306f 4280 set = lookupKeyWrite(c->db,c->argv[1]);
4281 if (set == NULL) {
c937aa89 4282 addReply(c,shared.czero);
ed9b544e 4283 } else {
ed9b544e 4284 if (set->type != REDIS_SET) {
c937aa89 4285 addReply(c,shared.wrongtypeerr);
ed9b544e 4286 return;
4287 }
4288 if (dictDelete(set->ptr,c->argv[2]) == DICT_OK) {
4289 server.dirty++;
12fea928 4290 if (htNeedsResize(set->ptr)) dictResize(set->ptr);
c937aa89 4291 addReply(c,shared.cone);
ed9b544e 4292 } else {
c937aa89 4293 addReply(c,shared.czero);
ed9b544e 4294 }
4295 }
4296}
4297
a4460ef4 4298static void smoveCommand(redisClient *c) {
4299 robj *srcset, *dstset;
4300
4301 srcset = lookupKeyWrite(c->db,c->argv[1]);
4302 dstset = lookupKeyWrite(c->db,c->argv[2]);
4303
4304 /* If the source key does not exist return 0, if it's of the wrong type
4305 * raise an error */
4306 if (srcset == NULL || srcset->type != REDIS_SET) {
4307 addReply(c, srcset ? shared.wrongtypeerr : shared.czero);
4308 return;
4309 }
4310 /* Error if the destination key is not a set as well */
4311 if (dstset && dstset->type != REDIS_SET) {
4312 addReply(c,shared.wrongtypeerr);
4313 return;
4314 }
4315 /* Remove the element from the source set */
4316 if (dictDelete(srcset->ptr,c->argv[3]) == DICT_ERR) {
4317 /* Key not found in the src set! return zero */
4318 addReply(c,shared.czero);
4319 return;
4320 }
4321 server.dirty++;
4322 /* Add the element to the destination set */
4323 if (!dstset) {
4324 dstset = createSetObject();
4325 dictAdd(c->db->dict,c->argv[2],dstset);
4326 incrRefCount(c->argv[2]);
4327 }
4328 if (dictAdd(dstset->ptr,c->argv[3],NULL) == DICT_OK)
4329 incrRefCount(c->argv[3]);
4330 addReply(c,shared.cone);
4331}
4332
ed9b544e 4333static void sismemberCommand(redisClient *c) {
3305306f 4334 robj *set;
ed9b544e 4335
3305306f 4336 set = lookupKeyRead(c->db,c->argv[1]);
4337 if (set == NULL) {
c937aa89 4338 addReply(c,shared.czero);
ed9b544e 4339 } else {
ed9b544e 4340 if (set->type != REDIS_SET) {
c937aa89 4341 addReply(c,shared.wrongtypeerr);
ed9b544e 4342 return;
4343 }
4344 if (dictFind(set->ptr,c->argv[2]))
c937aa89 4345 addReply(c,shared.cone);
ed9b544e 4346 else
c937aa89 4347 addReply(c,shared.czero);
ed9b544e 4348 }
4349}
4350
4351static void scardCommand(redisClient *c) {
3305306f 4352 robj *o;
ed9b544e 4353 dict *s;
4354
3305306f 4355 o = lookupKeyRead(c->db,c->argv[1]);
4356 if (o == NULL) {
c937aa89 4357 addReply(c,shared.czero);
ed9b544e 4358 return;
4359 } else {
ed9b544e 4360 if (o->type != REDIS_SET) {
c937aa89 4361 addReply(c,shared.wrongtypeerr);
ed9b544e 4362 } else {
4363 s = o->ptr;
682ac724 4364 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",
3305306f 4365 dictSize(s)));
ed9b544e 4366 }
4367 }
4368}
4369
12fea928 4370static void spopCommand(redisClient *c) {
4371 robj *set;
4372 dictEntry *de;
4373
4374 set = lookupKeyWrite(c->db,c->argv[1]);
4375 if (set == NULL) {
4376 addReply(c,shared.nullbulk);
4377 } else {
4378 if (set->type != REDIS_SET) {
4379 addReply(c,shared.wrongtypeerr);
4380 return;
4381 }
4382 de = dictGetRandomKey(set->ptr);
4383 if (de == NULL) {
4384 addReply(c,shared.nullbulk);
4385 } else {
4386 robj *ele = dictGetEntryKey(de);
4387
942a3961 4388 addReplyBulkLen(c,ele);
12fea928 4389 addReply(c,ele);
4390 addReply(c,shared.crlf);
4391 dictDelete(set->ptr,ele);
4392 if (htNeedsResize(set->ptr)) dictResize(set->ptr);
4393 server.dirty++;
4394 }
4395 }
4396}
4397
2abb95a9 4398static void srandmemberCommand(redisClient *c) {
4399 robj *set;
4400 dictEntry *de;
4401
4402 set = lookupKeyRead(c->db,c->argv[1]);
4403 if (set == NULL) {
4404 addReply(c,shared.nullbulk);
4405 } else {
4406 if (set->type != REDIS_SET) {
4407 addReply(c,shared.wrongtypeerr);
4408 return;
4409 }
4410 de = dictGetRandomKey(set->ptr);
4411 if (de == NULL) {
4412 addReply(c,shared.nullbulk);
4413 } else {
4414 robj *ele = dictGetEntryKey(de);
4415
4416 addReplyBulkLen(c,ele);
4417 addReply(c,ele);
4418 addReply(c,shared.crlf);
4419 }
4420 }
4421}
4422
ed9b544e 4423static int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
4424 dict **d1 = (void*) s1, **d2 = (void*) s2;
4425
3305306f 4426 return dictSize(*d1)-dictSize(*d2);
ed9b544e 4427}
4428
682ac724 4429static void sinterGenericCommand(redisClient *c, robj **setskeys, unsigned long setsnum, robj *dstkey) {
ed9b544e 4430 dict **dv = zmalloc(sizeof(dict*)*setsnum);
4431 dictIterator *di;
4432 dictEntry *de;
4433 robj *lenobj = NULL, *dstset = NULL;
682ac724 4434 unsigned long j, cardinality = 0;
ed9b544e 4435
ed9b544e 4436 for (j = 0; j < setsnum; j++) {
4437 robj *setobj;
3305306f 4438
4439 setobj = dstkey ?
4440 lookupKeyWrite(c->db,setskeys[j]) :
4441 lookupKeyRead(c->db,setskeys[j]);
4442 if (!setobj) {
ed9b544e 4443 zfree(dv);
5faa6025 4444 if (dstkey) {
fdcaae84 4445 if (deleteKey(c->db,dstkey))
4446 server.dirty++;
0d36ded0 4447 addReply(c,shared.czero);
5faa6025 4448 } else {
4449 addReply(c,shared.nullmultibulk);
4450 }
ed9b544e 4451 return;
4452 }
ed9b544e 4453 if (setobj->type != REDIS_SET) {
4454 zfree(dv);
c937aa89 4455 addReply(c,shared.wrongtypeerr);
ed9b544e 4456 return;
4457 }
4458 dv[j] = setobj->ptr;
4459 }
4460 /* Sort sets from the smallest to largest, this will improve our
4461 * algorithm's performace */
4462 qsort(dv,setsnum,sizeof(dict*),qsortCompareSetsByCardinality);
4463
4464 /* The first thing we should output is the total number of elements...
4465 * since this is a multi-bulk write, but at this stage we don't know
4466 * the intersection set size, so we use a trick, append an empty object
4467 * to the output list and save the pointer to later modify it with the
4468 * right length */
4469 if (!dstkey) {
4470 lenobj = createObject(REDIS_STRING,NULL);
4471 addReply(c,lenobj);
4472 decrRefCount(lenobj);
4473 } else {
4474 /* If we have a target key where to store the resulting set
4475 * create this key with an empty set inside */
4476 dstset = createSetObject();
ed9b544e 4477 }
4478
4479 /* Iterate all the elements of the first (smallest) set, and test
4480 * the element against all the other sets, if at least one set does
4481 * not include the element it is discarded */
4482 di = dictGetIterator(dv[0]);
ed9b544e 4483
4484 while((de = dictNext(di)) != NULL) {
4485 robj *ele;
4486
4487 for (j = 1; j < setsnum; j++)
4488 if (dictFind(dv[j],dictGetEntryKey(de)) == NULL) break;
4489 if (j != setsnum)
4490 continue; /* at least one set does not contain the member */
4491 ele = dictGetEntryKey(de);
4492 if (!dstkey) {
942a3961 4493 addReplyBulkLen(c,ele);
ed9b544e 4494 addReply(c,ele);
4495 addReply(c,shared.crlf);
4496 cardinality++;
4497 } else {
4498 dictAdd(dstset->ptr,ele,NULL);
4499 incrRefCount(ele);
4500 }
4501 }
4502 dictReleaseIterator(di);
4503
83cdfe18
AG
4504 if (dstkey) {
4505 /* Store the resulting set into the target */
4506 deleteKey(c->db,dstkey);
4507 dictAdd(c->db->dict,dstkey,dstset);
4508 incrRefCount(dstkey);
4509 }
4510
40d224a9 4511 if (!dstkey) {
682ac724 4512 lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",cardinality);
40d224a9 4513 } else {
682ac724 4514 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",
03fd01c7 4515 dictSize((dict*)dstset->ptr)));
40d224a9 4516 server.dirty++;
4517 }
ed9b544e 4518 zfree(dv);
4519}
4520
4521static void sinterCommand(redisClient *c) {
4522 sinterGenericCommand(c,c->argv+1,c->argc-1,NULL);
4523}
4524
4525static void sinterstoreCommand(redisClient *c) {
4526 sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
4527}
4528
f4f56e1d 4529#define REDIS_OP_UNION 0
4530#define REDIS_OP_DIFF 1
4531
4532static void sunionDiffGenericCommand(redisClient *c, robj **setskeys, int setsnum, robj *dstkey, int op) {
40d224a9 4533 dict **dv = zmalloc(sizeof(dict*)*setsnum);
4534 dictIterator *di;
4535 dictEntry *de;
f4f56e1d 4536 robj *dstset = NULL;
40d224a9 4537 int j, cardinality = 0;
4538
40d224a9 4539 for (j = 0; j < setsnum; j++) {
4540 robj *setobj;
4541
4542 setobj = dstkey ?
4543 lookupKeyWrite(c->db,setskeys[j]) :
4544 lookupKeyRead(c->db,setskeys[j]);
4545 if (!setobj) {
4546 dv[j] = NULL;
4547 continue;
4548 }
4549 if (setobj->type != REDIS_SET) {
4550 zfree(dv);
4551 addReply(c,shared.wrongtypeerr);
4552 return;
4553 }
4554 dv[j] = setobj->ptr;
4555 }
4556
4557 /* We need a temp set object to store our union. If the dstkey
4558 * is not NULL (that is, we are inside an SUNIONSTORE operation) then
4559 * this set object will be the resulting object to set into the target key*/
4560 dstset = createSetObject();
4561
40d224a9 4562 /* Iterate all the elements of all the sets, add every element a single
4563 * time to the result set */
4564 for (j = 0; j < setsnum; j++) {
51829ed3 4565 if (op == REDIS_OP_DIFF && j == 0 && !dv[j]) break; /* result set is empty */
40d224a9 4566 if (!dv[j]) continue; /* non existing keys are like empty sets */
4567
4568 di = dictGetIterator(dv[j]);
40d224a9 4569
4570 while((de = dictNext(di)) != NULL) {
4571 robj *ele;
4572
4573 /* dictAdd will not add the same element multiple times */
4574 ele = dictGetEntryKey(de);
f4f56e1d 4575 if (op == REDIS_OP_UNION || j == 0) {
4576 if (dictAdd(dstset->ptr,ele,NULL) == DICT_OK) {
4577 incrRefCount(ele);
40d224a9 4578 cardinality++;
4579 }
f4f56e1d 4580 } else if (op == REDIS_OP_DIFF) {
4581 if (dictDelete(dstset->ptr,ele) == DICT_OK) {
4582 cardinality--;
4583 }
40d224a9 4584 }
4585 }
4586 dictReleaseIterator(di);
51829ed3
AG
4587
4588 if (op == REDIS_OP_DIFF && cardinality == 0) break; /* result set is empty */
40d224a9 4589 }
4590
f4f56e1d 4591 /* Output the content of the resulting set, if not in STORE mode */
4592 if (!dstkey) {
4593 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",cardinality));
4594 di = dictGetIterator(dstset->ptr);
f4f56e1d 4595 while((de = dictNext(di)) != NULL) {
4596 robj *ele;
4597
4598 ele = dictGetEntryKey(de);
942a3961 4599 addReplyBulkLen(c,ele);
f4f56e1d 4600 addReply(c,ele);
4601 addReply(c,shared.crlf);
4602 }
4603 dictReleaseIterator(di);
83cdfe18
AG
4604 } else {
4605 /* If we have a target key where to store the resulting set
4606 * create this key with the result set inside */
4607 deleteKey(c->db,dstkey);
4608 dictAdd(c->db->dict,dstkey,dstset);
4609 incrRefCount(dstkey);
f4f56e1d 4610 }
4611
4612 /* Cleanup */
40d224a9 4613 if (!dstkey) {
40d224a9 4614 decrRefCount(dstset);
4615 } else {
682ac724 4616 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",
03fd01c7 4617 dictSize((dict*)dstset->ptr)));
40d224a9 4618 server.dirty++;
4619 }
4620 zfree(dv);
4621}
4622
4623static void sunionCommand(redisClient *c) {
f4f56e1d 4624 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_UNION);
40d224a9 4625}
4626
4627static void sunionstoreCommand(redisClient *c) {
f4f56e1d 4628 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_UNION);
4629}
4630
4631static void sdiffCommand(redisClient *c) {
4632 sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_DIFF);
4633}
4634
4635static void sdiffstoreCommand(redisClient *c) {
4636 sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_DIFF);
40d224a9 4637}
4638
6b47e12e 4639/* ==================================== ZSets =============================== */
4640
4641/* ZSETs are ordered sets using two data structures to hold the same elements
4642 * in order to get O(log(N)) INSERT and REMOVE operations into a sorted
4643 * data structure.
4644 *
4645 * The elements are added to an hash table mapping Redis objects to scores.
4646 * At the same time the elements are added to a skip list mapping scores
4647 * to Redis objects (so objects are sorted by scores in this "view"). */
4648
4649/* This skiplist implementation is almost a C translation of the original
4650 * algorithm described by William Pugh in "Skip Lists: A Probabilistic
4651 * Alternative to Balanced Trees", modified in three ways:
4652 * a) this implementation allows for repeated values.
4653 * b) the comparison is not just by key (our 'score') but by satellite data.
4654 * c) there is a back pointer, so it's a doubly linked list with the back
4655 * pointers being only at "level 1". This allows to traverse the list
4656 * from tail to head, useful for ZREVRANGE. */
4657
4658static zskiplistNode *zslCreateNode(int level, double score, robj *obj) {
4659 zskiplistNode *zn = zmalloc(sizeof(*zn));
4660
4661 zn->forward = zmalloc(sizeof(zskiplistNode*) * level);
4662 zn->score = score;
4663 zn->obj = obj;
4664 return zn;
4665}
4666
4667static zskiplist *zslCreate(void) {
4668 int j;
4669 zskiplist *zsl;
4670
4671 zsl = zmalloc(sizeof(*zsl));
4672 zsl->level = 1;
cc812361 4673 zsl->length = 0;
6b47e12e 4674 zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
4675 for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++)
4676 zsl->header->forward[j] = NULL;
e3870fab 4677 zsl->header->backward = NULL;
4678 zsl->tail = NULL;
6b47e12e 4679 return zsl;
4680}
4681
fd8ccf44 4682static void zslFreeNode(zskiplistNode *node) {
4683 decrRefCount(node->obj);
ad807e6f 4684 zfree(node->forward);
fd8ccf44 4685 zfree(node);
4686}
4687
4688static void zslFree(zskiplist *zsl) {
ad807e6f 4689 zskiplistNode *node = zsl->header->forward[0], *next;
fd8ccf44 4690
ad807e6f 4691 zfree(zsl->header->forward);
4692 zfree(zsl->header);
fd8ccf44 4693 while(node) {
599379dd 4694 next = node->forward[0];
fd8ccf44 4695 zslFreeNode(node);
4696 node = next;
4697 }
ad807e6f 4698 zfree(zsl);
fd8ccf44 4699}
4700
6b47e12e 4701static int zslRandomLevel(void) {
4702 int level = 1;
4703 while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
4704 level += 1;
4705 return level;
4706}
4707
4708static void zslInsert(zskiplist *zsl, double score, robj *obj) {
4709 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
4710 int i, level;
4711
4712 x = zsl->header;
4713 for (i = zsl->level-1; i >= 0; i--) {
9d60e6e4 4714 while (x->forward[i] &&
4715 (x->forward[i]->score < score ||
4716 (x->forward[i]->score == score &&
4717 compareStringObjects(x->forward[i]->obj,obj) < 0)))
6b47e12e 4718 x = x->forward[i];
4719 update[i] = x;
4720 }
6b47e12e 4721 /* we assume the key is not already inside, since we allow duplicated
4722 * scores, and the re-insertion of score and redis object should never
4723 * happpen since the caller of zslInsert() should test in the hash table
4724 * if the element is already inside or not. */
4725 level = zslRandomLevel();
4726 if (level > zsl->level) {
4727 for (i = zsl->level; i < level; i++)
4728 update[i] = zsl->header;
4729 zsl->level = level;
4730 }
4731 x = zslCreateNode(level,score,obj);
4732 for (i = 0; i < level; i++) {
4733 x->forward[i] = update[i]->forward[i];
4734 update[i]->forward[i] = x;
4735 }
bb975144 4736 x->backward = (update[0] == zsl->header) ? NULL : update[0];
e3870fab 4737 if (x->forward[0])
4738 x->forward[0]->backward = x;
4739 else
4740 zsl->tail = x;
cc812361 4741 zsl->length++;
6b47e12e 4742}
4743
50c55df5 4744/* Delete an element with matching score/object from the skiplist. */
fd8ccf44 4745static int zslDelete(zskiplist *zsl, double score, robj *obj) {
e197b441 4746 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
4747 int i;
4748
4749 x = zsl->header;
4750 for (i = zsl->level-1; i >= 0; i--) {
9d60e6e4 4751 while (x->forward[i] &&
4752 (x->forward[i]->score < score ||
4753 (x->forward[i]->score == score &&
4754 compareStringObjects(x->forward[i]->obj,obj) < 0)))
e197b441 4755 x = x->forward[i];
4756 update[i] = x;
4757 }
4758 /* We may have multiple elements with the same score, what we need
4759 * is to find the element with both the right score and object. */
4760 x = x->forward[0];
50c55df5 4761 if (x && score == x->score && compareStringObjects(x->obj,obj) == 0) {
9d60e6e4 4762 for (i = 0; i < zsl->level; i++) {
4763 if (update[i]->forward[i] != x) break;
4764 update[i]->forward[i] = x->forward[i];
4765 }
4766 if (x->forward[0]) {
4767 x->forward[0]->backward = (x->backward == zsl->header) ?
4768 NULL : x->backward;
e197b441 4769 } else {
9d60e6e4 4770 zsl->tail = x->backward;
e197b441 4771 }
9d60e6e4 4772 zslFreeNode(x);
4773 while(zsl->level > 1 && zsl->header->forward[zsl->level-1] == NULL)
4774 zsl->level--;
4775 zsl->length--;
4776 return 1;
4777 } else {
4778 return 0; /* not found */
e197b441 4779 }
4780 return 0; /* not found */
fd8ccf44 4781}
4782
1807985b 4783/* Delete all the elements with score between min and max from the skiplist.
4784 * Min and mx are inclusive, so a score >= min || score <= max is deleted.
4785 * Note that this function takes the reference to the hash table view of the
4786 * sorted set, in order to remove the elements from the hash table too. */
4787static unsigned long zslDeleteRange(zskiplist *zsl, double min, double max, dict *dict) {
4788 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
4789 unsigned long removed = 0;
4790 int i;
4791
4792 x = zsl->header;
4793 for (i = zsl->level-1; i >= 0; i--) {
4794 while (x->forward[i] && x->forward[i]->score < min)
4795 x = x->forward[i];
4796 update[i] = x;
4797 }
4798 /* We may have multiple elements with the same score, what we need
4799 * is to find the element with both the right score and object. */
4800 x = x->forward[0];
4801 while (x && x->score <= max) {
4802 zskiplistNode *next;
4803
4804 for (i = 0; i < zsl->level; i++) {
4805 if (update[i]->forward[i] != x) break;
4806 update[i]->forward[i] = x->forward[i];
4807 }
4808 if (x->forward[0]) {
4809 x->forward[0]->backward = (x->backward == zsl->header) ?
4810 NULL : x->backward;
4811 } else {
4812 zsl->tail = x->backward;
4813 }
4814 next = x->forward[0];
4815 dictDelete(dict,x->obj);
4816 zslFreeNode(x);
4817 while(zsl->level > 1 && zsl->header->forward[zsl->level-1] == NULL)
4818 zsl->level--;
4819 zsl->length--;
4820 removed++;
4821 x = next;
4822 }
4823 return removed; /* not found */
4824}
4825
50c55df5 4826/* Find the first node having a score equal or greater than the specified one.
4827 * Returns NULL if there is no match. */
4828static zskiplistNode *zslFirstWithScore(zskiplist *zsl, double score) {
4829 zskiplistNode *x;
4830 int i;
4831
4832 x = zsl->header;
4833 for (i = zsl->level-1; i >= 0; i--) {
4834 while (x->forward[i] && x->forward[i]->score < score)
4835 x = x->forward[i];
4836 }
4837 /* We may have multiple elements with the same score, what we need
4838 * is to find the element with both the right score and object. */
4839 return x->forward[0];
4840}
4841
fd8ccf44 4842/* The actual Z-commands implementations */
4843
7db723ad 4844/* This generic command implements both ZADD and ZINCRBY.
e2665397 4845 * scoreval is the score if the operation is a ZADD (doincrement == 0) or
7db723ad 4846 * the increment if the operation is a ZINCRBY (doincrement == 1). */
e2665397 4847static void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, int doincrement) {
fd8ccf44 4848 robj *zsetobj;
4849 zset *zs;
4850 double *score;
4851
e2665397 4852 zsetobj = lookupKeyWrite(c->db,key);
fd8ccf44 4853 if (zsetobj == NULL) {
4854 zsetobj = createZsetObject();
e2665397 4855 dictAdd(c->db->dict,key,zsetobj);
4856 incrRefCount(key);
fd8ccf44 4857 } else {
4858 if (zsetobj->type != REDIS_ZSET) {
4859 addReply(c,shared.wrongtypeerr);
4860 return;
4861 }
4862 }
fd8ccf44 4863 zs = zsetobj->ptr;
e2665397 4864
7db723ad 4865 /* Ok now since we implement both ZADD and ZINCRBY here the code
e2665397 4866 * needs to handle the two different conditions. It's all about setting
4867 * '*score', that is, the new score to set, to the right value. */
4868 score = zmalloc(sizeof(double));
4869 if (doincrement) {
4870 dictEntry *de;
4871
4872 /* Read the old score. If the element was not present starts from 0 */
4873 de = dictFind(zs->dict,ele);
4874 if (de) {
4875 double *oldscore = dictGetEntryVal(de);
4876 *score = *oldscore + scoreval;
4877 } else {
4878 *score = scoreval;
4879 }
4880 } else {
4881 *score = scoreval;
4882 }
4883
4884 /* What follows is a simple remove and re-insert operation that is common
7db723ad 4885 * to both ZADD and ZINCRBY... */
e2665397 4886 if (dictAdd(zs->dict,ele,score) == DICT_OK) {
fd8ccf44 4887 /* case 1: New element */
e2665397 4888 incrRefCount(ele); /* added to hash */
4889 zslInsert(zs->zsl,*score,ele);
4890 incrRefCount(ele); /* added to skiplist */
fd8ccf44 4891 server.dirty++;
e2665397 4892 if (doincrement)
e2665397 4893 addReplyDouble(c,*score);
91d71bfc 4894 else
4895 addReply(c,shared.cone);
fd8ccf44 4896 } else {
4897 dictEntry *de;
4898 double *oldscore;
4899
4900 /* case 2: Score update operation */
e2665397 4901 de = dictFind(zs->dict,ele);
dfc5e96c 4902 redisAssert(de != NULL);
fd8ccf44 4903 oldscore = dictGetEntryVal(de);
4904 if (*score != *oldscore) {
4905 int deleted;
4906
e2665397 4907 /* Remove and insert the element in the skip list with new score */
4908 deleted = zslDelete(zs->zsl,*oldscore,ele);
dfc5e96c 4909 redisAssert(deleted != 0);
e2665397 4910 zslInsert(zs->zsl,*score,ele);
4911 incrRefCount(ele);
4912 /* Update the score in the hash table */
4913 dictReplace(zs->dict,ele,score);
fd8ccf44 4914 server.dirty++;
2161a965 4915 } else {
4916 zfree(score);
fd8ccf44 4917 }
e2665397 4918 if (doincrement)
4919 addReplyDouble(c,*score);
4920 else
4921 addReply(c,shared.czero);
fd8ccf44 4922 }
4923}
4924
e2665397 4925static void zaddCommand(redisClient *c) {
4926 double scoreval;
4927
4928 scoreval = strtod(c->argv[2]->ptr,NULL);
4929 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,0);
4930}
4931
7db723ad 4932static void zincrbyCommand(redisClient *c) {
e2665397 4933 double scoreval;
4934
4935 scoreval = strtod(c->argv[2]->ptr,NULL);
4936 zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1);
4937}
4938
1b7106e7 4939static void zremCommand(redisClient *c) {
4940 robj *zsetobj;
4941 zset *zs;
4942
4943 zsetobj = lookupKeyWrite(c->db,c->argv[1]);
4944 if (zsetobj == NULL) {
4945 addReply(c,shared.czero);
4946 } else {
4947 dictEntry *de;
4948 double *oldscore;
4949 int deleted;
4950
4951 if (zsetobj->type != REDIS_ZSET) {
4952 addReply(c,shared.wrongtypeerr);
4953 return;
4954 }
4955 zs = zsetobj->ptr;
4956 de = dictFind(zs->dict,c->argv[2]);
4957 if (de == NULL) {
4958 addReply(c,shared.czero);
4959 return;
4960 }
4961 /* Delete from the skiplist */
4962 oldscore = dictGetEntryVal(de);
4963 deleted = zslDelete(zs->zsl,*oldscore,c->argv[2]);
dfc5e96c 4964 redisAssert(deleted != 0);
1b7106e7 4965
4966 /* Delete from the hash table */
4967 dictDelete(zs->dict,c->argv[2]);
4968 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
4969 server.dirty++;
4970 addReply(c,shared.cone);
4971 }
4972}
4973
1807985b 4974static void zremrangebyscoreCommand(redisClient *c) {
4975 double min = strtod(c->argv[2]->ptr,NULL);
4976 double max = strtod(c->argv[3]->ptr,NULL);
4977 robj *zsetobj;
4978 zset *zs;
4979
4980 zsetobj = lookupKeyWrite(c->db,c->argv[1]);
4981 if (zsetobj == NULL) {
4982 addReply(c,shared.czero);
4983 } else {
4984 long deleted;
4985
4986 if (zsetobj->type != REDIS_ZSET) {
4987 addReply(c,shared.wrongtypeerr);
4988 return;
4989 }
4990 zs = zsetobj->ptr;
4991 deleted = zslDeleteRange(zs->zsl,min,max,zs->dict);
4992 if (htNeedsResize(zs->dict)) dictResize(zs->dict);
4993 server.dirty += deleted;
4994 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",deleted));
4995 }
4996}
4997
e3870fab 4998static void zrangeGenericCommand(redisClient *c, int reverse) {
cc812361 4999 robj *o;
5000 int start = atoi(c->argv[2]->ptr);
5001 int end = atoi(c->argv[3]->ptr);
752da584 5002 int withscores = 0;
5003
5004 if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) {
5005 withscores = 1;
5006 } else if (c->argc >= 5) {
5007 addReply(c,shared.syntaxerr);
5008 return;
5009 }
cc812361 5010
5011 o = lookupKeyRead(c->db,c->argv[1]);
5012 if (o == NULL) {
5013 addReply(c,shared.nullmultibulk);
5014 } else {
5015 if (o->type != REDIS_ZSET) {
5016 addReply(c,shared.wrongtypeerr);
5017 } else {
5018 zset *zsetobj = o->ptr;
5019 zskiplist *zsl = zsetobj->zsl;
5020 zskiplistNode *ln;
5021
5022 int llen = zsl->length;
5023 int rangelen, j;
5024 robj *ele;
5025
5026 /* convert negative indexes */
5027 if (start < 0) start = llen+start;
5028 if (end < 0) end = llen+end;
5029 if (start < 0) start = 0;
5030 if (end < 0) end = 0;
5031
5032 /* indexes sanity checks */
5033 if (start > end || start >= llen) {
5034 /* Out of range start or start > end result in empty list */
5035 addReply(c,shared.emptymultibulk);
5036 return;
5037 }
5038 if (end >= llen) end = llen-1;
5039 rangelen = (end-start)+1;
5040
5041 /* Return the result in form of a multi-bulk reply */
e3870fab 5042 if (reverse) {
5043 ln = zsl->tail;
5044 while (start--)
5045 ln = ln->backward;
5046 } else {
5047 ln = zsl->header->forward[0];
5048 while (start--)
5049 ln = ln->forward[0];
5050 }
cc812361 5051
752da584 5052 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",
5053 withscores ? (rangelen*2) : rangelen));
cc812361 5054 for (j = 0; j < rangelen; j++) {
0aad7a19 5055 ele = ln->obj;
cc812361 5056 addReplyBulkLen(c,ele);
5057 addReply(c,ele);
5058 addReply(c,shared.crlf);
752da584 5059 if (withscores)
5060 addReplyDouble(c,ln->score);
e3870fab 5061 ln = reverse ? ln->backward : ln->forward[0];
cc812361 5062 }
5063 }
5064 }
5065}
5066
e3870fab 5067static void zrangeCommand(redisClient *c) {
5068 zrangeGenericCommand(c,0);
5069}
5070
5071static void zrevrangeCommand(redisClient *c) {
5072 zrangeGenericCommand(c,1);
5073}
5074
50c55df5 5075static void zrangebyscoreCommand(redisClient *c) {
5076 robj *o;
5077 double min = strtod(c->argv[2]->ptr,NULL);
5078 double max = strtod(c->argv[3]->ptr,NULL);
80181f78 5079 int offset = 0, limit = -1;
5080
5081 if (c->argc != 4 && c->argc != 7) {
454d4e43 5082 addReplySds(c,
5083 sdsnew("-ERR wrong number of arguments for ZRANGEBYSCORE\r\n"));
80181f78 5084 return;
5085 } else if (c->argc == 7 && strcasecmp(c->argv[4]->ptr,"limit")) {
5086 addReply(c,shared.syntaxerr);
5087 return;
5088 } else if (c->argc == 7) {
5089 offset = atoi(c->argv[5]->ptr);
5090 limit = atoi(c->argv[6]->ptr);
0b13687c 5091 if (offset < 0) offset = 0;
80181f78 5092 }
50c55df5 5093
5094 o = lookupKeyRead(c->db,c->argv[1]);
5095 if (o == NULL) {
5096 addReply(c,shared.nullmultibulk);
5097 } else {
5098 if (o->type != REDIS_ZSET) {
5099 addReply(c,shared.wrongtypeerr);
5100 } else {
5101 zset *zsetobj = o->ptr;
5102 zskiplist *zsl = zsetobj->zsl;
5103 zskiplistNode *ln;
5104 robj *ele, *lenobj;
5105 unsigned int rangelen = 0;
5106
5107 /* Get the first node with the score >= min */
5108 ln = zslFirstWithScore(zsl,min);
5109 if (ln == NULL) {
5110 /* No element matching the speciifed interval */
5111 addReply(c,shared.emptymultibulk);
5112 return;
5113 }
5114
5115 /* We don't know in advance how many matching elements there
5116 * are in the list, so we push this object that will represent
5117 * the multi-bulk length in the output buffer, and will "fix"
5118 * it later */
5119 lenobj = createObject(REDIS_STRING,NULL);
5120 addReply(c,lenobj);
c74e7c77 5121 decrRefCount(lenobj);
50c55df5 5122
dbbc7285 5123 while(ln && ln->score <= max) {
80181f78 5124 if (offset) {
5125 offset--;
5126 ln = ln->forward[0];
5127 continue;
5128 }
5129 if (limit == 0) break;
50c55df5 5130 ele = ln->obj;
5131 addReplyBulkLen(c,ele);
5132 addReply(c,ele);
5133 addReply(c,shared.crlf);
5134 ln = ln->forward[0];
5135 rangelen++;
80181f78 5136 if (limit > 0) limit--;
50c55df5 5137 }
5138 lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",rangelen);
5139 }
5140 }
5141}
5142
3c41331e 5143static void zcardCommand(redisClient *c) {
e197b441 5144 robj *o;
5145 zset *zs;
5146
5147 o = lookupKeyRead(c->db,c->argv[1]);
5148 if (o == NULL) {
5149 addReply(c,shared.czero);
5150 return;
5151 } else {
5152 if (o->type != REDIS_ZSET) {
5153 addReply(c,shared.wrongtypeerr);
5154 } else {
5155 zs = o->ptr;
682ac724 5156 addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",zs->zsl->length));
e197b441 5157 }
5158 }
5159}
5160
6e333bbe 5161static void zscoreCommand(redisClient *c) {
5162 robj *o;
5163 zset *zs;
5164
5165 o = lookupKeyRead(c->db,c->argv[1]);
5166 if (o == NULL) {
96d8b4ee 5167 addReply(c,shared.nullbulk);
6e333bbe 5168 return;
5169 } else {
5170 if (o->type != REDIS_ZSET) {
5171 addReply(c,shared.wrongtypeerr);
5172 } else {
5173 dictEntry *de;
5174
5175 zs = o->ptr;
5176 de = dictFind(zs->dict,c->argv[2]);
5177 if (!de) {
5178 addReply(c,shared.nullbulk);
5179 } else {
6e333bbe 5180 double *score = dictGetEntryVal(de);
5181
e2665397 5182 addReplyDouble(c,*score);
6e333bbe 5183 }
5184 }
5185 }
5186}
5187
6b47e12e 5188/* ========================= Non type-specific commands ==================== */
5189
ed9b544e 5190static void flushdbCommand(redisClient *c) {
ca37e9cd 5191 server.dirty += dictSize(c->db->dict);
3305306f 5192 dictEmpty(c->db->dict);
5193 dictEmpty(c->db->expires);
ed9b544e 5194 addReply(c,shared.ok);
ed9b544e 5195}
5196
5197static void flushallCommand(redisClient *c) {
ca37e9cd 5198 server.dirty += emptyDb();
ed9b544e 5199 addReply(c,shared.ok);
f78fd11b 5200 rdbSave(server.dbfilename);
ca37e9cd 5201 server.dirty++;
ed9b544e 5202}
5203
56906eef 5204static redisSortOperation *createSortOperation(int type, robj *pattern) {
ed9b544e 5205 redisSortOperation *so = zmalloc(sizeof(*so));
ed9b544e 5206 so->type = type;
5207 so->pattern = pattern;
5208 return so;
5209}
5210
5211/* Return the value associated to the key with a name obtained
5212 * substituting the first occurence of '*' in 'pattern' with 'subst' */
56906eef 5213static robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
ed9b544e 5214 char *p;
5215 sds spat, ssub;
5216 robj keyobj;
5217 int prefixlen, sublen, postfixlen;
ed9b544e 5218 /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */
5219 struct {
f1017b3f 5220 long len;
5221 long free;
ed9b544e 5222 char buf[REDIS_SORTKEY_MAX+1];
5223 } keyname;
5224
28173a49 5225 /* If the pattern is "#" return the substitution object itself in order
5226 * to implement the "SORT ... GET #" feature. */
5227 spat = pattern->ptr;
5228 if (spat[0] == '#' && spat[1] == '\0') {
5229 return subst;
5230 }
5231
5232 /* The substitution object may be specially encoded. If so we create
9d65a1bb 5233 * a decoded object on the fly. Otherwise getDecodedObject will just
5234 * increment the ref count, that we'll decrement later. */
5235 subst = getDecodedObject(subst);
942a3961 5236
ed9b544e 5237 ssub = subst->ptr;
5238 if (sdslen(spat)+sdslen(ssub)-1 > REDIS_SORTKEY_MAX) return NULL;
5239 p = strchr(spat,'*');
ed5a857a 5240 if (!p) {
5241 decrRefCount(subst);
5242 return NULL;
5243 }
ed9b544e 5244
5245 prefixlen = p-spat;
5246 sublen = sdslen(ssub);
5247 postfixlen = sdslen(spat)-(prefixlen+1);
5248 memcpy(keyname.buf,spat,prefixlen);
5249 memcpy(keyname.buf+prefixlen,ssub,sublen);
5250 memcpy(keyname.buf+prefixlen+sublen,p+1,postfixlen);
5251 keyname.buf[prefixlen+sublen+postfixlen] = '\0';
5252 keyname.len = prefixlen+sublen+postfixlen;
5253
dfc5e96c 5254 initStaticStringObject(keyobj,((char*)&keyname)+(sizeof(long)*2))
942a3961 5255 decrRefCount(subst);
5256
a4d1ba9a 5257 /* printf("lookup '%s' => %p\n", keyname.buf,de); */
3305306f 5258 return lookupKeyRead(db,&keyobj);
ed9b544e 5259}
5260
5261/* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with
5262 * the additional parameter is not standard but a BSD-specific we have to
5263 * pass sorting parameters via the global 'server' structure */
5264static int sortCompare(const void *s1, const void *s2) {
5265 const redisSortObject *so1 = s1, *so2 = s2;
5266 int cmp;
5267
5268 if (!server.sort_alpha) {
5269 /* Numeric sorting. Here it's trivial as we precomputed scores */
5270 if (so1->u.score > so2->u.score) {
5271 cmp = 1;
5272 } else if (so1->u.score < so2->u.score) {
5273 cmp = -1;
5274 } else {
5275 cmp = 0;
5276 }
5277 } else {
5278 /* Alphanumeric sorting */
5279 if (server.sort_bypattern) {
5280 if (!so1->u.cmpobj || !so2->u.cmpobj) {
5281 /* At least one compare object is NULL */
5282 if (so1->u.cmpobj == so2->u.cmpobj)
5283 cmp = 0;
5284 else if (so1->u.cmpobj == NULL)
5285 cmp = -1;
5286 else
5287 cmp = 1;
5288 } else {
5289 /* We have both the objects, use strcoll */
5290 cmp = strcoll(so1->u.cmpobj->ptr,so2->u.cmpobj->ptr);
5291 }
5292 } else {
5293 /* Compare elements directly */
9d65a1bb 5294 robj *dec1, *dec2;
5295
5296 dec1 = getDecodedObject(so1->obj);
5297 dec2 = getDecodedObject(so2->obj);
5298 cmp = strcoll(dec1->ptr,dec2->ptr);
5299 decrRefCount(dec1);
5300 decrRefCount(dec2);
ed9b544e 5301 }
5302 }
5303 return server.sort_desc ? -cmp : cmp;
5304}
5305
5306/* The SORT command is the most complex command in Redis. Warning: this code
5307 * is optimized for speed and a bit less for readability */
5308static void sortCommand(redisClient *c) {
ed9b544e 5309 list *operations;
5310 int outputlen = 0;
5311 int desc = 0, alpha = 0;
5312 int limit_start = 0, limit_count = -1, start, end;
5313 int j, dontsort = 0, vectorlen;
5314 int getop = 0; /* GET operation counter */
443c6409 5315 robj *sortval, *sortby = NULL, *storekey = NULL;
ed9b544e 5316 redisSortObject *vector; /* Resulting vector to sort */
5317
5318 /* Lookup the key to sort. It must be of the right types */
3305306f 5319 sortval = lookupKeyRead(c->db,c->argv[1]);
5320 if (sortval == NULL) {
d922ae65 5321 addReply(c,shared.nullmultibulk);
ed9b544e 5322 return;
5323 }
a5eb649b 5324 if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST &&
5325 sortval->type != REDIS_ZSET)
5326 {
c937aa89 5327 addReply(c,shared.wrongtypeerr);
ed9b544e 5328 return;
5329 }
5330
5331 /* Create a list of operations to perform for every sorted element.
5332 * Operations can be GET/DEL/INCR/DECR */
5333 operations = listCreate();
092dac2a 5334 listSetFreeMethod(operations,zfree);
ed9b544e 5335 j = 2;
5336
5337 /* Now we need to protect sortval incrementing its count, in the future
5338 * SORT may have options able to overwrite/delete keys during the sorting
5339 * and the sorted key itself may get destroied */
5340 incrRefCount(sortval);
5341
5342 /* The SORT command has an SQL-alike syntax, parse it */
5343 while(j < c->argc) {
5344 int leftargs = c->argc-j-1;
5345 if (!strcasecmp(c->argv[j]->ptr,"asc")) {
5346 desc = 0;
5347 } else if (!strcasecmp(c->argv[j]->ptr,"desc")) {
5348 desc = 1;
5349 } else if (!strcasecmp(c->argv[j]->ptr,"alpha")) {
5350 alpha = 1;
5351 } else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) {
5352 limit_start = atoi(c->argv[j+1]->ptr);
5353 limit_count = atoi(c->argv[j+2]->ptr);
5354 j+=2;
443c6409 5355 } else if (!strcasecmp(c->argv[j]->ptr,"store") && leftargs >= 1) {
5356 storekey = c->argv[j+1];
5357 j++;
ed9b544e 5358 } else if (!strcasecmp(c->argv[j]->ptr,"by") && leftargs >= 1) {
5359 sortby = c->argv[j+1];
5360 /* If the BY pattern does not contain '*', i.e. it is constant,
5361 * we don't need to sort nor to lookup the weight keys. */
5362 if (strchr(c->argv[j+1]->ptr,'*') == NULL) dontsort = 1;
5363 j++;
5364 } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
5365 listAddNodeTail(operations,createSortOperation(
5366 REDIS_SORT_GET,c->argv[j+1]));
5367 getop++;
5368 j++;
ed9b544e 5369 } else {
5370 decrRefCount(sortval);
5371 listRelease(operations);
c937aa89 5372 addReply(c,shared.syntaxerr);
ed9b544e 5373 return;
5374 }
5375 j++;
5376 }
5377
5378 /* Load the sorting vector with all the objects to sort */
a5eb649b 5379 switch(sortval->type) {
5380 case REDIS_LIST: vectorlen = listLength((list*)sortval->ptr); break;
5381 case REDIS_SET: vectorlen = dictSize((dict*)sortval->ptr); break;
5382 case REDIS_ZSET: vectorlen = dictSize(((zset*)sortval->ptr)->dict); break;
dfc5e96c 5383 default: vectorlen = 0; redisAssert(0); /* Avoid GCC warning */
a5eb649b 5384 }
ed9b544e 5385 vector = zmalloc(sizeof(redisSortObject)*vectorlen);
ed9b544e 5386 j = 0;
a5eb649b 5387
ed9b544e 5388 if (sortval->type == REDIS_LIST) {
5389 list *list = sortval->ptr;
6208b3a7 5390 listNode *ln;
c7df85a4 5391 listIter li;
6208b3a7 5392
c7df85a4 5393 listRewind(list,&li);
5394 while((ln = listNext(&li))) {
ed9b544e 5395 robj *ele = ln->value;
5396 vector[j].obj = ele;
5397 vector[j].u.score = 0;
5398 vector[j].u.cmpobj = NULL;
ed9b544e 5399 j++;
5400 }
5401 } else {
a5eb649b 5402 dict *set;
ed9b544e 5403 dictIterator *di;
5404 dictEntry *setele;
5405
a5eb649b 5406 if (sortval->type == REDIS_SET) {
5407 set = sortval->ptr;
5408 } else {
5409 zset *zs = sortval->ptr;
5410 set = zs->dict;
5411 }
5412
ed9b544e 5413 di = dictGetIterator(set);
ed9b544e 5414 while((setele = dictNext(di)) != NULL) {
5415 vector[j].obj = dictGetEntryKey(setele);
5416 vector[j].u.score = 0;
5417 vector[j].u.cmpobj = NULL;
5418 j++;
5419 }
5420 dictReleaseIterator(di);
5421 }
dfc5e96c 5422 redisAssert(j == vectorlen);
ed9b544e 5423
5424 /* Now it's time to load the right scores in the sorting vector */
5425 if (dontsort == 0) {
5426 for (j = 0; j < vectorlen; j++) {
5427 if (sortby) {
5428 robj *byval;
5429
3305306f 5430 byval = lookupKeyByPattern(c->db,sortby,vector[j].obj);
ed9b544e 5431 if (!byval || byval->type != REDIS_STRING) continue;
5432 if (alpha) {
9d65a1bb 5433 vector[j].u.cmpobj = getDecodedObject(byval);
ed9b544e 5434 } else {
942a3961 5435 if (byval->encoding == REDIS_ENCODING_RAW) {
5436 vector[j].u.score = strtod(byval->ptr,NULL);
5437 } else {
9d65a1bb 5438 /* Don't need to decode the object if it's
5439 * integer-encoded (the only encoding supported) so
5440 * far. We can just cast it */
f1017b3f 5441 if (byval->encoding == REDIS_ENCODING_INT) {
942a3961 5442 vector[j].u.score = (long)byval->ptr;
f1017b3f 5443 } else
dfc5e96c 5444 redisAssert(1 != 1);
942a3961 5445 }
ed9b544e 5446 }
5447 } else {
942a3961 5448 if (!alpha) {
5449 if (vector[j].obj->encoding == REDIS_ENCODING_RAW)
5450 vector[j].u.score = strtod(vector[j].obj->ptr,NULL);
5451 else {
5452 if (vector[j].obj->encoding == REDIS_ENCODING_INT)
5453 vector[j].u.score = (long) vector[j].obj->ptr;
5454 else
dfc5e96c 5455 redisAssert(1 != 1);
942a3961 5456 }
5457 }
ed9b544e 5458 }
5459 }
5460 }
5461
5462 /* We are ready to sort the vector... perform a bit of sanity check
5463 * on the LIMIT option too. We'll use a partial version of quicksort. */
5464 start = (limit_start < 0) ? 0 : limit_start;
5465 end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1;
5466 if (start >= vectorlen) {
5467 start = vectorlen-1;
5468 end = vectorlen-2;
5469 }
5470 if (end >= vectorlen) end = vectorlen-1;
5471
5472 if (dontsort == 0) {
5473 server.sort_desc = desc;
5474 server.sort_alpha = alpha;
5475 server.sort_bypattern = sortby ? 1 : 0;
5f5b9840 5476 if (sortby && (start != 0 || end != vectorlen-1))
5477 pqsort(vector,vectorlen,sizeof(redisSortObject),sortCompare, start,end);
5478 else
5479 qsort(vector,vectorlen,sizeof(redisSortObject),sortCompare);
ed9b544e 5480 }
5481
5482 /* Send command output to the output buffer, performing the specified
5483 * GET/DEL/INCR/DECR operations if any. */
5484 outputlen = getop ? getop*(end-start+1) : end-start+1;
443c6409 5485 if (storekey == NULL) {
5486 /* STORE option not specified, sent the sorting result to client */
5487 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",outputlen));
5488 for (j = start; j <= end; j++) {
5489 listNode *ln;
c7df85a4 5490 listIter li;
5491
443c6409 5492 if (!getop) {
5493 addReplyBulkLen(c,vector[j].obj);
5494 addReply(c,vector[j].obj);
5495 addReply(c,shared.crlf);
5496 }
c7df85a4 5497 listRewind(operations,&li);
5498 while((ln = listNext(&li))) {
443c6409 5499 redisSortOperation *sop = ln->value;
5500 robj *val = lookupKeyByPattern(c->db,sop->pattern,
5501 vector[j].obj);
5502
5503 if (sop->type == REDIS_SORT_GET) {
5504 if (!val || val->type != REDIS_STRING) {
5505 addReply(c,shared.nullbulk);
5506 } else {
5507 addReplyBulkLen(c,val);
5508 addReply(c,val);
5509 addReply(c,shared.crlf);
5510 }
5511 } else {
dfc5e96c 5512 redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
443c6409 5513 }
5514 }
ed9b544e 5515 }
443c6409 5516 } else {
5517 robj *listObject = createListObject();
5518 list *listPtr = (list*) listObject->ptr;
5519
5520 /* STORE option specified, set the sorting result as a List object */
5521 for (j = start; j <= end; j++) {
5522 listNode *ln;
c7df85a4 5523 listIter li;
5524
443c6409 5525 if (!getop) {
5526 listAddNodeTail(listPtr,vector[j].obj);
5527 incrRefCount(vector[j].obj);
5528 }
c7df85a4 5529 listRewind(operations,&li);
5530 while((ln = listNext(&li))) {
443c6409 5531 redisSortOperation *sop = ln->value;
5532 robj *val = lookupKeyByPattern(c->db,sop->pattern,
5533 vector[j].obj);
5534
5535 if (sop->type == REDIS_SORT_GET) {
5536 if (!val || val->type != REDIS_STRING) {
5537 listAddNodeTail(listPtr,createStringObject("",0));
5538 } else {
5539 listAddNodeTail(listPtr,val);
5540 incrRefCount(val);
5541 }
ed9b544e 5542 } else {
dfc5e96c 5543 redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
ed9b544e 5544 }
ed9b544e 5545 }
ed9b544e 5546 }
121796f7 5547 if (dictReplace(c->db->dict,storekey,listObject)) {
5548 incrRefCount(storekey);
5549 }
443c6409 5550 /* Note: we add 1 because the DB is dirty anyway since even if the
5551 * SORT result is empty a new key is set and maybe the old content
5552 * replaced. */
5553 server.dirty += 1+outputlen;
5554 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",outputlen));
ed9b544e 5555 }
5556
5557 /* Cleanup */
5558 decrRefCount(sortval);
5559 listRelease(operations);
5560 for (j = 0; j < vectorlen; j++) {
5561 if (sortby && alpha && vector[j].u.cmpobj)
5562 decrRefCount(vector[j].u.cmpobj);
5563 }
5564 zfree(vector);
5565}
5566
ec6c7a1d 5567/* Convert an amount of bytes into a human readable string in the form
5568 * of 100B, 2G, 100M, 4K, and so forth. */
5569static void bytesToHuman(char *s, unsigned long long n) {
5570 double d;
5571
5572 if (n < 1024) {
5573 /* Bytes */
5574 sprintf(s,"%lluB",n);
5575 return;
5576 } else if (n < (1024*1024)) {
5577 d = (double)n/(1024);
5578 sprintf(s,"%.2fK",d);
5579 } else if (n < (1024LL*1024*1024)) {
5580 d = (double)n/(1024*1024);
5581 sprintf(s,"%.2fM",d);
5582 } else if (n < (1024LL*1024*1024*1024)) {
5583 d = (double)n/(1024LL*1024*1024);
5584 sprintf(s,"%.2fM",d);
5585 }
5586}
5587
1c85b79f 5588/* Create the string returned by the INFO command. This is decoupled
5589 * by the INFO command itself as we need to report the same information
5590 * on memory corruption problems. */
5591static sds genRedisInfoString(void) {
ed9b544e 5592 sds info;
5593 time_t uptime = time(NULL)-server.stat_starttime;
c3cb078d 5594 int j;
ec6c7a1d 5595 char hmem[64];
5596
5597 bytesToHuman(hmem,server.usedmemory);
ed9b544e 5598 info = sdscatprintf(sdsempty(),
5599 "redis_version:%s\r\n"
f1017b3f 5600 "arch_bits:%s\r\n"
7a932b74 5601 "multiplexing_api:%s\r\n"
0d7170a4 5602 "process_id:%ld\r\n"
682ac724 5603 "uptime_in_seconds:%ld\r\n"
5604 "uptime_in_days:%ld\r\n"
ed9b544e 5605 "connected_clients:%d\r\n"
5606 "connected_slaves:%d\r\n"
f86a74e9 5607 "blocked_clients:%d\r\n"
5fba9f71 5608 "used_memory:%zu\r\n"
ec6c7a1d 5609 "used_memory_human:%s\r\n"
ed9b544e 5610 "changes_since_last_save:%lld\r\n"
be2bb6b0 5611 "bgsave_in_progress:%d\r\n"
682ac724 5612 "last_save_time:%ld\r\n"
b3fad521 5613 "bgrewriteaof_in_progress:%d\r\n"
ed9b544e 5614 "total_connections_received:%lld\r\n"
5615 "total_commands_processed:%lld\r\n"
7d98e08c 5616 "vm_enabled:%d\r\n"
a0f643ea 5617 "role:%s\r\n"
ed9b544e 5618 ,REDIS_VERSION,
f1017b3f 5619 (sizeof(long) == 8) ? "64" : "32",
7a932b74 5620 aeGetApiName(),
0d7170a4 5621 (long) getpid(),
a0f643ea 5622 uptime,
5623 uptime/(3600*24),
ed9b544e 5624 listLength(server.clients)-listLength(server.slaves),
5625 listLength(server.slaves),
f86a74e9 5626 server.blockedclients,
ed9b544e 5627 server.usedmemory,
ec6c7a1d 5628 hmem,
ed9b544e 5629 server.dirty,
9d65a1bb 5630 server.bgsavechildpid != -1,
ed9b544e 5631 server.lastsave,
b3fad521 5632 server.bgrewritechildpid != -1,
ed9b544e 5633 server.stat_numconnections,
5634 server.stat_numcommands,
7d98e08c 5635 server.vm_enabled != 0,
a0f643ea 5636 server.masterhost == NULL ? "master" : "slave"
ed9b544e 5637 );
a0f643ea 5638 if (server.masterhost) {
5639 info = sdscatprintf(info,
5640 "master_host:%s\r\n"
5641 "master_port:%d\r\n"
5642 "master_link_status:%s\r\n"
5643 "master_last_io_seconds_ago:%d\r\n"
5644 ,server.masterhost,
5645 server.masterport,
5646 (server.replstate == REDIS_REPL_CONNECTED) ?
5647 "up" : "down",
f72b934d 5648 server.master ? ((int)(time(NULL)-server.master->lastinteraction)) : -1
a0f643ea 5649 );
5650 }
7d98e08c 5651 if (server.vm_enabled) {
1064ef87 5652 lockThreadedIO();
7d98e08c 5653 info = sdscatprintf(info,
5654 "vm_conf_max_memory:%llu\r\n"
5655 "vm_conf_page_size:%llu\r\n"
5656 "vm_conf_pages:%llu\r\n"
5657 "vm_stats_used_pages:%llu\r\n"
5658 "vm_stats_swapped_objects:%llu\r\n"
5659 "vm_stats_swappin_count:%llu\r\n"
5660 "vm_stats_swappout_count:%llu\r\n"
b9bc0eef 5661 "vm_stats_io_newjobs_len:%lu\r\n"
5662 "vm_stats_io_processing_len:%lu\r\n"
5663 "vm_stats_io_processed_len:%lu\r\n"
5664 "vm_stats_io_waiting_clients:%lu\r\n"
25fd2cb2 5665 "vm_stats_io_active_threads:%lu\r\n"
7d98e08c 5666 ,(unsigned long long) server.vm_max_memory,
5667 (unsigned long long) server.vm_page_size,
5668 (unsigned long long) server.vm_pages,
5669 (unsigned long long) server.vm_stats_used_pages,
5670 (unsigned long long) server.vm_stats_swapped_objects,
5671 (unsigned long long) server.vm_stats_swapins,
b9bc0eef 5672 (unsigned long long) server.vm_stats_swapouts,
5673 (unsigned long) listLength(server.io_newjobs),
5674 (unsigned long) listLength(server.io_processing),
5675 (unsigned long) listLength(server.io_processed),
25fd2cb2 5676 (unsigned long) listLength(server.io_clients),
5677 (unsigned long) server.io_active_threads
7d98e08c 5678 );
1064ef87 5679 unlockThreadedIO();
7d98e08c 5680 }
c3cb078d 5681 for (j = 0; j < server.dbnum; j++) {
5682 long long keys, vkeys;
5683
5684 keys = dictSize(server.db[j].dict);
5685 vkeys = dictSize(server.db[j].expires);
5686 if (keys || vkeys) {
9d65a1bb 5687 info = sdscatprintf(info, "db%d:keys=%lld,expires=%lld\r\n",
c3cb078d 5688 j, keys, vkeys);
5689 }
5690 }
1c85b79f 5691 return info;
5692}
5693
5694static void infoCommand(redisClient *c) {
5695 sds info = genRedisInfoString();
83c6a618 5696 addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n",
5697 (unsigned long)sdslen(info)));
ed9b544e 5698 addReplySds(c,info);
70003d28 5699 addReply(c,shared.crlf);
ed9b544e 5700}
5701
3305306f 5702static void monitorCommand(redisClient *c) {
5703 /* ignore MONITOR if aleady slave or in monitor mode */
5704 if (c->flags & REDIS_SLAVE) return;
5705
5706 c->flags |= (REDIS_SLAVE|REDIS_MONITOR);
5707 c->slaveseldb = 0;
6b47e12e 5708 listAddNodeTail(server.monitors,c);
3305306f 5709 addReply(c,shared.ok);
5710}
5711
5712/* ================================= Expire ================================= */
5713static int removeExpire(redisDb *db, robj *key) {
5714 if (dictDelete(db->expires,key) == DICT_OK) {
5715 return 1;
5716 } else {
5717 return 0;
5718 }
5719}
5720
5721static int setExpire(redisDb *db, robj *key, time_t when) {
5722 if (dictAdd(db->expires,key,(void*)when) == DICT_ERR) {
5723 return 0;
5724 } else {
5725 incrRefCount(key);
5726 return 1;
5727 }
5728}
5729
bb32ede5 5730/* Return the expire time of the specified key, or -1 if no expire
5731 * is associated with this key (i.e. the key is non volatile) */
5732static time_t getExpire(redisDb *db, robj *key) {
5733 dictEntry *de;
5734
5735 /* No expire? return ASAP */
5736 if (dictSize(db->expires) == 0 ||
5737 (de = dictFind(db->expires,key)) == NULL) return -1;
5738
5739 return (time_t) dictGetEntryVal(de);
5740}
5741
3305306f 5742static int expireIfNeeded(redisDb *db, robj *key) {
5743 time_t when;
5744 dictEntry *de;
5745
5746 /* No expire? return ASAP */
5747 if (dictSize(db->expires) == 0 ||
5748 (de = dictFind(db->expires,key)) == NULL) return 0;
5749
5750 /* Lookup the expire */
5751 when = (time_t) dictGetEntryVal(de);
5752 if (time(NULL) <= when) return 0;
5753
5754 /* Delete the key */
5755 dictDelete(db->expires,key);
5756 return dictDelete(db->dict,key) == DICT_OK;
5757}
5758
5759static int deleteIfVolatile(redisDb *db, robj *key) {
5760 dictEntry *de;
5761
5762 /* No expire? return ASAP */
5763 if (dictSize(db->expires) == 0 ||
5764 (de = dictFind(db->expires,key)) == NULL) return 0;
5765
5766 /* Delete the key */
0c66a471 5767 server.dirty++;
3305306f 5768 dictDelete(db->expires,key);
5769 return dictDelete(db->dict,key) == DICT_OK;
5770}
5771
802e8373 5772static void expireGenericCommand(redisClient *c, robj *key, time_t seconds) {
3305306f 5773 dictEntry *de;
3305306f 5774
802e8373 5775 de = dictFind(c->db->dict,key);
3305306f 5776 if (de == NULL) {
5777 addReply(c,shared.czero);
5778 return;
5779 }
43e5ccdf 5780 if (seconds < 0) {
5781 if (deleteKey(c->db,key)) server.dirty++;
5782 addReply(c, shared.cone);
3305306f 5783 return;
5784 } else {
5785 time_t when = time(NULL)+seconds;
802e8373 5786 if (setExpire(c->db,key,when)) {
3305306f 5787 addReply(c,shared.cone);
77423026 5788 server.dirty++;
5789 } else {
3305306f 5790 addReply(c,shared.czero);
77423026 5791 }
3305306f 5792 return;
5793 }
5794}
5795
802e8373 5796static void expireCommand(redisClient *c) {
5797 expireGenericCommand(c,c->argv[1],strtol(c->argv[2]->ptr,NULL,10));
5798}
5799
5800static void expireatCommand(redisClient *c) {
5801 expireGenericCommand(c,c->argv[1],strtol(c->argv[2]->ptr,NULL,10)-time(NULL));
5802}
5803
fd88489a 5804static void ttlCommand(redisClient *c) {
5805 time_t expire;
5806 int ttl = -1;
5807
5808 expire = getExpire(c->db,c->argv[1]);
5809 if (expire != -1) {
5810 ttl = (int) (expire-time(NULL));
5811 if (ttl < 0) ttl = -1;
5812 }
5813 addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",ttl));
5814}
5815
6e469882 5816/* ================================ MULTI/EXEC ============================== */
5817
5818/* Client state initialization for MULTI/EXEC */
5819static void initClientMultiState(redisClient *c) {
5820 c->mstate.commands = NULL;
5821 c->mstate.count = 0;
5822}
5823
5824/* Release all the resources associated with MULTI/EXEC state */
5825static void freeClientMultiState(redisClient *c) {
5826 int j;
5827
5828 for (j = 0; j < c->mstate.count; j++) {
5829 int i;
5830 multiCmd *mc = c->mstate.commands+j;
5831
5832 for (i = 0; i < mc->argc; i++)
5833 decrRefCount(mc->argv[i]);
5834 zfree(mc->argv);
5835 }
5836 zfree(c->mstate.commands);
5837}
5838
5839/* Add a new command into the MULTI commands queue */
5840static void queueMultiCommand(redisClient *c, struct redisCommand *cmd) {
5841 multiCmd *mc;
5842 int j;
5843
5844 c->mstate.commands = zrealloc(c->mstate.commands,
5845 sizeof(multiCmd)*(c->mstate.count+1));
5846 mc = c->mstate.commands+c->mstate.count;
5847 mc->cmd = cmd;
5848 mc->argc = c->argc;
5849 mc->argv = zmalloc(sizeof(robj*)*c->argc);
5850 memcpy(mc->argv,c->argv,sizeof(robj*)*c->argc);
5851 for (j = 0; j < c->argc; j++)
5852 incrRefCount(mc->argv[j]);
5853 c->mstate.count++;
5854}
5855
5856static void multiCommand(redisClient *c) {
5857 c->flags |= REDIS_MULTI;
36c548f0 5858 addReply(c,shared.ok);
6e469882 5859}
5860
5861static void execCommand(redisClient *c) {
5862 int j;
5863 robj **orig_argv;
5864 int orig_argc;
5865
5866 if (!(c->flags & REDIS_MULTI)) {
5867 addReplySds(c,sdsnew("-ERR EXEC without MULTI\r\n"));
5868 return;
5869 }
5870
5871 orig_argv = c->argv;
5872 orig_argc = c->argc;
5873 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->mstate.count));
5874 for (j = 0; j < c->mstate.count; j++) {
5875 c->argc = c->mstate.commands[j].argc;
5876 c->argv = c->mstate.commands[j].argv;
5877 call(c,c->mstate.commands[j].cmd);
5878 }
5879 c->argv = orig_argv;
5880 c->argc = orig_argc;
5881 freeClientMultiState(c);
5882 initClientMultiState(c);
5883 c->flags &= (~REDIS_MULTI);
5884}
5885
4409877e 5886/* =========================== Blocking Operations ========================= */
5887
5888/* Currently Redis blocking operations support is limited to list POP ops,
5889 * so the current implementation is not fully generic, but it is also not
5890 * completely specific so it will not require a rewrite to support new
5891 * kind of blocking operations in the future.
5892 *
5893 * Still it's important to note that list blocking operations can be already
5894 * used as a notification mechanism in order to implement other blocking
5895 * operations at application level, so there must be a very strong evidence
5896 * of usefulness and generality before new blocking operations are implemented.
5897 *
5898 * This is how the current blocking POP works, we use BLPOP as example:
5899 * - If the user calls BLPOP and the key exists and contains a non empty list
5900 * then LPOP is called instead. So BLPOP is semantically the same as LPOP
5901 * if there is not to block.
5902 * - If instead BLPOP is called and the key does not exists or the list is
5903 * empty we need to block. In order to do so we remove the notification for
5904 * new data to read in the client socket (so that we'll not serve new
5905 * requests if the blocking request is not served). Also we put the client
95242ab5 5906 * in a dictionary (db->blockingkeys) mapping keys to a list of clients
4409877e 5907 * blocking for this keys.
5908 * - If a PUSH operation against a key with blocked clients waiting is
5909 * performed, we serve the first in the list: basically instead to push
5910 * the new element inside the list we return it to the (first / oldest)
5911 * blocking client, unblock the client, and remove it form the list.
5912 *
5913 * The above comment and the source code should be enough in order to understand
5914 * the implementation and modify / fix it later.
5915 */
5916
5917/* Set a client in blocking mode for the specified key, with the specified
5918 * timeout */
b177fd30 5919static void blockForKeys(redisClient *c, robj **keys, int numkeys, time_t timeout) {
4409877e 5920 dictEntry *de;
5921 list *l;
b177fd30 5922 int j;
4409877e 5923
b177fd30 5924 c->blockingkeys = zmalloc(sizeof(robj*)*numkeys);
5925 c->blockingkeysnum = numkeys;
4409877e 5926 c->blockingto = timeout;
b177fd30 5927 for (j = 0; j < numkeys; j++) {
5928 /* Add the key in the client structure, to map clients -> keys */
5929 c->blockingkeys[j] = keys[j];
5930 incrRefCount(keys[j]);
4409877e 5931
b177fd30 5932 /* And in the other "side", to map keys -> clients */
5933 de = dictFind(c->db->blockingkeys,keys[j]);
5934 if (de == NULL) {
5935 int retval;
5936
5937 /* For every key we take a list of clients blocked for it */
5938 l = listCreate();
5939 retval = dictAdd(c->db->blockingkeys,keys[j],l);
5940 incrRefCount(keys[j]);
5941 assert(retval == DICT_OK);
5942 } else {
5943 l = dictGetEntryVal(de);
5944 }
5945 listAddNodeTail(l,c);
4409877e 5946 }
b177fd30 5947 /* Mark the client as a blocked client */
4409877e 5948 c->flags |= REDIS_BLOCKED;
5949 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
f86a74e9 5950 server.blockedclients++;
4409877e 5951}
5952
5953/* Unblock a client that's waiting in a blocking operation such as BLPOP */
b0d8747d 5954static void unblockClientWaitingData(redisClient *c) {
4409877e 5955 dictEntry *de;
5956 list *l;
b177fd30 5957 int j;
4409877e 5958
b177fd30 5959 assert(c->blockingkeys != NULL);
5960 /* The client may wait for multiple keys, so unblock it for every key. */
5961 for (j = 0; j < c->blockingkeysnum; j++) {
5962 /* Remove this client from the list of clients waiting for this key. */
5963 de = dictFind(c->db->blockingkeys,c->blockingkeys[j]);
5964 assert(de != NULL);
5965 l = dictGetEntryVal(de);
5966 listDelNode(l,listSearchKey(l,c));
5967 /* If the list is empty we need to remove it to avoid wasting memory */
5968 if (listLength(l) == 0)
5969 dictDelete(c->db->blockingkeys,c->blockingkeys[j]);
5970 decrRefCount(c->blockingkeys[j]);
5971 }
5972 /* Cleanup the client structure */
5973 zfree(c->blockingkeys);
5974 c->blockingkeys = NULL;
4409877e 5975 c->flags &= (~REDIS_BLOCKED);
f86a74e9 5976 server.blockedclients--;
4409877e 5977 /* Ok now we are ready to get read events from socket, note that we
b0d8747d 5978 * can't trap errors here as it's possible that unblockClientWaitingDatas() is
4409877e 5979 * called from freeClient() itself, and the only thing we can do
5980 * if we failed to register the READABLE event is to kill the client.
5981 * Still the following function should never fail in the real world as
5982 * we are sure the file descriptor is sane, and we exit on out of mem. */
5983 aeCreateFileEvent(server.el, c->fd, AE_READABLE, readQueryFromClient, c);
5984 /* As a final step we want to process data if there is some command waiting
b0d8747d 5985 * in the input buffer. Note that this is safe even if
5986 * unblockClientWaitingData() gets called from freeClient() because
5987 * freeClient() will be smart enough to call this function
5988 * *after* c->querybuf was set to NULL. */
4409877e 5989 if (c->querybuf && sdslen(c->querybuf) > 0) processInputBuffer(c);
5990}
5991
5992/* This should be called from any function PUSHing into lists.
5993 * 'c' is the "pushing client", 'key' is the key it is pushing data against,
5994 * 'ele' is the element pushed.
5995 *
5996 * If the function returns 0 there was no client waiting for a list push
5997 * against this key.
5998 *
5999 * If the function returns 1 there was a client waiting for a list push
6000 * against this key, the element was passed to this client thus it's not
6001 * needed to actually add it to the list and the caller should return asap. */
6002static int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
6003 struct dictEntry *de;
6004 redisClient *receiver;
6005 list *l;
6006 listNode *ln;
6007
6008 de = dictFind(c->db->blockingkeys,key);
6009 if (de == NULL) return 0;
6010 l = dictGetEntryVal(de);
6011 ln = listFirst(l);
6012 assert(ln != NULL);
6013 receiver = ln->value;
4409877e 6014
b177fd30 6015 addReplySds(receiver,sdsnew("*2\r\n"));
6016 addReplyBulkLen(receiver,key);
6017 addReply(receiver,key);
6018 addReply(receiver,shared.crlf);
4409877e 6019 addReplyBulkLen(receiver,ele);
6020 addReply(receiver,ele);
6021 addReply(receiver,shared.crlf);
b0d8747d 6022 unblockClientWaitingData(receiver);
4409877e 6023 return 1;
6024}
6025
6026/* Blocking RPOP/LPOP */
6027static void blockingPopGenericCommand(redisClient *c, int where) {
6028 robj *o;
6029 time_t timeout;
b177fd30 6030 int j;
4409877e 6031
b177fd30 6032 for (j = 1; j < c->argc-1; j++) {
6033 o = lookupKeyWrite(c->db,c->argv[j]);
6034 if (o != NULL) {
6035 if (o->type != REDIS_LIST) {
6036 addReply(c,shared.wrongtypeerr);
4409877e 6037 return;
b177fd30 6038 } else {
6039 list *list = o->ptr;
6040 if (listLength(list) != 0) {
6041 /* If the list contains elements fall back to the usual
6042 * non-blocking POP operation */
6043 robj *argv[2], **orig_argv;
6044 int orig_argc;
6045
6046 /* We need to alter the command arguments before to call
6047 * popGenericCommand() as the command takes a single key. */
6048 orig_argv = c->argv;
6049 orig_argc = c->argc;
6050 argv[1] = c->argv[j];
6051 c->argv = argv;
6052 c->argc = 2;
6053
6054 /* Also the return value is different, we need to output
6055 * the multi bulk reply header and the key name. The
6056 * "real" command will add the last element (the value)
6057 * for us. If this souds like an hack to you it's just
6058 * because it is... */
6059 addReplySds(c,sdsnew("*2\r\n"));
6060 addReplyBulkLen(c,argv[1]);
6061 addReply(c,argv[1]);
6062 addReply(c,shared.crlf);
6063 popGenericCommand(c,where);
6064
6065 /* Fix the client structure with the original stuff */
6066 c->argv = orig_argv;
6067 c->argc = orig_argc;
6068 return;
6069 }
4409877e 6070 }
6071 }
6072 }
6073 /* If the list is empty or the key does not exists we must block */
b177fd30 6074 timeout = strtol(c->argv[c->argc-1]->ptr,NULL,10);
4409877e 6075 if (timeout > 0) timeout += time(NULL);
b177fd30 6076 blockForKeys(c,c->argv+1,c->argc-2,timeout);
4409877e 6077}
6078
6079static void blpopCommand(redisClient *c) {
6080 blockingPopGenericCommand(c,REDIS_HEAD);
6081}
6082
6083static void brpopCommand(redisClient *c) {
6084 blockingPopGenericCommand(c,REDIS_TAIL);
6085}
6086
ed9b544e 6087/* =============================== Replication ============================= */
6088
a4d1ba9a 6089static int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 6090 ssize_t nwritten, ret = size;
6091 time_t start = time(NULL);
6092
6093 timeout++;
6094 while(size) {
6095 if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
6096 nwritten = write(fd,ptr,size);
6097 if (nwritten == -1) return -1;
6098 ptr += nwritten;
6099 size -= nwritten;
6100 }
6101 if ((time(NULL)-start) > timeout) {
6102 errno = ETIMEDOUT;
6103 return -1;
6104 }
6105 }
6106 return ret;
6107}
6108
a4d1ba9a 6109static int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 6110 ssize_t nread, totread = 0;
6111 time_t start = time(NULL);
6112
6113 timeout++;
6114 while(size) {
6115 if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
6116 nread = read(fd,ptr,size);
6117 if (nread == -1) return -1;
6118 ptr += nread;
6119 size -= nread;
6120 totread += nread;
6121 }
6122 if ((time(NULL)-start) > timeout) {
6123 errno = ETIMEDOUT;
6124 return -1;
6125 }
6126 }
6127 return totread;
6128}
6129
6130static int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
6131 ssize_t nread = 0;
6132
6133 size--;
6134 while(size) {
6135 char c;
6136
6137 if (syncRead(fd,&c,1,timeout) == -1) return -1;
6138 if (c == '\n') {
6139 *ptr = '\0';
6140 if (nread && *(ptr-1) == '\r') *(ptr-1) = '\0';
6141 return nread;
6142 } else {
6143 *ptr++ = c;
6144 *ptr = '\0';
6145 nread++;
6146 }
6147 }
6148 return nread;
6149}
6150
6151static void syncCommand(redisClient *c) {
40d224a9 6152 /* ignore SYNC if aleady slave or in monitor mode */
6153 if (c->flags & REDIS_SLAVE) return;
6154
6155 /* SYNC can't be issued when the server has pending data to send to
6156 * the client about already issued commands. We need a fresh reply
6157 * buffer registering the differences between the BGSAVE and the current
6158 * dataset, so that we can copy to other slaves if needed. */
6159 if (listLength(c->reply) != 0) {
6160 addReplySds(c,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
6161 return;
6162 }
6163
6164 redisLog(REDIS_NOTICE,"Slave ask for synchronization");
6165 /* Here we need to check if there is a background saving operation
6166 * in progress, or if it is required to start one */
9d65a1bb 6167 if (server.bgsavechildpid != -1) {
40d224a9 6168 /* Ok a background save is in progress. Let's check if it is a good
6169 * one for replication, i.e. if there is another slave that is
6170 * registering differences since the server forked to save */
6171 redisClient *slave;
6172 listNode *ln;
c7df85a4 6173 listIter li;
40d224a9 6174
c7df85a4 6175 listRewind(server.slaves,&li);
6176 while((ln = listNext(&li))) {
40d224a9 6177 slave = ln->value;
6178 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break;
40d224a9 6179 }
6180 if (ln) {
6181 /* Perfect, the server is already registering differences for
6182 * another slave. Set the right state, and copy the buffer. */
6183 listRelease(c->reply);
6184 c->reply = listDup(slave->reply);
40d224a9 6185 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
6186 redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC");
6187 } else {
6188 /* No way, we need to wait for the next BGSAVE in order to
6189 * register differences */
6190 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
6191 redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
6192 }
6193 } else {
6194 /* Ok we don't have a BGSAVE in progress, let's start one */
6195 redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
6196 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
6197 redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE");
6198 addReplySds(c,sdsnew("-ERR Unalbe to perform background save\r\n"));
6199 return;
6200 }
6201 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
6202 }
6208b3a7 6203 c->repldbfd = -1;
40d224a9 6204 c->flags |= REDIS_SLAVE;
6205 c->slaveseldb = 0;
6b47e12e 6206 listAddNodeTail(server.slaves,c);
40d224a9 6207 return;
6208}
6209
6208b3a7 6210static void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
6211 redisClient *slave = privdata;
6212 REDIS_NOTUSED(el);
6213 REDIS_NOTUSED(mask);
6214 char buf[REDIS_IOBUF_LEN];
6215 ssize_t nwritten, buflen;
6216
6217 if (slave->repldboff == 0) {
6218 /* Write the bulk write count before to transfer the DB. In theory here
6219 * we don't know how much room there is in the output buffer of the
6220 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
6221 * operations) will never be smaller than the few bytes we need. */
6222 sds bulkcount;
6223
6224 bulkcount = sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
6225 slave->repldbsize);
6226 if (write(fd,bulkcount,sdslen(bulkcount)) != (signed)sdslen(bulkcount))
6227 {
6228 sdsfree(bulkcount);
6229 freeClient(slave);
6230 return;
6231 }
6232 sdsfree(bulkcount);
6233 }
6234 lseek(slave->repldbfd,slave->repldboff,SEEK_SET);
6235 buflen = read(slave->repldbfd,buf,REDIS_IOBUF_LEN);
6236 if (buflen <= 0) {
6237 redisLog(REDIS_WARNING,"Read error sending DB to slave: %s",
6238 (buflen == 0) ? "premature EOF" : strerror(errno));
6239 freeClient(slave);
6240 return;
6241 }
6242 if ((nwritten = write(fd,buf,buflen)) == -1) {
f870935d 6243 redisLog(REDIS_VERBOSE,"Write error sending DB to slave: %s",
6208b3a7 6244 strerror(errno));
6245 freeClient(slave);
6246 return;
6247 }
6248 slave->repldboff += nwritten;
6249 if (slave->repldboff == slave->repldbsize) {
6250 close(slave->repldbfd);
6251 slave->repldbfd = -1;
6252 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
6253 slave->replstate = REDIS_REPL_ONLINE;
6254 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
266373b2 6255 sendReplyToClient, slave) == AE_ERR) {
6208b3a7 6256 freeClient(slave);
6257 return;
6258 }
6259 addReplySds(slave,sdsempty());
6260 redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
6261 }
6262}
ed9b544e 6263
a3b21203 6264/* This function is called at the end of every backgrond saving.
6265 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
6266 * otherwise REDIS_ERR is passed to the function.
6267 *
6268 * The goal of this function is to handle slaves waiting for a successful
6269 * background saving in order to perform non-blocking synchronization. */
6270static void updateSlavesWaitingBgsave(int bgsaveerr) {
6208b3a7 6271 listNode *ln;
6272 int startbgsave = 0;
c7df85a4 6273 listIter li;
ed9b544e 6274
c7df85a4 6275 listRewind(server.slaves,&li);
6276 while((ln = listNext(&li))) {
6208b3a7 6277 redisClient *slave = ln->value;
ed9b544e 6278
6208b3a7 6279 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) {
6280 startbgsave = 1;
6281 slave->replstate = REDIS_REPL_WAIT_BGSAVE_END;
6282 } else if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
dde65f3f 6283 struct redis_stat buf;
6208b3a7 6284
6285 if (bgsaveerr != REDIS_OK) {
6286 freeClient(slave);
6287 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE child returned an error");
6288 continue;
6289 }
6290 if ((slave->repldbfd = open(server.dbfilename,O_RDONLY)) == -1 ||
dde65f3f 6291 redis_fstat(slave->repldbfd,&buf) == -1) {
6208b3a7 6292 freeClient(slave);
6293 redisLog(REDIS_WARNING,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno));
6294 continue;
6295 }
6296 slave->repldboff = 0;
6297 slave->repldbsize = buf.st_size;
6298 slave->replstate = REDIS_REPL_SEND_BULK;
6299 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
266373b2 6300 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE, sendBulkToSlave, slave) == AE_ERR) {
6208b3a7 6301 freeClient(slave);
6302 continue;
6303 }
6304 }
ed9b544e 6305 }
6208b3a7 6306 if (startbgsave) {
6307 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
c7df85a4 6308 listIter li;
6309
6310 listRewind(server.slaves,&li);
6208b3a7 6311 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE failed");
c7df85a4 6312 while((ln = listNext(&li))) {
6208b3a7 6313 redisClient *slave = ln->value;
ed9b544e 6314
6208b3a7 6315 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START)
6316 freeClient(slave);
6317 }
6318 }
6319 }
ed9b544e 6320}
6321
6322static int syncWithMaster(void) {
d0ccebcf 6323 char buf[1024], tmpfile[256], authcmd[1024];
ed9b544e 6324 int dumpsize;
6325 int fd = anetTcpConnect(NULL,server.masterhost,server.masterport);
6326 int dfd;
6327
6328 if (fd == -1) {
6329 redisLog(REDIS_WARNING,"Unable to connect to MASTER: %s",
6330 strerror(errno));
6331 return REDIS_ERR;
6332 }
d0ccebcf 6333
6334 /* AUTH with the master if required. */
6335 if(server.masterauth) {
6336 snprintf(authcmd, 1024, "AUTH %s\r\n", server.masterauth);
6337 if (syncWrite(fd, authcmd, strlen(server.masterauth)+7, 5) == -1) {
6338 close(fd);
6339 redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",
6340 strerror(errno));
6341 return REDIS_ERR;
6342 }
6343 /* Read the AUTH result. */
6344 if (syncReadLine(fd,buf,1024,3600) == -1) {
6345 close(fd);
6346 redisLog(REDIS_WARNING,"I/O error reading auth result from MASTER: %s",
6347 strerror(errno));
6348 return REDIS_ERR;
6349 }
6350 if (buf[0] != '+') {
6351 close(fd);
6352 redisLog(REDIS_WARNING,"Cannot AUTH to MASTER, is the masterauth password correct?");
6353 return REDIS_ERR;
6354 }
6355 }
6356
ed9b544e 6357 /* Issue the SYNC command */
6358 if (syncWrite(fd,"SYNC \r\n",7,5) == -1) {
6359 close(fd);
6360 redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
6361 strerror(errno));
6362 return REDIS_ERR;
6363 }
6364 /* Read the bulk write count */
8c4d91fc 6365 if (syncReadLine(fd,buf,1024,3600) == -1) {
ed9b544e 6366 close(fd);
6367 redisLog(REDIS_WARNING,"I/O error reading bulk count from MASTER: %s",
6368 strerror(errno));
6369 return REDIS_ERR;
6370 }
4aa701c1 6371 if (buf[0] != '$') {
6372 close(fd);
6373 redisLog(REDIS_WARNING,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
6374 return REDIS_ERR;
6375 }
c937aa89 6376 dumpsize = atoi(buf+1);
ed9b544e 6377 redisLog(REDIS_NOTICE,"Receiving %d bytes data dump from MASTER",dumpsize);
6378 /* Read the bulk write data on a temp file */
6379 snprintf(tmpfile,256,"temp-%d.%ld.rdb",(int)time(NULL),(long int)random());
6380 dfd = open(tmpfile,O_CREAT|O_WRONLY,0644);
6381 if (dfd == -1) {
6382 close(fd);
6383 redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
6384 return REDIS_ERR;
6385 }
6386 while(dumpsize) {
6387 int nread, nwritten;
6388
6389 nread = read(fd,buf,(dumpsize < 1024)?dumpsize:1024);
6390 if (nread == -1) {
6391 redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
6392 strerror(errno));
6393 close(fd);
6394 close(dfd);
6395 return REDIS_ERR;
6396 }
6397 nwritten = write(dfd,buf,nread);
6398 if (nwritten == -1) {
6399 redisLog(REDIS_WARNING,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
6400 close(fd);
6401 close(dfd);
6402 return REDIS_ERR;
6403 }
6404 dumpsize -= nread;
6405 }
6406 close(dfd);
6407 if (rename(tmpfile,server.dbfilename) == -1) {
6408 redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
6409 unlink(tmpfile);
6410 close(fd);
6411 return REDIS_ERR;
6412 }
6413 emptyDb();
f78fd11b 6414 if (rdbLoad(server.dbfilename) != REDIS_OK) {
ed9b544e 6415 redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
6416 close(fd);
6417 return REDIS_ERR;
6418 }
6419 server.master = createClient(fd);
6420 server.master->flags |= REDIS_MASTER;
179b3952 6421 server.master->authenticated = 1;
ed9b544e 6422 server.replstate = REDIS_REPL_CONNECTED;
6423 return REDIS_OK;
6424}
6425
321b0e13 6426static void slaveofCommand(redisClient *c) {
6427 if (!strcasecmp(c->argv[1]->ptr,"no") &&
6428 !strcasecmp(c->argv[2]->ptr,"one")) {
6429 if (server.masterhost) {
6430 sdsfree(server.masterhost);
6431 server.masterhost = NULL;
6432 if (server.master) freeClient(server.master);
6433 server.replstate = REDIS_REPL_NONE;
6434 redisLog(REDIS_NOTICE,"MASTER MODE enabled (user request)");
6435 }
6436 } else {
6437 sdsfree(server.masterhost);
6438 server.masterhost = sdsdup(c->argv[1]->ptr);
6439 server.masterport = atoi(c->argv[2]->ptr);
6440 if (server.master) freeClient(server.master);
6441 server.replstate = REDIS_REPL_CONNECT;
6442 redisLog(REDIS_NOTICE,"SLAVE OF %s:%d enabled (user request)",
6443 server.masterhost, server.masterport);
6444 }
6445 addReply(c,shared.ok);
6446}
6447
3fd78bcd 6448/* ============================ Maxmemory directive ======================== */
6449
a5819310 6450/* Try to free one object form the pre-allocated objects free list.
6451 * This is useful under low mem conditions as by default we take 1 million
6452 * free objects allocated. On success REDIS_OK is returned, otherwise
6453 * REDIS_ERR. */
6454static int tryFreeOneObjectFromFreelist(void) {
f870935d 6455 robj *o;
6456
a5819310 6457 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
6458 if (listLength(server.objfreelist)) {
6459 listNode *head = listFirst(server.objfreelist);
6460 o = listNodeValue(head);
6461 listDelNode(server.objfreelist,head);
6462 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
6463 zfree(o);
6464 return REDIS_OK;
6465 } else {
6466 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
6467 return REDIS_ERR;
6468 }
f870935d 6469}
6470
3fd78bcd 6471/* This function gets called when 'maxmemory' is set on the config file to limit
6472 * the max memory used by the server, and we are out of memory.
6473 * This function will try to, in order:
6474 *
6475 * - Free objects from the free list
6476 * - Try to remove keys with an EXPIRE set
6477 *
6478 * It is not possible to free enough memory to reach used-memory < maxmemory
6479 * the server will start refusing commands that will enlarge even more the
6480 * memory usage.
6481 */
6482static void freeMemoryIfNeeded(void) {
6483 while (server.maxmemory && zmalloc_used_memory() > server.maxmemory) {
a5819310 6484 int j, k, freed = 0;
6485
6486 if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
6487 for (j = 0; j < server.dbnum; j++) {
6488 int minttl = -1;
6489 robj *minkey = NULL;
6490 struct dictEntry *de;
6491
6492 if (dictSize(server.db[j].expires)) {
6493 freed = 1;
6494 /* From a sample of three keys drop the one nearest to
6495 * the natural expire */
6496 for (k = 0; k < 3; k++) {
6497 time_t t;
6498
6499 de = dictGetRandomKey(server.db[j].expires);
6500 t = (time_t) dictGetEntryVal(de);
6501 if (minttl == -1 || t < minttl) {
6502 minkey = dictGetEntryKey(de);
6503 minttl = t;
3fd78bcd 6504 }
3fd78bcd 6505 }
a5819310 6506 deleteKey(server.db+j,minkey);
3fd78bcd 6507 }
3fd78bcd 6508 }
a5819310 6509 if (!freed) return; /* nothing to free... */
3fd78bcd 6510 }
6511}
6512
f80dff62 6513/* ============================== Append Only file ========================== */
6514
6515static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {
6516 sds buf = sdsempty();
6517 int j;
6518 ssize_t nwritten;
6519 time_t now;
6520 robj *tmpargv[3];
6521
6522 /* The DB this command was targetting is not the same as the last command
6523 * we appendend. To issue a SELECT command is needed. */
6524 if (dictid != server.appendseldb) {
6525 char seldb[64];
6526
6527 snprintf(seldb,sizeof(seldb),"%d",dictid);
682ac724 6528 buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
83c6a618 6529 (unsigned long)strlen(seldb),seldb);
f80dff62 6530 server.appendseldb = dictid;
6531 }
6532
6533 /* "Fix" the argv vector if the command is EXPIRE. We want to translate
6534 * EXPIREs into EXPIREATs calls */
6535 if (cmd->proc == expireCommand) {
6536 long when;
6537
6538 tmpargv[0] = createStringObject("EXPIREAT",8);
6539 tmpargv[1] = argv[1];
6540 incrRefCount(argv[1]);
6541 when = time(NULL)+strtol(argv[2]->ptr,NULL,10);
6542 tmpargv[2] = createObject(REDIS_STRING,
6543 sdscatprintf(sdsempty(),"%ld",when));
6544 argv = tmpargv;
6545 }
6546
6547 /* Append the actual command */
6548 buf = sdscatprintf(buf,"*%d\r\n",argc);
6549 for (j = 0; j < argc; j++) {
6550 robj *o = argv[j];
6551
9d65a1bb 6552 o = getDecodedObject(o);
83c6a618 6553 buf = sdscatprintf(buf,"$%lu\r\n",(unsigned long)sdslen(o->ptr));
f80dff62 6554 buf = sdscatlen(buf,o->ptr,sdslen(o->ptr));
6555 buf = sdscatlen(buf,"\r\n",2);
9d65a1bb 6556 decrRefCount(o);
f80dff62 6557 }
6558
6559 /* Free the objects from the modified argv for EXPIREAT */
6560 if (cmd->proc == expireCommand) {
6561 for (j = 0; j < 3; j++)
6562 decrRefCount(argv[j]);
6563 }
6564
6565 /* We want to perform a single write. This should be guaranteed atomic
6566 * at least if the filesystem we are writing is a real physical one.
6567 * While this will save us against the server being killed I don't think
6568 * there is much to do about the whole server stopping for power problems
6569 * or alike */
6570 nwritten = write(server.appendfd,buf,sdslen(buf));
6571 if (nwritten != (signed)sdslen(buf)) {
6572 /* Ooops, we are in troubles. The best thing to do for now is
6573 * to simply exit instead to give the illusion that everything is
6574 * working as expected. */
6575 if (nwritten == -1) {
6576 redisLog(REDIS_WARNING,"Exiting on error writing to the append-only file: %s",strerror(errno));
6577 } else {
6578 redisLog(REDIS_WARNING,"Exiting on short write while writing to the append-only file: %s",strerror(errno));
6579 }
6580 exit(1);
6581 }
85a83172 6582 /* If a background append only file rewriting is in progress we want to
6583 * accumulate the differences between the child DB and the current one
6584 * in a buffer, so that when the child process will do its work we
6585 * can append the differences to the new append only file. */
6586 if (server.bgrewritechildpid != -1)
6587 server.bgrewritebuf = sdscatlen(server.bgrewritebuf,buf,sdslen(buf));
6588
6589 sdsfree(buf);
f80dff62 6590 now = time(NULL);
6591 if (server.appendfsync == APPENDFSYNC_ALWAYS ||
6592 (server.appendfsync == APPENDFSYNC_EVERYSEC &&
6593 now-server.lastfsync > 1))
6594 {
6595 fsync(server.appendfd); /* Let's try to get this data on the disk */
6596 server.lastfsync = now;
6597 }
6598}
6599
6600/* In Redis commands are always executed in the context of a client, so in
6601 * order to load the append only file we need to create a fake client. */
6602static struct redisClient *createFakeClient(void) {
6603 struct redisClient *c = zmalloc(sizeof(*c));
6604
6605 selectDb(c,0);
6606 c->fd = -1;
6607 c->querybuf = sdsempty();
6608 c->argc = 0;
6609 c->argv = NULL;
6610 c->flags = 0;
9387d17d 6611 /* We set the fake client as a slave waiting for the synchronization
6612 * so that Redis will not try to send replies to this client. */
6613 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
f80dff62 6614 c->reply = listCreate();
6615 listSetFreeMethod(c->reply,decrRefCount);
6616 listSetDupMethod(c->reply,dupClientReplyValue);
6617 return c;
6618}
6619
6620static void freeFakeClient(struct redisClient *c) {
6621 sdsfree(c->querybuf);
6622 listRelease(c->reply);
6623 zfree(c);
6624}
6625
6626/* Replay the append log file. On error REDIS_OK is returned. On non fatal
6627 * error (the append only file is zero-length) REDIS_ERR is returned. On
6628 * fatal error an error message is logged and the program exists. */
6629int loadAppendOnlyFile(char *filename) {
6630 struct redisClient *fakeClient;
6631 FILE *fp = fopen(filename,"r");
6632 struct redis_stat sb;
b492cf00 6633 unsigned long long loadedkeys = 0;
f80dff62 6634
6635 if (redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0)
6636 return REDIS_ERR;
6637
6638 if (fp == NULL) {
6639 redisLog(REDIS_WARNING,"Fatal error: can't open the append log file for reading: %s",strerror(errno));
6640 exit(1);
6641 }
6642
6643 fakeClient = createFakeClient();
6644 while(1) {
6645 int argc, j;
6646 unsigned long len;
6647 robj **argv;
6648 char buf[128];
6649 sds argsds;
6650 struct redisCommand *cmd;
6651
6652 if (fgets(buf,sizeof(buf),fp) == NULL) {
6653 if (feof(fp))
6654 break;
6655 else
6656 goto readerr;
6657 }
6658 if (buf[0] != '*') goto fmterr;
6659 argc = atoi(buf+1);
6660 argv = zmalloc(sizeof(robj*)*argc);
6661 for (j = 0; j < argc; j++) {
6662 if (fgets(buf,sizeof(buf),fp) == NULL) goto readerr;
6663 if (buf[0] != '$') goto fmterr;
6664 len = strtol(buf+1,NULL,10);
6665 argsds = sdsnewlen(NULL,len);
0f151ef1 6666 if (len && fread(argsds,len,1,fp) == 0) goto fmterr;
f80dff62 6667 argv[j] = createObject(REDIS_STRING,argsds);
6668 if (fread(buf,2,1,fp) == 0) goto fmterr; /* discard CRLF */
6669 }
6670
6671 /* Command lookup */
6672 cmd = lookupCommand(argv[0]->ptr);
6673 if (!cmd) {
6674 redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", argv[0]->ptr);
6675 exit(1);
6676 }
6677 /* Try object sharing and encoding */
6678 if (server.shareobjects) {
6679 int j;
6680 for(j = 1; j < argc; j++)
6681 argv[j] = tryObjectSharing(argv[j]);
6682 }
6683 if (cmd->flags & REDIS_CMD_BULK)
6684 tryObjectEncoding(argv[argc-1]);
6685 /* Run the command in the context of a fake client */
6686 fakeClient->argc = argc;
6687 fakeClient->argv = argv;
6688 cmd->proc(fakeClient);
6689 /* Discard the reply objects list from the fake client */
6690 while(listLength(fakeClient->reply))
6691 listDelNode(fakeClient->reply,listFirst(fakeClient->reply));
6692 /* Clean up, ready for the next command */
6693 for (j = 0; j < argc; j++) decrRefCount(argv[j]);
6694 zfree(argv);
b492cf00 6695 /* Handle swapping while loading big datasets when VM is on */
6696 loadedkeys++;
6697 if (server.vm_enabled && (loadedkeys % 5000) == 0) {
6698 while (zmalloc_used_memory() > server.vm_max_memory) {
a69a0c9c 6699 if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
b492cf00 6700 }
6701 }
f80dff62 6702 }
6703 fclose(fp);
6704 freeFakeClient(fakeClient);
6705 return REDIS_OK;
6706
6707readerr:
6708 if (feof(fp)) {
6709 redisLog(REDIS_WARNING,"Unexpected end of file reading the append only file");
6710 } else {
6711 redisLog(REDIS_WARNING,"Unrecoverable error reading the append only file: %s", strerror(errno));
6712 }
6713 exit(1);
6714fmterr:
6715 redisLog(REDIS_WARNING,"Bad file format reading the append only file");
6716 exit(1);
6717}
6718
9d65a1bb 6719/* Write an object into a file in the bulk format $<count>\r\n<payload>\r\n */
6720static int fwriteBulk(FILE *fp, robj *obj) {
6721 char buf[128];
b9bc0eef 6722 int decrrc = 0;
6723
f2d9f50f 6724 /* Avoid the incr/decr ref count business if possible to help
6725 * copy-on-write (we are often in a child process when this function
6726 * is called).
6727 * Also makes sure that key objects don't get incrRefCount-ed when VM
6728 * is enabled */
6729 if (obj->encoding != REDIS_ENCODING_RAW) {
b9bc0eef 6730 obj = getDecodedObject(obj);
6731 decrrc = 1;
6732 }
9d65a1bb 6733 snprintf(buf,sizeof(buf),"$%ld\r\n",(long)sdslen(obj->ptr));
6734 if (fwrite(buf,strlen(buf),1,fp) == 0) goto err;
e96e4fbf 6735 if (sdslen(obj->ptr) && fwrite(obj->ptr,sdslen(obj->ptr),1,fp) == 0)
6736 goto err;
9d65a1bb 6737 if (fwrite("\r\n",2,1,fp) == 0) goto err;
b9bc0eef 6738 if (decrrc) decrRefCount(obj);
9d65a1bb 6739 return 1;
6740err:
b9bc0eef 6741 if (decrrc) decrRefCount(obj);
9d65a1bb 6742 return 0;
6743}
6744
6745/* Write a double value in bulk format $<count>\r\n<payload>\r\n */
6746static int fwriteBulkDouble(FILE *fp, double d) {
6747 char buf[128], dbuf[128];
6748
6749 snprintf(dbuf,sizeof(dbuf),"%.17g\r\n",d);
6750 snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(dbuf)-2);
6751 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
6752 if (fwrite(dbuf,strlen(dbuf),1,fp) == 0) return 0;
6753 return 1;
6754}
6755
6756/* Write a long value in bulk format $<count>\r\n<payload>\r\n */
6757static int fwriteBulkLong(FILE *fp, long l) {
6758 char buf[128], lbuf[128];
6759
6760 snprintf(lbuf,sizeof(lbuf),"%ld\r\n",l);
6761 snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(lbuf)-2);
6762 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
6763 if (fwrite(lbuf,strlen(lbuf),1,fp) == 0) return 0;
6764 return 1;
6765}
6766
6767/* Write a sequence of commands able to fully rebuild the dataset into
6768 * "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
6769static int rewriteAppendOnlyFile(char *filename) {
6770 dictIterator *di = NULL;
6771 dictEntry *de;
6772 FILE *fp;
6773 char tmpfile[256];
6774 int j;
6775 time_t now = time(NULL);
6776
6777 /* Note that we have to use a different temp name here compared to the
6778 * one used by rewriteAppendOnlyFileBackground() function. */
6779 snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid());
6780 fp = fopen(tmpfile,"w");
6781 if (!fp) {
6782 redisLog(REDIS_WARNING, "Failed rewriting the append only file: %s", strerror(errno));
6783 return REDIS_ERR;
6784 }
6785 for (j = 0; j < server.dbnum; j++) {
6786 char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n";
6787 redisDb *db = server.db+j;
6788 dict *d = db->dict;
6789 if (dictSize(d) == 0) continue;
6790 di = dictGetIterator(d);
6791 if (!di) {
6792 fclose(fp);
6793 return REDIS_ERR;
6794 }
6795
6796 /* SELECT the new DB */
6797 if (fwrite(selectcmd,sizeof(selectcmd)-1,1,fp) == 0) goto werr;
85a83172 6798 if (fwriteBulkLong(fp,j) == 0) goto werr;
9d65a1bb 6799
6800 /* Iterate this DB writing every entry */
6801 while((de = dictNext(di)) != NULL) {
e7546c63 6802 robj *key, *o;
6803 time_t expiretime;
6804 int swapped;
6805
6806 key = dictGetEntryKey(de);
b9bc0eef 6807 /* If the value for this key is swapped, load a preview in memory.
6808 * We use a "swapped" flag to remember if we need to free the
6809 * value object instead to just increment the ref count anyway
6810 * in order to avoid copy-on-write of pages if we are forked() */
996cb5f7 6811 if (!server.vm_enabled || key->storage == REDIS_VM_MEMORY ||
6812 key->storage == REDIS_VM_SWAPPING) {
e7546c63 6813 o = dictGetEntryVal(de);
6814 swapped = 0;
6815 } else {
6816 o = vmPreviewObject(key);
e7546c63 6817 swapped = 1;
6818 }
6819 expiretime = getExpire(db,key);
9d65a1bb 6820
6821 /* Save the key and associated value */
9d65a1bb 6822 if (o->type == REDIS_STRING) {
6823 /* Emit a SET command */
6824 char cmd[]="*3\r\n$3\r\nSET\r\n";
6825 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
6826 /* Key and value */
6827 if (fwriteBulk(fp,key) == 0) goto werr;
6828 if (fwriteBulk(fp,o) == 0) goto werr;
6829 } else if (o->type == REDIS_LIST) {
6830 /* Emit the RPUSHes needed to rebuild the list */
6831 list *list = o->ptr;
6832 listNode *ln;
c7df85a4 6833 listIter li;
9d65a1bb 6834
c7df85a4 6835 listRewind(list,&li);
6836 while((ln = listNext(&li))) {
9d65a1bb 6837 char cmd[]="*3\r\n$5\r\nRPUSH\r\n";
6838 robj *eleobj = listNodeValue(ln);
6839
6840 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
6841 if (fwriteBulk(fp,key) == 0) goto werr;
6842 if (fwriteBulk(fp,eleobj) == 0) goto werr;
6843 }
6844 } else if (o->type == REDIS_SET) {
6845 /* Emit the SADDs needed to rebuild the set */
6846 dict *set = o->ptr;
6847 dictIterator *di = dictGetIterator(set);
6848 dictEntry *de;
6849
6850 while((de = dictNext(di)) != NULL) {
6851 char cmd[]="*3\r\n$4\r\nSADD\r\n";
6852 robj *eleobj = dictGetEntryKey(de);
6853
6854 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
6855 if (fwriteBulk(fp,key) == 0) goto werr;
6856 if (fwriteBulk(fp,eleobj) == 0) goto werr;
6857 }
6858 dictReleaseIterator(di);
6859 } else if (o->type == REDIS_ZSET) {
6860 /* Emit the ZADDs needed to rebuild the sorted set */
6861 zset *zs = o->ptr;
6862 dictIterator *di = dictGetIterator(zs->dict);
6863 dictEntry *de;
6864
6865 while((de = dictNext(di)) != NULL) {
6866 char cmd[]="*4\r\n$4\r\nZADD\r\n";
6867 robj *eleobj = dictGetEntryKey(de);
6868 double *score = dictGetEntryVal(de);
6869
6870 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
6871 if (fwriteBulk(fp,key) == 0) goto werr;
6872 if (fwriteBulkDouble(fp,*score) == 0) goto werr;
6873 if (fwriteBulk(fp,eleobj) == 0) goto werr;
6874 }
6875 dictReleaseIterator(di);
6876 } else {
dfc5e96c 6877 redisAssert(0 != 0);
9d65a1bb 6878 }
6879 /* Save the expire time */
6880 if (expiretime != -1) {
e96e4fbf 6881 char cmd[]="*3\r\n$8\r\nEXPIREAT\r\n";
9d65a1bb 6882 /* If this key is already expired skip it */
6883 if (expiretime < now) continue;
6884 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
6885 if (fwriteBulk(fp,key) == 0) goto werr;
6886 if (fwriteBulkLong(fp,expiretime) == 0) goto werr;
6887 }
b9bc0eef 6888 if (swapped) decrRefCount(o);
9d65a1bb 6889 }
6890 dictReleaseIterator(di);
6891 }
6892
6893 /* Make sure data will not remain on the OS's output buffers */
6894 fflush(fp);
6895 fsync(fileno(fp));
6896 fclose(fp);
6897
6898 /* Use RENAME to make sure the DB file is changed atomically only
6899 * if the generate DB file is ok. */
6900 if (rename(tmpfile,filename) == -1) {
6901 redisLog(REDIS_WARNING,"Error moving temp append only file on the final destination: %s", strerror(errno));
6902 unlink(tmpfile);
6903 return REDIS_ERR;
6904 }
6905 redisLog(REDIS_NOTICE,"SYNC append only file rewrite performed");
6906 return REDIS_OK;
6907
6908werr:
6909 fclose(fp);
6910 unlink(tmpfile);
e96e4fbf 6911 redisLog(REDIS_WARNING,"Write error writing append only file on disk: %s", strerror(errno));
9d65a1bb 6912 if (di) dictReleaseIterator(di);
6913 return REDIS_ERR;
6914}
6915
6916/* This is how rewriting of the append only file in background works:
6917 *
6918 * 1) The user calls BGREWRITEAOF
6919 * 2) Redis calls this function, that forks():
6920 * 2a) the child rewrite the append only file in a temp file.
6921 * 2b) the parent accumulates differences in server.bgrewritebuf.
6922 * 3) When the child finished '2a' exists.
6923 * 4) The parent will trap the exit code, if it's OK, will append the
6924 * data accumulated into server.bgrewritebuf into the temp file, and
6925 * finally will rename(2) the temp file in the actual file name.
6926 * The the new file is reopened as the new append only file. Profit!
6927 */
6928static int rewriteAppendOnlyFileBackground(void) {
6929 pid_t childpid;
6930
6931 if (server.bgrewritechildpid != -1) return REDIS_ERR;
054e426d 6932 if (server.vm_enabled) waitEmptyIOJobsQueue();
9d65a1bb 6933 if ((childpid = fork()) == 0) {
6934 /* Child */
6935 char tmpfile[256];
9d65a1bb 6936
054e426d 6937 if (server.vm_enabled) vmReopenSwapFile();
6938 close(server.fd);
9d65a1bb 6939 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
6940 if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
6941 exit(0);
6942 } else {
6943 exit(1);
6944 }
6945 } else {
6946 /* Parent */
6947 if (childpid == -1) {
6948 redisLog(REDIS_WARNING,
6949 "Can't rewrite append only file in background: fork: %s",
6950 strerror(errno));
6951 return REDIS_ERR;
6952 }
6953 redisLog(REDIS_NOTICE,
6954 "Background append only file rewriting started by pid %d",childpid);
6955 server.bgrewritechildpid = childpid;
85a83172 6956 /* We set appendseldb to -1 in order to force the next call to the
6957 * feedAppendOnlyFile() to issue a SELECT command, so the differences
6958 * accumulated by the parent into server.bgrewritebuf will start
6959 * with a SELECT statement and it will be safe to merge. */
6960 server.appendseldb = -1;
9d65a1bb 6961 return REDIS_OK;
6962 }
6963 return REDIS_OK; /* unreached */
6964}
6965
6966static void bgrewriteaofCommand(redisClient *c) {
6967 if (server.bgrewritechildpid != -1) {
6968 addReplySds(c,sdsnew("-ERR background append only file rewriting already in progress\r\n"));
6969 return;
6970 }
6971 if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
49b99ab4 6972 char *status = "+Background append only file rewriting started\r\n";
6973 addReplySds(c,sdsnew(status));
9d65a1bb 6974 } else {
6975 addReply(c,shared.err);
6976 }
6977}
6978
6979static void aofRemoveTempFile(pid_t childpid) {
6980 char tmpfile[256];
6981
6982 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) childpid);
6983 unlink(tmpfile);
6984}
6985
996cb5f7 6986/* Virtual Memory is composed mainly of two subsystems:
6987 * - Blocking Virutal Memory
6988 * - Threaded Virtual Memory I/O
6989 * The two parts are not fully decoupled, but functions are split among two
6990 * different sections of the source code (delimited by comments) in order to
6991 * make more clear what functionality is about the blocking VM and what about
6992 * the threaded (not blocking) VM.
6993 *
6994 * Redis VM design:
6995 *
6996 * Redis VM is a blocking VM (one that blocks reading swapped values from
6997 * disk into memory when a value swapped out is needed in memory) that is made
6998 * unblocking by trying to examine the command argument vector in order to
6999 * load in background values that will likely be needed in order to exec
7000 * the command. The command is executed only once all the relevant keys
7001 * are loaded into memory.
7002 *
7003 * This basically is almost as simple of a blocking VM, but almost as parallel
7004 * as a fully non-blocking VM.
7005 */
7006
7007/* =================== Virtual Memory - Blocking Side ====================== */
054e426d 7008
7009/* substitute the first occurrence of '%p' with the process pid in the
7010 * swap file name. */
7011static void expandVmSwapFilename(void) {
7012 char *p = strstr(server.vm_swap_file,"%p");
7013 sds new;
7014
7015 if (!p) return;
7016 new = sdsempty();
7017 *p = '\0';
7018 new = sdscat(new,server.vm_swap_file);
7019 new = sdscatprintf(new,"%ld",(long) getpid());
7020 new = sdscat(new,p+2);
7021 zfree(server.vm_swap_file);
7022 server.vm_swap_file = new;
7023}
7024
75680a3c 7025static void vmInit(void) {
7026 off_t totsize;
996cb5f7 7027 int pipefds[2];
bcaa7a4f 7028 size_t stacksize;
75680a3c 7029
4ad37480 7030 if (server.vm_max_threads != 0)
7031 zmalloc_enable_thread_safeness(); /* we need thread safe zmalloc() */
7032
054e426d 7033 expandVmSwapFilename();
7034 redisLog(REDIS_NOTICE,"Using '%s' as swap file",server.vm_swap_file);
6fa987e3 7035 if ((server.vm_fp = fopen(server.vm_swap_file,"r+b")) == NULL) {
7036 server.vm_fp = fopen(server.vm_swap_file,"w+b");
7037 }
75680a3c 7038 if (server.vm_fp == NULL) {
6fa987e3 7039 redisLog(REDIS_WARNING,
7040 "Impossible to open the swap file: %s. Exiting.",
7041 strerror(errno));
75680a3c 7042 exit(1);
7043 }
7044 server.vm_fd = fileno(server.vm_fp);
7045 server.vm_next_page = 0;
7046 server.vm_near_pages = 0;
7d98e08c 7047 server.vm_stats_used_pages = 0;
7048 server.vm_stats_swapped_objects = 0;
7049 server.vm_stats_swapouts = 0;
7050 server.vm_stats_swapins = 0;
75680a3c 7051 totsize = server.vm_pages*server.vm_page_size;
7052 redisLog(REDIS_NOTICE,"Allocating %lld bytes of swap file",totsize);
7053 if (ftruncate(server.vm_fd,totsize) == -1) {
7054 redisLog(REDIS_WARNING,"Can't ftruncate swap file: %s. Exiting.",
7055 strerror(errno));
7056 exit(1);
7057 } else {
7058 redisLog(REDIS_NOTICE,"Swap file allocated with success");
7059 }
7d30035d 7060 server.vm_bitmap = zmalloc((server.vm_pages+7)/8);
f870935d 7061 redisLog(REDIS_VERBOSE,"Allocated %lld bytes page table for %lld pages",
4ef8de8a 7062 (long long) (server.vm_pages+7)/8, server.vm_pages);
7d30035d 7063 memset(server.vm_bitmap,0,(server.vm_pages+7)/8);
92f8e882 7064
996cb5f7 7065 /* Initialize threaded I/O (used by Virtual Memory) */
7066 server.io_newjobs = listCreate();
7067 server.io_processing = listCreate();
7068 server.io_processed = listCreate();
92f8e882 7069 server.io_clients = listCreate();
7070 pthread_mutex_init(&server.io_mutex,NULL);
a5819310 7071 pthread_mutex_init(&server.obj_freelist_mutex,NULL);
7072 pthread_mutex_init(&server.io_swapfile_mutex,NULL);
92f8e882 7073 server.io_active_threads = 0;
996cb5f7 7074 if (pipe(pipefds) == -1) {
7075 redisLog(REDIS_WARNING,"Unable to intialized VM: pipe(2): %s. Exiting."
7076 ,strerror(errno));
7077 exit(1);
7078 }
7079 server.io_ready_pipe_read = pipefds[0];
7080 server.io_ready_pipe_write = pipefds[1];
7081 redisAssert(anetNonBlock(NULL,server.io_ready_pipe_read) != ANET_ERR);
bcaa7a4f 7082 /* LZF requires a lot of stack */
7083 pthread_attr_init(&server.io_threads_attr);
7084 pthread_attr_getstacksize(&server.io_threads_attr, &stacksize);
7085 while (stacksize < REDIS_THREAD_STACK_SIZE) stacksize *= 2;
7086 pthread_attr_setstacksize(&server.io_threads_attr, stacksize);
b9bc0eef 7087 /* Listen for events in the threaded I/O pipe */
7088 if (aeCreateFileEvent(server.el, server.io_ready_pipe_read, AE_READABLE,
7089 vmThreadedIOCompletedJob, NULL) == AE_ERR)
7090 oom("creating file event");
75680a3c 7091}
7092
06224fec 7093/* Mark the page as used */
7094static void vmMarkPageUsed(off_t page) {
7095 off_t byte = page/8;
7096 int bit = page&7;
970e10bb 7097 redisAssert(vmFreePage(page) == 1);
06224fec 7098 server.vm_bitmap[byte] |= 1<<bit;
f870935d 7099 redisLog(REDIS_DEBUG,"Mark used: %lld (byte:%lld bit:%d)\n",
7100 (long long)page, (long long)byte, bit);
06224fec 7101}
7102
7103/* Mark N contiguous pages as used, with 'page' being the first. */
7104static void vmMarkPagesUsed(off_t page, off_t count) {
7105 off_t j;
7106
7107 for (j = 0; j < count; j++)
7d30035d 7108 vmMarkPageUsed(page+j);
7d98e08c 7109 server.vm_stats_used_pages += count;
06224fec 7110}
7111
7112/* Mark the page as free */
7113static void vmMarkPageFree(off_t page) {
7114 off_t byte = page/8;
7115 int bit = page&7;
970e10bb 7116 redisAssert(vmFreePage(page) == 0);
06224fec 7117 server.vm_bitmap[byte] &= ~(1<<bit);
970e10bb 7118 redisLog(REDIS_DEBUG,"Mark free: %lld (byte:%lld bit:%d)\n",
7119 (long long)page, (long long)byte, bit);
06224fec 7120}
7121
7122/* Mark N contiguous pages as free, with 'page' being the first. */
7123static void vmMarkPagesFree(off_t page, off_t count) {
7124 off_t j;
7125
7126 for (j = 0; j < count; j++)
7d30035d 7127 vmMarkPageFree(page+j);
7d98e08c 7128 server.vm_stats_used_pages -= count;
970e10bb 7129 if (server.vm_stats_used_pages > 100000000) {
7130 *((char*)-1) = 'x';
7131 }
06224fec 7132}
7133
7134/* Test if the page is free */
7135static int vmFreePage(off_t page) {
7136 off_t byte = page/8;
7137 int bit = page&7;
7d30035d 7138 return (server.vm_bitmap[byte] & (1<<bit)) == 0;
06224fec 7139}
7140
7141/* Find N contiguous free pages storing the first page of the cluster in *first.
3a66edc7 7142 * Returns REDIS_OK if it was able to find N contiguous pages, otherwise
7143 * REDIS_ERR is returned.
06224fec 7144 *
7145 * This function uses a simple algorithm: we try to allocate
7146 * REDIS_VM_MAX_NEAR_PAGES sequentially, when we reach this limit we start
7147 * again from the start of the swap file searching for free spaces.
7148 *
7149 * If it looks pretty clear that there are no free pages near our offset
7150 * we try to find less populated places doing a forward jump of
7151 * REDIS_VM_MAX_RANDOM_JUMP, then we start scanning again a few pages
7152 * without hurry, and then we jump again and so forth...
7153 *
7154 * This function can be improved using a free list to avoid to guess
7155 * too much, since we could collect data about freed pages.
7156 *
7157 * note: I implemented this function just after watching an episode of
7158 * Battlestar Galactica, where the hybrid was continuing to say "JUMP!"
7159 */
c7df85a4 7160static int vmFindContiguousPages(off_t *first, off_t n) {
06224fec 7161 off_t base, offset = 0, since_jump = 0, numfree = 0;
7162
7163 if (server.vm_near_pages == REDIS_VM_MAX_NEAR_PAGES) {
7164 server.vm_near_pages = 0;
7165 server.vm_next_page = 0;
7166 }
7167 server.vm_near_pages++; /* Yet another try for pages near to the old ones */
7168 base = server.vm_next_page;
7169
7170 while(offset < server.vm_pages) {
7171 off_t this = base+offset;
7172
7173 /* If we overflow, restart from page zero */
7174 if (this >= server.vm_pages) {
7175 this -= server.vm_pages;
7176 if (this == 0) {
7177 /* Just overflowed, what we found on tail is no longer
7178 * interesting, as it's no longer contiguous. */
7179 numfree = 0;
7180 }
7181 }
f6c0bba8 7182 redisLog(REDIS_DEBUG, "THIS: %lld (%c)\n", (long long) this, vmFreePage(this) ? 'F' : 'X');
06224fec 7183 if (vmFreePage(this)) {
7184 /* This is a free page */
7185 numfree++;
7186 /* Already got N free pages? Return to the caller, with success */
7187 if (numfree == n) {
7d30035d 7188 *first = this-(n-1);
7189 server.vm_next_page = this+1;
3a66edc7 7190 return REDIS_OK;
06224fec 7191 }
7192 } else {
7193 /* The current one is not a free page */
7194 numfree = 0;
7195 }
7196
7197 /* Fast-forward if the current page is not free and we already
7198 * searched enough near this place. */
7199 since_jump++;
7200 if (!numfree && since_jump >= REDIS_VM_MAX_RANDOM_JUMP/4) {
7201 offset += random() % REDIS_VM_MAX_RANDOM_JUMP;
7202 since_jump = 0;
7203 /* Note that even if we rewind after the jump, we are don't need
7204 * to make sure numfree is set to zero as we only jump *if* it
7205 * is set to zero. */
7206 } else {
7207 /* Otherwise just check the next page */
7208 offset++;
7209 }
7210 }
3a66edc7 7211 return REDIS_ERR;
7212}
7213
a5819310 7214/* Write the specified object at the specified page of the swap file */
7215static int vmWriteObjectOnSwap(robj *o, off_t page) {
7216 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
7217 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
7218 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
7219 redisLog(REDIS_WARNING,
7220 "Critical VM problem in vmSwapObjectBlocking(): can't seek: %s",
7221 strerror(errno));
7222 return REDIS_ERR;
7223 }
7224 rdbSaveObject(server.vm_fp,o);
7225 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
7226 return REDIS_OK;
7227}
7228
3a66edc7 7229/* Swap the 'val' object relative to 'key' into disk. Store all the information
7230 * needed to later retrieve the object into the key object.
7231 * If we can't find enough contiguous empty pages to swap the object on disk
7232 * REDIS_ERR is returned. */
a69a0c9c 7233static int vmSwapObjectBlocking(robj *key, robj *val) {
b9bc0eef 7234 off_t pages = rdbSavedObjectPages(val,NULL);
3a66edc7 7235 off_t page;
7236
7237 assert(key->storage == REDIS_VM_MEMORY);
4ef8de8a 7238 assert(key->refcount == 1);
3a66edc7 7239 if (vmFindContiguousPages(&page,pages) == REDIS_ERR) return REDIS_ERR;
a5819310 7240 if (vmWriteObjectOnSwap(val,page) == REDIS_ERR) return REDIS_ERR;
3a66edc7 7241 key->vm.page = page;
7242 key->vm.usedpages = pages;
7243 key->storage = REDIS_VM_SWAPPED;
d894161b 7244 key->vtype = val->type;
3a66edc7 7245 decrRefCount(val); /* Deallocate the object from memory. */
7246 vmMarkPagesUsed(page,pages);
7d30035d 7247 redisLog(REDIS_DEBUG,"VM: object %s swapped out at %lld (%lld pages)",
7248 (unsigned char*) key->ptr,
7249 (unsigned long long) page, (unsigned long long) pages);
7d98e08c 7250 server.vm_stats_swapped_objects++;
7251 server.vm_stats_swapouts++;
0841cc92 7252 fflush(server.vm_fp);
3a66edc7 7253 return REDIS_OK;
7254}
7255
a5819310 7256static robj *vmReadObjectFromSwap(off_t page, int type) {
7257 robj *o;
3a66edc7 7258
a5819310 7259 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
7260 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
3a66edc7 7261 redisLog(REDIS_WARNING,
7262 "Unrecoverable VM problem in vmLoadObject(): can't seek: %s",
7263 strerror(errno));
7264 exit(1);
7265 }
a5819310 7266 o = rdbLoadObject(type,server.vm_fp);
7267 if (o == NULL) {
3a66edc7 7268 redisLog(REDIS_WARNING, "Unrecoverable VM problem in vmLoadObject(): can't load object from swap file: %s", strerror(errno));
7269 exit(1);
7270 }
a5819310 7271 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
7272 return o;
7273}
7274
7275/* Load the value object relative to the 'key' object from swap to memory.
7276 * The newly allocated object is returned.
7277 *
7278 * If preview is true the unserialized object is returned to the caller but
7279 * no changes are made to the key object, nor the pages are marked as freed */
7280static robj *vmGenericLoadObject(robj *key, int preview) {
7281 robj *val;
7282
7283 redisAssert(key->storage == REDIS_VM_SWAPPED);
7284 val = vmReadObjectFromSwap(key->vm.page,key->vtype);
7e69548d 7285 if (!preview) {
7286 key->storage = REDIS_VM_MEMORY;
7287 key->vm.atime = server.unixtime;
7288 vmMarkPagesFree(key->vm.page,key->vm.usedpages);
7289 redisLog(REDIS_DEBUG, "VM: object %s loaded from disk",
7290 (unsigned char*) key->ptr);
7d98e08c 7291 server.vm_stats_swapped_objects--;
38aba9a1 7292 } else {
7293 redisLog(REDIS_DEBUG, "VM: object %s previewed from disk",
7294 (unsigned char*) key->ptr);
7e69548d 7295 }
7d98e08c 7296 server.vm_stats_swapins++;
3a66edc7 7297 return val;
06224fec 7298}
7299
7e69548d 7300/* Plain object loading, from swap to memory */
7301static robj *vmLoadObject(robj *key) {
996cb5f7 7302 /* If we are loading the object in background, stop it, we
7303 * need to load this object synchronously ASAP. */
7304 if (key->storage == REDIS_VM_LOADING)
7305 vmCancelThreadedIOJob(key);
7e69548d 7306 return vmGenericLoadObject(key,0);
7307}
7308
7309/* Just load the value on disk, without to modify the key.
7310 * This is useful when we want to perform some operation on the value
7311 * without to really bring it from swap to memory, like while saving the
7312 * dataset or rewriting the append only log. */
7313static robj *vmPreviewObject(robj *key) {
7314 return vmGenericLoadObject(key,1);
7315}
7316
4ef8de8a 7317/* How a good candidate is this object for swapping?
7318 * The better candidate it is, the greater the returned value.
7319 *
7320 * Currently we try to perform a fast estimation of the object size in
7321 * memory, and combine it with aging informations.
7322 *
7323 * Basically swappability = idle-time * log(estimated size)
7324 *
7325 * Bigger objects are preferred over smaller objects, but not
7326 * proportionally, this is why we use the logarithm. This algorithm is
7327 * just a first try and will probably be tuned later. */
7328static double computeObjectSwappability(robj *o) {
7329 time_t age = server.unixtime - o->vm.atime;
7330 long asize = 0;
7331 list *l;
7332 dict *d;
7333 struct dictEntry *de;
7334 int z;
7335
7336 if (age <= 0) return 0;
7337 switch(o->type) {
7338 case REDIS_STRING:
7339 if (o->encoding != REDIS_ENCODING_RAW) {
7340 asize = sizeof(*o);
7341 } else {
7342 asize = sdslen(o->ptr)+sizeof(*o)+sizeof(long)*2;
7343 }
7344 break;
7345 case REDIS_LIST:
7346 l = o->ptr;
7347 listNode *ln = listFirst(l);
7348
7349 asize = sizeof(list);
7350 if (ln) {
7351 robj *ele = ln->value;
7352 long elesize;
7353
7354 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
7355 (sizeof(*o)+sdslen(ele->ptr)) :
7356 sizeof(*o);
7357 asize += (sizeof(listNode)+elesize)*listLength(l);
7358 }
7359 break;
7360 case REDIS_SET:
7361 case REDIS_ZSET:
7362 z = (o->type == REDIS_ZSET);
7363 d = z ? ((zset*)o->ptr)->dict : o->ptr;
7364
7365 asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
7366 if (z) asize += sizeof(zset)-sizeof(dict);
7367 if (dictSize(d)) {
7368 long elesize;
7369 robj *ele;
7370
7371 de = dictGetRandomKey(d);
7372 ele = dictGetEntryKey(de);
7373 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
7374 (sizeof(*o)+sdslen(ele->ptr)) :
7375 sizeof(*o);
7376 asize += (sizeof(struct dictEntry)+elesize)*dictSize(d);
7377 if (z) asize += sizeof(zskiplistNode)*dictSize(d);
7378 }
7379 break;
7380 }
7381 return (double)asize*log(1+asize);
7382}
7383
7384/* Try to swap an object that's a good candidate for swapping.
7385 * Returns REDIS_OK if the object was swapped, REDIS_ERR if it's not possible
a69a0c9c 7386 * to swap any object at all.
7387 *
7388 * If 'usethreaded' is true, Redis will try to swap the object in background
7389 * using I/O threads. */
7390static int vmSwapOneObject(int usethreads) {
4ef8de8a 7391 int j, i;
7392 struct dictEntry *best = NULL;
7393 double best_swappability = 0;
b9bc0eef 7394 redisDb *best_db = NULL;
4ef8de8a 7395 robj *key, *val;
7396
7397 for (j = 0; j < server.dbnum; j++) {
7398 redisDb *db = server.db+j;
b0d8747d 7399 int maxtries = 100;
4ef8de8a 7400
7401 if (dictSize(db->dict) == 0) continue;
7402 for (i = 0; i < 5; i++) {
7403 dictEntry *de;
7404 double swappability;
7405
e3cadb8a 7406 if (maxtries) maxtries--;
4ef8de8a 7407 de = dictGetRandomKey(db->dict);
7408 key = dictGetEntryKey(de);
7409 val = dictGetEntryVal(de);
1064ef87 7410 /* Only swap objects that are currently in memory.
7411 *
7412 * Also don't swap shared objects if threaded VM is on, as we
7413 * try to ensure that the main thread does not touch the
7414 * object while the I/O thread is using it, but we can't
7415 * control other keys without adding additional mutex. */
7416 if (key->storage != REDIS_VM_MEMORY ||
7417 (server.vm_max_threads != 0 && val->refcount != 1)) {
e3cadb8a 7418 if (maxtries) i--; /* don't count this try */
7419 continue;
7420 }
4ef8de8a 7421 swappability = computeObjectSwappability(val);
7422 if (!best || swappability > best_swappability) {
7423 best = de;
7424 best_swappability = swappability;
b9bc0eef 7425 best_db = db;
4ef8de8a 7426 }
7427 }
7428 }
e3cadb8a 7429 if (best == NULL) {
7430 redisLog(REDIS_DEBUG,"No swappable key found!");
7431 return REDIS_ERR;
7432 }
4ef8de8a 7433 key = dictGetEntryKey(best);
7434 val = dictGetEntryVal(best);
7435
e3cadb8a 7436 redisLog(REDIS_DEBUG,"Key with best swappability: %s, %f",
4ef8de8a 7437 key->ptr, best_swappability);
7438
7439 /* Unshare the key if needed */
7440 if (key->refcount > 1) {
7441 robj *newkey = dupStringObject(key);
7442 decrRefCount(key);
7443 key = dictGetEntryKey(best) = newkey;
7444 }
7445 /* Swap it */
a69a0c9c 7446 if (usethreads) {
b9bc0eef 7447 vmSwapObjectThreaded(key,val,best_db);
4ef8de8a 7448 return REDIS_OK;
7449 } else {
a69a0c9c 7450 if (vmSwapObjectBlocking(key,val) == REDIS_OK) {
7451 dictGetEntryVal(best) = NULL;
7452 return REDIS_OK;
7453 } else {
7454 return REDIS_ERR;
7455 }
4ef8de8a 7456 }
7457}
7458
a69a0c9c 7459static int vmSwapOneObjectBlocking() {
7460 return vmSwapOneObject(0);
7461}
7462
7463static int vmSwapOneObjectThreaded() {
7464 return vmSwapOneObject(1);
7465}
7466
7e69548d 7467/* Return true if it's safe to swap out objects in a given moment.
7468 * Basically we don't want to swap objects out while there is a BGSAVE
7469 * or a BGAEOREWRITE running in backgroud. */
7470static int vmCanSwapOut(void) {
7471 return (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1);
7472}
7473
1b03836c 7474/* Delete a key if swapped. Returns 1 if the key was found, was swapped
7475 * and was deleted. Otherwise 0 is returned. */
7476static int deleteIfSwapped(redisDb *db, robj *key) {
7477 dictEntry *de;
7478 robj *foundkey;
7479
7480 if ((de = dictFind(db->dict,key)) == NULL) return 0;
7481 foundkey = dictGetEntryKey(de);
7482 if (foundkey->storage == REDIS_VM_MEMORY) return 0;
7483 deleteKey(db,key);
7484 return 1;
7485}
7486
996cb5f7 7487/* =================== Virtual Memory - Threaded I/O ======================= */
7488
b9bc0eef 7489static void freeIOJob(iojob *j) {
7490 if (j->type == REDIS_IOJOB_PREPARE_SWAP ||
7491 j->type == REDIS_IOJOB_DO_SWAP)
7492 decrRefCount(j->val);
7493 decrRefCount(j->key);
7494 zfree(j);
7495}
7496
996cb5f7 7497/* Every time a thread finished a Job, it writes a byte into the write side
7498 * of an unix pipe in order to "awake" the main thread, and this function
7499 * is called. */
7500static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
7501 int mask)
7502{
7503 char buf[1];
b0d8747d 7504 int retval, processed = 0, toprocess = -1, trytoswap = 1;
996cb5f7 7505 REDIS_NOTUSED(el);
7506 REDIS_NOTUSED(mask);
7507 REDIS_NOTUSED(privdata);
7508
7509 /* For every byte we read in the read side of the pipe, there is one
7510 * I/O job completed to process. */
7511 while((retval = read(fd,buf,1)) == 1) {
b9bc0eef 7512 iojob *j;
7513 listNode *ln;
7514 robj *key;
7515 struct dictEntry *de;
7516
996cb5f7 7517 redisLog(REDIS_DEBUG,"Processing I/O completed job");
b9bc0eef 7518
7519 /* Get the processed element (the oldest one) */
7520 lockThreadedIO();
1064ef87 7521 assert(listLength(server.io_processed) != 0);
f6c0bba8 7522 if (toprocess == -1) {
7523 toprocess = (listLength(server.io_processed)*REDIS_MAX_COMPLETED_JOBS_PROCESSED)/100;
7524 if (toprocess <= 0) toprocess = 1;
7525 }
b9bc0eef 7526 ln = listFirst(server.io_processed);
7527 j = ln->value;
7528 listDelNode(server.io_processed,ln);
7529 unlockThreadedIO();
7530 /* If this job is marked as canceled, just ignore it */
7531 if (j->canceled) {
7532 freeIOJob(j);
7533 continue;
7534 }
7535 /* Post process it in the main thread, as there are things we
7536 * can do just here to avoid race conditions and/or invasive locks */
6c96ba7d 7537 redisLog(REDIS_DEBUG,"Job %p type: %d, key at %p (%s) refcount: %d\n", (void*) j, j->type, (void*)j->key, (char*)j->key->ptr, j->key->refcount);
b9bc0eef 7538 de = dictFind(j->db->dict,j->key);
7539 assert(de != NULL);
7540 key = dictGetEntryKey(de);
7541 if (j->type == REDIS_IOJOB_LOAD) {
7542 /* Key loaded, bring it at home */
7543 key->storage = REDIS_VM_MEMORY;
7544 key->vm.atime = server.unixtime;
7545 vmMarkPagesFree(key->vm.page,key->vm.usedpages);
7546 redisLog(REDIS_DEBUG, "VM: object %s loaded from disk (threaded)",
7547 (unsigned char*) key->ptr);
7548 server.vm_stats_swapped_objects--;
7549 server.vm_stats_swapins++;
7550 freeIOJob(j);
7551 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
7552 /* Now we know the amount of pages required to swap this object.
7553 * Let's find some space for it, and queue this task again
7554 * rebranded as REDIS_IOJOB_DO_SWAP. */
054e426d 7555 if (!vmCanSwapOut() ||
7556 vmFindContiguousPages(&j->page,j->pages) == REDIS_ERR)
7557 {
7558 /* Ooops... no space or we can't swap as there is
7559 * a fork()ed Redis trying to save stuff on disk. */
b9bc0eef 7560 freeIOJob(j);
054e426d 7561 key->storage = REDIS_VM_MEMORY; /* undo operation */
b9bc0eef 7562 } else {
c7df85a4 7563 /* Note that we need to mark this pages as used now,
7564 * if the job will be canceled, we'll mark them as freed
7565 * again. */
7566 vmMarkPagesUsed(j->page,j->pages);
b9bc0eef 7567 j->type = REDIS_IOJOB_DO_SWAP;
7568 lockThreadedIO();
7569 queueIOJob(j);
7570 unlockThreadedIO();
7571 }
7572 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
7573 robj *val;
7574
7575 /* Key swapped. We can finally free some memory. */
6c96ba7d 7576 if (key->storage != REDIS_VM_SWAPPING) {
7577 printf("key->storage: %d\n",key->storage);
7578 printf("key->name: %s\n",(char*)key->ptr);
7579 printf("key->refcount: %d\n",key->refcount);
7580 printf("val: %p\n",(void*)j->val);
7581 printf("val->type: %d\n",j->val->type);
7582 printf("val->ptr: %s\n",(char*)j->val->ptr);
7583 }
7584 redisAssert(key->storage == REDIS_VM_SWAPPING);
b9bc0eef 7585 val = dictGetEntryVal(de);
7586 key->vm.page = j->page;
7587 key->vm.usedpages = j->pages;
7588 key->storage = REDIS_VM_SWAPPED;
7589 key->vtype = j->val->type;
7590 decrRefCount(val); /* Deallocate the object from memory. */
f11b8647 7591 dictGetEntryVal(de) = NULL;
b9bc0eef 7592 redisLog(REDIS_DEBUG,
7593 "VM: object %s swapped out at %lld (%lld pages) (threaded)",
7594 (unsigned char*) key->ptr,
7595 (unsigned long long) j->page, (unsigned long long) j->pages);
7596 server.vm_stats_swapped_objects++;
7597 server.vm_stats_swapouts++;
7598 freeIOJob(j);
f11b8647 7599 /* Put a few more swap requests in queue if we are still
7600 * out of memory */
b0d8747d 7601 if (trytoswap && vmCanSwapOut() &&
7602 zmalloc_used_memory() > server.vm_max_memory)
7603 {
f11b8647 7604 int more = 1;
7605 while(more) {
7606 lockThreadedIO();
7607 more = listLength(server.io_newjobs) <
7608 (unsigned) server.vm_max_threads;
7609 unlockThreadedIO();
7610 /* Don't waste CPU time if swappable objects are rare. */
b0d8747d 7611 if (vmSwapOneObjectThreaded() == REDIS_ERR) {
7612 trytoswap = 0;
7613 break;
7614 }
f11b8647 7615 }
7616 }
b9bc0eef 7617 }
c953f24b 7618 processed++;
f6c0bba8 7619 if (processed == toprocess) return;
996cb5f7 7620 }
7621 if (retval < 0 && errno != EAGAIN) {
7622 redisLog(REDIS_WARNING,
7623 "WARNING: read(2) error in vmThreadedIOCompletedJob() %s",
7624 strerror(errno));
7625 }
7626}
7627
7628static void lockThreadedIO(void) {
7629 pthread_mutex_lock(&server.io_mutex);
7630}
7631
7632static void unlockThreadedIO(void) {
7633 pthread_mutex_unlock(&server.io_mutex);
7634}
7635
7636/* Remove the specified object from the threaded I/O queue if still not
7637 * processed, otherwise make sure to flag it as canceled. */
7638static void vmCancelThreadedIOJob(robj *o) {
7639 list *lists[3] = {
6c96ba7d 7640 server.io_newjobs, /* 0 */
7641 server.io_processing, /* 1 */
7642 server.io_processed /* 2 */
996cb5f7 7643 };
7644 int i;
7645
7646 assert(o->storage == REDIS_VM_LOADING || o->storage == REDIS_VM_SWAPPING);
2e111efe 7647again:
996cb5f7 7648 lockThreadedIO();
7649 /* Search for a matching key in one of the queues */
7650 for (i = 0; i < 3; i++) {
7651 listNode *ln;
c7df85a4 7652 listIter li;
996cb5f7 7653
c7df85a4 7654 listRewind(lists[i],&li);
7655 while ((ln = listNext(&li)) != NULL) {
996cb5f7 7656 iojob *job = ln->value;
7657
6c96ba7d 7658 if (job->canceled) continue; /* Skip this, already canceled. */
996cb5f7 7659 if (compareStringObjects(job->key,o) == 0) {
970e10bb 7660 redisLog(REDIS_DEBUG,"*** CANCELED %p (%s) (type %d) (LIST ID %d)\n",
7661 (void*)job, (char*)o->ptr, job->type, i);
427a2153 7662 /* Mark the pages as free since the swap didn't happened
7663 * or happened but is now discarded. */
970e10bb 7664 if (i != 1 && job->type == REDIS_IOJOB_DO_SWAP)
427a2153 7665 vmMarkPagesFree(job->page,job->pages);
7666 /* Cancel the job. It depends on the list the job is
7667 * living in. */
996cb5f7 7668 switch(i) {
7669 case 0: /* io_newjobs */
6c96ba7d 7670 /* If the job was yet not processed the best thing to do
996cb5f7 7671 * is to remove it from the queue at all */
6c96ba7d 7672 freeIOJob(job);
996cb5f7 7673 listDelNode(lists[i],ln);
7674 break;
7675 case 1: /* io_processing */
2e111efe 7676 /* Oh Shi- the thread is messing with the Job, and
7677 * probably with the object if this is a
7678 * PREPARE_SWAP or DO_SWAP job. Better to wait for the
7679 * job to move into the next queue... */
7680 if (job->type != REDIS_IOJOB_LOAD) {
7681 /* Yes, we try again and again until the job
7682 * is completed. */
7683 unlockThreadedIO();
7684 /* But let's wait some time for the I/O thread
7685 * to finish with this job. After all this condition
7686 * should be very rare. */
7687 usleep(1);
7688 goto again;
7689 } else {
7690 job->canceled = 1;
7691 break;
7692 }
996cb5f7 7693 case 2: /* io_processed */
2e111efe 7694 /* The job was already processed, that's easy...
7695 * just mark it as canceled so that we'll ignore it
7696 * when processing completed jobs. */
996cb5f7 7697 job->canceled = 1;
7698 break;
7699 }
c7df85a4 7700 /* Finally we have to adjust the storage type of the object
7701 * in order to "UNDO" the operaiton. */
996cb5f7 7702 if (o->storage == REDIS_VM_LOADING)
7703 o->storage = REDIS_VM_SWAPPED;
7704 else if (o->storage == REDIS_VM_SWAPPING)
7705 o->storage = REDIS_VM_MEMORY;
7706 unlockThreadedIO();
7707 return;
7708 }
7709 }
7710 }
7711 unlockThreadedIO();
7712 assert(1 != 1); /* We should never reach this */
7713}
7714
b9bc0eef 7715static void *IOThreadEntryPoint(void *arg) {
7716 iojob *j;
7717 listNode *ln;
7718 REDIS_NOTUSED(arg);
7719
7720 pthread_detach(pthread_self());
7721 while(1) {
7722 /* Get a new job to process */
7723 lockThreadedIO();
7724 if (listLength(server.io_newjobs) == 0) {
7725 /* No new jobs in queue, exit. */
b74880b4 7726 redisLog(REDIS_DEBUG,"Thread %lld exiting, nothing to do",
b9bc0eef 7727 (long long) pthread_self());
7728 server.io_active_threads--;
7729 unlockThreadedIO();
7730 return NULL;
7731 }
7732 ln = listFirst(server.io_newjobs);
7733 j = ln->value;
7734 listDelNode(server.io_newjobs,ln);
7735 /* Add the job in the processing queue */
7736 j->thread = pthread_self();
7737 listAddNodeTail(server.io_processing,j);
7738 ln = listLast(server.io_processing); /* We use ln later to remove it */
7739 unlockThreadedIO();
b74880b4 7740 redisLog(REDIS_DEBUG,"Thread %lld got a new job (type %d): %p about key '%s'",
6c96ba7d 7741 (long long) pthread_self(), j->type, (void*)j, (char*)j->key->ptr);
b9bc0eef 7742
7743 /* Process the Job */
7744 if (j->type == REDIS_IOJOB_LOAD) {
7745 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
7746 FILE *fp = fopen("/dev/null","w+");
7747 j->pages = rdbSavedObjectPages(j->val,fp);
7748 fclose(fp);
7749 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
a5819310 7750 if (vmWriteObjectOnSwap(j->val,j->page) == REDIS_ERR)
7751 j->canceled = 1;
b9bc0eef 7752 }
7753
7754 /* Done: insert the job into the processed queue */
b74880b4 7755 redisLog(REDIS_DEBUG,"Thread %lld completed the job: %p (key %s)",
6c96ba7d 7756 (long long) pthread_self(), (void*)j, (char*)j->key->ptr);
b9bc0eef 7757 lockThreadedIO();
7758 listDelNode(server.io_processing,ln);
7759 listAddNodeTail(server.io_processed,j);
7760 unlockThreadedIO();
7761
7762 /* Signal the main thread there is new stuff to process */
7763 assert(write(server.io_ready_pipe_write,"x",1) == 1);
7764 }
7765 return NULL; /* never reached */
7766}
7767
7768static void spawnIOThread(void) {
7769 pthread_t thread;
7770
bcaa7a4f 7771 pthread_create(&thread,&server.io_threads_attr,IOThreadEntryPoint,NULL);
b9bc0eef 7772 server.io_active_threads++;
7773}
7774
4ee9488d 7775/* We need to wait for the last thread to exit before we are able to
7776 * fork() in order to BGSAVE or BGREWRITEAOF. */
054e426d 7777static void waitEmptyIOJobsQueue(void) {
4ee9488d 7778 while(1) {
76b7233a 7779 int io_processed_len;
7780
4ee9488d 7781 lockThreadedIO();
054e426d 7782 if (listLength(server.io_newjobs) == 0 &&
7783 listLength(server.io_processing) == 0 &&
7784 server.io_active_threads == 0)
7785 {
4ee9488d 7786 unlockThreadedIO();
7787 return;
7788 }
76b7233a 7789 /* While waiting for empty jobs queue condition we post-process some
7790 * finshed job, as I/O threads may be hanging trying to write against
7791 * the io_ready_pipe_write FD but there are so much pending jobs that
7792 * it's blocking. */
7793 io_processed_len = listLength(server.io_processed);
4ee9488d 7794 unlockThreadedIO();
76b7233a 7795 if (io_processed_len) {
7796 vmThreadedIOCompletedJob(NULL,server.io_ready_pipe_read,NULL,0);
7797 usleep(1000); /* 1 millisecond */
7798 } else {
7799 usleep(10000); /* 10 milliseconds */
7800 }
4ee9488d 7801 }
7802}
7803
054e426d 7804static void vmReopenSwapFile(void) {
7805 fclose(server.vm_fp);
7806 server.vm_fp = fopen(server.vm_swap_file,"r+b");
7807 if (server.vm_fp == NULL) {
7808 redisLog(REDIS_WARNING,"Can't re-open the VM swap file: %s. Exiting.",
7809 server.vm_swap_file);
7810 exit(1);
7811 }
7812 server.vm_fd = fileno(server.vm_fp);
7813}
7814
b9bc0eef 7815/* This function must be called while with threaded IO locked */
7816static void queueIOJob(iojob *j) {
6c96ba7d 7817 redisLog(REDIS_DEBUG,"Queued IO Job %p type %d about key '%s'\n",
7818 (void*)j, j->type, (char*)j->key->ptr);
b9bc0eef 7819 listAddNodeTail(server.io_newjobs,j);
7820 if (server.io_active_threads < server.vm_max_threads)
7821 spawnIOThread();
7822}
7823
7824static int vmSwapObjectThreaded(robj *key, robj *val, redisDb *db) {
7825 iojob *j;
7826
7827 assert(key->storage == REDIS_VM_MEMORY);
7828 assert(key->refcount == 1);
7829
7830 j = zmalloc(sizeof(*j));
7831 j->type = REDIS_IOJOB_PREPARE_SWAP;
7832 j->db = db;
7833 j->key = dupStringObject(key);
7834 j->val = val;
7835 incrRefCount(val);
7836 j->canceled = 0;
7837 j->thread = (pthread_t) -1;
f11b8647 7838 key->storage = REDIS_VM_SWAPPING;
b9bc0eef 7839
7840 lockThreadedIO();
7841 queueIOJob(j);
7842 unlockThreadedIO();
7843 return REDIS_OK;
7844}
7845
b0d8747d 7846/* ============ Virtual Memory - Blocking clients on missing keys =========== */
7847
7848/* Is this client attempting to run a command against swapped keys?
7849 * If so, block it ASAP, load the keys in background, then resume it.4
7850 *
7851 * The improtat thing about this function is that it can fail! If keys will
7852 * still be swapped when the client is resumed, a few of key lookups will
7853 * just block loading keys from disk. */
7854#if 0
7855static void blockClientOnSwappedKeys(redisClient *c) {
7856}
7857#endif
7858
7f957c92 7859/* ================================= Debugging ============================== */
7860
7861static void debugCommand(redisClient *c) {
7862 if (!strcasecmp(c->argv[1]->ptr,"segfault")) {
7863 *((char*)-1) = 'x';
210e29f7 7864 } else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
7865 if (rdbSave(server.dbfilename) != REDIS_OK) {
7866 addReply(c,shared.err);
7867 return;
7868 }
7869 emptyDb();
7870 if (rdbLoad(server.dbfilename) != REDIS_OK) {
7871 addReply(c,shared.err);
7872 return;
7873 }
7874 redisLog(REDIS_WARNING,"DB reloaded by DEBUG RELOAD");
7875 addReply(c,shared.ok);
71c2b467 7876 } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) {
7877 emptyDb();
7878 if (loadAppendOnlyFile(server.appendfilename) != REDIS_OK) {
7879 addReply(c,shared.err);
7880 return;
7881 }
7882 redisLog(REDIS_WARNING,"Append Only File loaded by DEBUG LOADAOF");
7883 addReply(c,shared.ok);
333298da 7884 } else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
7885 dictEntry *de = dictFind(c->db->dict,c->argv[2]);
7886 robj *key, *val;
7887
7888 if (!de) {
7889 addReply(c,shared.nokeyerr);
7890 return;
7891 }
7892 key = dictGetEntryKey(de);
7893 val = dictGetEntryVal(de);
b9bc0eef 7894 if (server.vm_enabled && (key->storage == REDIS_VM_MEMORY ||
7895 key->storage == REDIS_VM_SWAPPING)) {
ace06542 7896 addReplySds(c,sdscatprintf(sdsempty(),
7897 "+Key at:%p refcount:%d, value at:%p refcount:%d "
7898 "encoding:%d serializedlength:%lld\r\n",
682ac724 7899 (void*)key, key->refcount, (void*)val, val->refcount,
459f52a8 7900 val->encoding, (long long) rdbSavedObjectLen(val,NULL)));
ace06542 7901 } else {
7902 addReplySds(c,sdscatprintf(sdsempty(),
7903 "+Key at:%p refcount:%d, value swapped at: page %llu "
7904 "using %llu pages\r\n",
7905 (void*)key, key->refcount, (unsigned long long) key->vm.page,
7906 (unsigned long long) key->vm.usedpages));
7907 }
7d30035d 7908 } else if (!strcasecmp(c->argv[1]->ptr,"swapout") && c->argc == 3) {
7909 dictEntry *de = dictFind(c->db->dict,c->argv[2]);
7910 robj *key, *val;
7911
7912 if (!server.vm_enabled) {
7913 addReplySds(c,sdsnew("-ERR Virtual Memory is disabled\r\n"));
7914 return;
7915 }
7916 if (!de) {
7917 addReply(c,shared.nokeyerr);
7918 return;
7919 }
7920 key = dictGetEntryKey(de);
7921 val = dictGetEntryVal(de);
4ef8de8a 7922 /* If the key is shared we want to create a copy */
7923 if (key->refcount > 1) {
7924 robj *newkey = dupStringObject(key);
7925 decrRefCount(key);
7926 key = dictGetEntryKey(de) = newkey;
7927 }
7928 /* Swap it */
7d30035d 7929 if (key->storage != REDIS_VM_MEMORY) {
7930 addReplySds(c,sdsnew("-ERR This key is not in memory\r\n"));
a69a0c9c 7931 } else if (vmSwapObjectBlocking(key,val) == REDIS_OK) {
7d30035d 7932 dictGetEntryVal(de) = NULL;
7933 addReply(c,shared.ok);
7934 } else {
7935 addReply(c,shared.err);
7936 }
7f957c92 7937 } else {
333298da 7938 addReplySds(c,sdsnew(
7d30035d 7939 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPOUT <key>|RELOAD]\r\n"));
7f957c92 7940 }
7941}
56906eef 7942
6c96ba7d 7943static void _redisAssert(char *estr, char *file, int line) {
dfc5e96c 7944 redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
6c96ba7d 7945 redisLog(REDIS_WARNING,"==> %s:%d '%s' is not true\n",file,line,estr);
dfc5e96c 7946#ifdef HAVE_BACKTRACE
7947 redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
7948 *((char*)-1) = 'x';
7949#endif
7950}
7951
bcfc686d 7952/* =================================== Main! ================================ */
56906eef 7953
bcfc686d 7954#ifdef __linux__
7955int linuxOvercommitMemoryValue(void) {
7956 FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
7957 char buf[64];
56906eef 7958
bcfc686d 7959 if (!fp) return -1;
7960 if (fgets(buf,64,fp) == NULL) {
7961 fclose(fp);
7962 return -1;
7963 }
7964 fclose(fp);
56906eef 7965
bcfc686d 7966 return atoi(buf);
7967}
7968
7969void linuxOvercommitMemoryWarning(void) {
7970 if (linuxOvercommitMemoryValue() == 0) {
7971 redisLog(REDIS_WARNING,"WARNING overcommit_memory is set to 0! Background save may fail under low condition memory. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.");
7972 }
7973}
7974#endif /* __linux__ */
7975
7976static void daemonize(void) {
7977 int fd;
7978 FILE *fp;
7979
7980 if (fork() != 0) exit(0); /* parent exits */
7981 setsid(); /* create a new session */
7982
7983 /* Every output goes to /dev/null. If Redis is daemonized but
7984 * the 'logfile' is set to 'stdout' in the configuration file
7985 * it will not log at all. */
7986 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
7987 dup2(fd, STDIN_FILENO);
7988 dup2(fd, STDOUT_FILENO);
7989 dup2(fd, STDERR_FILENO);
7990 if (fd > STDERR_FILENO) close(fd);
7991 }
7992 /* Try to write the pid file */
7993 fp = fopen(server.pidfile,"w");
7994 if (fp) {
7995 fprintf(fp,"%d\n",getpid());
7996 fclose(fp);
56906eef 7997 }
56906eef 7998}
7999
bcfc686d 8000int main(int argc, char **argv) {
8001 initServerConfig();
8002 if (argc == 2) {
8003 resetServerSaveParams();
8004 loadServerConfig(argv[1]);
8005 } else if (argc > 2) {
8006 fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
8007 exit(1);
8008 } else {
8009 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'");
8010 }
bcfc686d 8011 if (server.daemonize) daemonize();
71c54b21 8012 initServer();
bcfc686d 8013 redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
8014#ifdef __linux__
8015 linuxOvercommitMemoryWarning();
8016#endif
8017 if (server.appendonly) {
8018 if (loadAppendOnlyFile(server.appendfilename) == REDIS_OK)
8019 redisLog(REDIS_NOTICE,"DB loaded from append only file");
8020 } else {
8021 if (rdbLoad(server.dbfilename) == REDIS_OK)
8022 redisLog(REDIS_NOTICE,"DB loaded from disk");
8023 }
bcfc686d 8024 redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
8025 aeMain(server.el);
8026 aeDeleteEventLoop(server.el);
8027 return 0;
8028}
8029
8030/* ============================= Backtrace support ========================= */
8031
8032#ifdef HAVE_BACKTRACE
8033static char *findFuncName(void *pointer, unsigned long *offset);
8034
56906eef 8035static void *getMcontextEip(ucontext_t *uc) {
8036#if defined(__FreeBSD__)
8037 return (void*) uc->uc_mcontext.mc_eip;
8038#elif defined(__dietlibc__)
8039 return (void*) uc->uc_mcontext.eip;
06db1f50 8040#elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
da0a1620 8041 #if __x86_64__
8042 return (void*) uc->uc_mcontext->__ss.__rip;
8043 #else
56906eef 8044 return (void*) uc->uc_mcontext->__ss.__eip;
da0a1620 8045 #endif
06db1f50 8046#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
cb7e07cc 8047 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
06db1f50 8048 return (void*) uc->uc_mcontext->__ss.__rip;
cbc59b38 8049 #else
8050 return (void*) uc->uc_mcontext->__ss.__eip;
8051 #endif
c04c9ac9 8052#elif defined(__i386__) || defined(__X86_64__) || defined(__x86_64__)
8053 return (void*) uc->uc_mcontext.gregs[REG_EIP]; /* Linux 32/64 bit */
b91cf5ef 8054#elif defined(__ia64__) /* Linux IA64 */
8055 return (void*) uc->uc_mcontext.sc_ip;
8056#else
8057 return NULL;
56906eef 8058#endif
8059}
8060
8061static void segvHandler(int sig, siginfo_t *info, void *secret) {
8062 void *trace[100];
8063 char **messages = NULL;
8064 int i, trace_size = 0;
8065 unsigned long offset=0;
56906eef 8066 ucontext_t *uc = (ucontext_t*) secret;
1c85b79f 8067 sds infostring;
56906eef 8068 REDIS_NOTUSED(info);
8069
8070 redisLog(REDIS_WARNING,
8071 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION, sig);
1c85b79f 8072 infostring = genRedisInfoString();
8073 redisLog(REDIS_WARNING, "%s",infostring);
8074 /* It's not safe to sdsfree() the returned string under memory
8075 * corruption conditions. Let it leak as we are going to abort */
56906eef 8076
8077 trace_size = backtrace(trace, 100);
de96dbfe 8078 /* overwrite sigaction with caller's address */
b91cf5ef 8079 if (getMcontextEip(uc) != NULL) {
8080 trace[1] = getMcontextEip(uc);
8081 }
56906eef 8082 messages = backtrace_symbols(trace, trace_size);
fe3bbfbe 8083
d76412d1 8084 for (i=1; i<trace_size; ++i) {
56906eef 8085 char *fn = findFuncName(trace[i], &offset), *p;
8086
8087 p = strchr(messages[i],'+');
8088 if (!fn || (p && ((unsigned long)strtol(p+1,NULL,10)) < offset)) {
8089 redisLog(REDIS_WARNING,"%s", messages[i]);
8090 } else {
8091 redisLog(REDIS_WARNING,"%d redis-server %p %s + %d", i, trace[i], fn, (unsigned int)offset);
8092 }
8093 }
b177fd30 8094 /* free(messages); Don't call free() with possibly corrupted memory. */
56906eef 8095 exit(0);
fe3bbfbe 8096}
56906eef 8097
8098static void setupSigSegvAction(void) {
8099 struct sigaction act;
8100
8101 sigemptyset (&act.sa_mask);
8102 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
8103 * is used. Otherwise, sa_handler is used */
8104 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
8105 act.sa_sigaction = segvHandler;
8106 sigaction (SIGSEGV, &act, NULL);
8107 sigaction (SIGBUS, &act, NULL);
12fea928 8108 sigaction (SIGFPE, &act, NULL);
8109 sigaction (SIGILL, &act, NULL);
8110 sigaction (SIGBUS, &act, NULL);
e65fdc78 8111 return;
56906eef 8112}
e65fdc78 8113
bcfc686d 8114#include "staticsymbols.h"
8115/* This function try to convert a pointer into a function name. It's used in
8116 * oreder to provide a backtrace under segmentation fault that's able to
8117 * display functions declared as static (otherwise the backtrace is useless). */
8118static char *findFuncName(void *pointer, unsigned long *offset){
8119 int i, ret = -1;
8120 unsigned long off, minoff = 0;
ed9b544e 8121
bcfc686d 8122 /* Try to match against the Symbol with the smallest offset */
8123 for (i=0; symsTable[i].pointer; i++) {
8124 unsigned long lp = (unsigned long) pointer;
0bc03378 8125
bcfc686d 8126 if (lp != (unsigned long)-1 && lp >= symsTable[i].pointer) {
8127 off=lp-symsTable[i].pointer;
8128 if (ret < 0 || off < minoff) {
8129 minoff=off;
8130 ret=i;
8131 }
8132 }
0bc03378 8133 }
bcfc686d 8134 if (ret == -1) return NULL;
8135 *offset = minoff;
8136 return symsTable[ret].name;
0bc03378 8137}
bcfc686d 8138#else /* HAVE_BACKTRACE */
8139static void setupSigSegvAction(void) {
0bc03378 8140}
bcfc686d 8141#endif /* HAVE_BACKTRACE */
0bc03378 8142
ed9b544e 8143
ed9b544e 8144
bcfc686d 8145/* The End */
8146
8147
ed9b544e 8148