]> git.saurik.com Git - redis.git/blame - redis.c
Changelog updated
[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
5dc70bff 30#define REDIS_VERSION "1.3.2"
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);
4409877e 546static void unblockClient(redisClient *c);
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},
0b13687c 673 {"rpoplpush",rpoplpushcommand,3,REDIS_CMD_BULK|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);
f86a74e9 1041 unblockClient(c);
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
1675 * call, we have to set querybuf to NULL *before* to call unblockClient()
1676 * to avoid processInputBuffer() will get called. Also it is important
1677 * to remove the file events after this, because this call adds
1678 * the READABLE event. */
1679 sdsfree(c->querybuf);
1680 c->querybuf = NULL;
1681 if (c->flags & REDIS_BLOCKED)
1682 unblockClient(c);
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 */
5954static void unblockClient(redisClient *c) {
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
5978 * can't trap errors here as it's possible that unblockClients() is
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
5985 * in the input buffer. Note that this is safe even if unblockClient()
5986 * gets called from freeClient() because freeClient() will be smart
5987 * enough to call this function *after* c->querybuf was set to NULL. */
5988 if (c->querybuf && sdslen(c->querybuf) > 0) processInputBuffer(c);
5989}
5990
5991/* This should be called from any function PUSHing into lists.
5992 * 'c' is the "pushing client", 'key' is the key it is pushing data against,
5993 * 'ele' is the element pushed.
5994 *
5995 * If the function returns 0 there was no client waiting for a list push
5996 * against this key.
5997 *
5998 * If the function returns 1 there was a client waiting for a list push
5999 * against this key, the element was passed to this client thus it's not
6000 * needed to actually add it to the list and the caller should return asap. */
6001static int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
6002 struct dictEntry *de;
6003 redisClient *receiver;
6004 list *l;
6005 listNode *ln;
6006
6007 de = dictFind(c->db->blockingkeys,key);
6008 if (de == NULL) return 0;
6009 l = dictGetEntryVal(de);
6010 ln = listFirst(l);
6011 assert(ln != NULL);
6012 receiver = ln->value;
4409877e 6013
b177fd30 6014 addReplySds(receiver,sdsnew("*2\r\n"));
6015 addReplyBulkLen(receiver,key);
6016 addReply(receiver,key);
6017 addReply(receiver,shared.crlf);
4409877e 6018 addReplyBulkLen(receiver,ele);
6019 addReply(receiver,ele);
6020 addReply(receiver,shared.crlf);
6021 unblockClient(receiver);
6022 return 1;
6023}
6024
6025/* Blocking RPOP/LPOP */
6026static void blockingPopGenericCommand(redisClient *c, int where) {
6027 robj *o;
6028 time_t timeout;
b177fd30 6029 int j;
4409877e 6030
b177fd30 6031 for (j = 1; j < c->argc-1; j++) {
6032 o = lookupKeyWrite(c->db,c->argv[j]);
6033 if (o != NULL) {
6034 if (o->type != REDIS_LIST) {
6035 addReply(c,shared.wrongtypeerr);
4409877e 6036 return;
b177fd30 6037 } else {
6038 list *list = o->ptr;
6039 if (listLength(list) != 0) {
6040 /* If the list contains elements fall back to the usual
6041 * non-blocking POP operation */
6042 robj *argv[2], **orig_argv;
6043 int orig_argc;
6044
6045 /* We need to alter the command arguments before to call
6046 * popGenericCommand() as the command takes a single key. */
6047 orig_argv = c->argv;
6048 orig_argc = c->argc;
6049 argv[1] = c->argv[j];
6050 c->argv = argv;
6051 c->argc = 2;
6052
6053 /* Also the return value is different, we need to output
6054 * the multi bulk reply header and the key name. The
6055 * "real" command will add the last element (the value)
6056 * for us. If this souds like an hack to you it's just
6057 * because it is... */
6058 addReplySds(c,sdsnew("*2\r\n"));
6059 addReplyBulkLen(c,argv[1]);
6060 addReply(c,argv[1]);
6061 addReply(c,shared.crlf);
6062 popGenericCommand(c,where);
6063
6064 /* Fix the client structure with the original stuff */
6065 c->argv = orig_argv;
6066 c->argc = orig_argc;
6067 return;
6068 }
4409877e 6069 }
6070 }
6071 }
6072 /* If the list is empty or the key does not exists we must block */
b177fd30 6073 timeout = strtol(c->argv[c->argc-1]->ptr,NULL,10);
4409877e 6074 if (timeout > 0) timeout += time(NULL);
b177fd30 6075 blockForKeys(c,c->argv+1,c->argc-2,timeout);
4409877e 6076}
6077
6078static void blpopCommand(redisClient *c) {
6079 blockingPopGenericCommand(c,REDIS_HEAD);
6080}
6081
6082static void brpopCommand(redisClient *c) {
6083 blockingPopGenericCommand(c,REDIS_TAIL);
6084}
6085
ed9b544e 6086/* =============================== Replication ============================= */
6087
a4d1ba9a 6088static int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 6089 ssize_t nwritten, ret = size;
6090 time_t start = time(NULL);
6091
6092 timeout++;
6093 while(size) {
6094 if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
6095 nwritten = write(fd,ptr,size);
6096 if (nwritten == -1) return -1;
6097 ptr += nwritten;
6098 size -= nwritten;
6099 }
6100 if ((time(NULL)-start) > timeout) {
6101 errno = ETIMEDOUT;
6102 return -1;
6103 }
6104 }
6105 return ret;
6106}
6107
a4d1ba9a 6108static int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
ed9b544e 6109 ssize_t nread, totread = 0;
6110 time_t start = time(NULL);
6111
6112 timeout++;
6113 while(size) {
6114 if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
6115 nread = read(fd,ptr,size);
6116 if (nread == -1) return -1;
6117 ptr += nread;
6118 size -= nread;
6119 totread += nread;
6120 }
6121 if ((time(NULL)-start) > timeout) {
6122 errno = ETIMEDOUT;
6123 return -1;
6124 }
6125 }
6126 return totread;
6127}
6128
6129static int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
6130 ssize_t nread = 0;
6131
6132 size--;
6133 while(size) {
6134 char c;
6135
6136 if (syncRead(fd,&c,1,timeout) == -1) return -1;
6137 if (c == '\n') {
6138 *ptr = '\0';
6139 if (nread && *(ptr-1) == '\r') *(ptr-1) = '\0';
6140 return nread;
6141 } else {
6142 *ptr++ = c;
6143 *ptr = '\0';
6144 nread++;
6145 }
6146 }
6147 return nread;
6148}
6149
6150static void syncCommand(redisClient *c) {
40d224a9 6151 /* ignore SYNC if aleady slave or in monitor mode */
6152 if (c->flags & REDIS_SLAVE) return;
6153
6154 /* SYNC can't be issued when the server has pending data to send to
6155 * the client about already issued commands. We need a fresh reply
6156 * buffer registering the differences between the BGSAVE and the current
6157 * dataset, so that we can copy to other slaves if needed. */
6158 if (listLength(c->reply) != 0) {
6159 addReplySds(c,sdsnew("-ERR SYNC is invalid with pending input\r\n"));
6160 return;
6161 }
6162
6163 redisLog(REDIS_NOTICE,"Slave ask for synchronization");
6164 /* Here we need to check if there is a background saving operation
6165 * in progress, or if it is required to start one */
9d65a1bb 6166 if (server.bgsavechildpid != -1) {
40d224a9 6167 /* Ok a background save is in progress. Let's check if it is a good
6168 * one for replication, i.e. if there is another slave that is
6169 * registering differences since the server forked to save */
6170 redisClient *slave;
6171 listNode *ln;
c7df85a4 6172 listIter li;
40d224a9 6173
c7df85a4 6174 listRewind(server.slaves,&li);
6175 while((ln = listNext(&li))) {
40d224a9 6176 slave = ln->value;
6177 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break;
40d224a9 6178 }
6179 if (ln) {
6180 /* Perfect, the server is already registering differences for
6181 * another slave. Set the right state, and copy the buffer. */
6182 listRelease(c->reply);
6183 c->reply = listDup(slave->reply);
40d224a9 6184 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
6185 redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC");
6186 } else {
6187 /* No way, we need to wait for the next BGSAVE in order to
6188 * register differences */
6189 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
6190 redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
6191 }
6192 } else {
6193 /* Ok we don't have a BGSAVE in progress, let's start one */
6194 redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
6195 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
6196 redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE");
6197 addReplySds(c,sdsnew("-ERR Unalbe to perform background save\r\n"));
6198 return;
6199 }
6200 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
6201 }
6208b3a7 6202 c->repldbfd = -1;
40d224a9 6203 c->flags |= REDIS_SLAVE;
6204 c->slaveseldb = 0;
6b47e12e 6205 listAddNodeTail(server.slaves,c);
40d224a9 6206 return;
6207}
6208
6208b3a7 6209static void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
6210 redisClient *slave = privdata;
6211 REDIS_NOTUSED(el);
6212 REDIS_NOTUSED(mask);
6213 char buf[REDIS_IOBUF_LEN];
6214 ssize_t nwritten, buflen;
6215
6216 if (slave->repldboff == 0) {
6217 /* Write the bulk write count before to transfer the DB. In theory here
6218 * we don't know how much room there is in the output buffer of the
6219 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
6220 * operations) will never be smaller than the few bytes we need. */
6221 sds bulkcount;
6222
6223 bulkcount = sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
6224 slave->repldbsize);
6225 if (write(fd,bulkcount,sdslen(bulkcount)) != (signed)sdslen(bulkcount))
6226 {
6227 sdsfree(bulkcount);
6228 freeClient(slave);
6229 return;
6230 }
6231 sdsfree(bulkcount);
6232 }
6233 lseek(slave->repldbfd,slave->repldboff,SEEK_SET);
6234 buflen = read(slave->repldbfd,buf,REDIS_IOBUF_LEN);
6235 if (buflen <= 0) {
6236 redisLog(REDIS_WARNING,"Read error sending DB to slave: %s",
6237 (buflen == 0) ? "premature EOF" : strerror(errno));
6238 freeClient(slave);
6239 return;
6240 }
6241 if ((nwritten = write(fd,buf,buflen)) == -1) {
f870935d 6242 redisLog(REDIS_VERBOSE,"Write error sending DB to slave: %s",
6208b3a7 6243 strerror(errno));
6244 freeClient(slave);
6245 return;
6246 }
6247 slave->repldboff += nwritten;
6248 if (slave->repldboff == slave->repldbsize) {
6249 close(slave->repldbfd);
6250 slave->repldbfd = -1;
6251 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
6252 slave->replstate = REDIS_REPL_ONLINE;
6253 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
266373b2 6254 sendReplyToClient, slave) == AE_ERR) {
6208b3a7 6255 freeClient(slave);
6256 return;
6257 }
6258 addReplySds(slave,sdsempty());
6259 redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
6260 }
6261}
ed9b544e 6262
a3b21203 6263/* This function is called at the end of every backgrond saving.
6264 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
6265 * otherwise REDIS_ERR is passed to the function.
6266 *
6267 * The goal of this function is to handle slaves waiting for a successful
6268 * background saving in order to perform non-blocking synchronization. */
6269static void updateSlavesWaitingBgsave(int bgsaveerr) {
6208b3a7 6270 listNode *ln;
6271 int startbgsave = 0;
c7df85a4 6272 listIter li;
ed9b544e 6273
c7df85a4 6274 listRewind(server.slaves,&li);
6275 while((ln = listNext(&li))) {
6208b3a7 6276 redisClient *slave = ln->value;
ed9b544e 6277
6208b3a7 6278 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) {
6279 startbgsave = 1;
6280 slave->replstate = REDIS_REPL_WAIT_BGSAVE_END;
6281 } else if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
dde65f3f 6282 struct redis_stat buf;
6208b3a7 6283
6284 if (bgsaveerr != REDIS_OK) {
6285 freeClient(slave);
6286 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE child returned an error");
6287 continue;
6288 }
6289 if ((slave->repldbfd = open(server.dbfilename,O_RDONLY)) == -1 ||
dde65f3f 6290 redis_fstat(slave->repldbfd,&buf) == -1) {
6208b3a7 6291 freeClient(slave);
6292 redisLog(REDIS_WARNING,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno));
6293 continue;
6294 }
6295 slave->repldboff = 0;
6296 slave->repldbsize = buf.st_size;
6297 slave->replstate = REDIS_REPL_SEND_BULK;
6298 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
266373b2 6299 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE, sendBulkToSlave, slave) == AE_ERR) {
6208b3a7 6300 freeClient(slave);
6301 continue;
6302 }
6303 }
ed9b544e 6304 }
6208b3a7 6305 if (startbgsave) {
6306 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
c7df85a4 6307 listIter li;
6308
6309 listRewind(server.slaves,&li);
6208b3a7 6310 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE failed");
c7df85a4 6311 while((ln = listNext(&li))) {
6208b3a7 6312 redisClient *slave = ln->value;
ed9b544e 6313
6208b3a7 6314 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START)
6315 freeClient(slave);
6316 }
6317 }
6318 }
ed9b544e 6319}
6320
6321static int syncWithMaster(void) {
d0ccebcf 6322 char buf[1024], tmpfile[256], authcmd[1024];
ed9b544e 6323 int dumpsize;
6324 int fd = anetTcpConnect(NULL,server.masterhost,server.masterport);
6325 int dfd;
6326
6327 if (fd == -1) {
6328 redisLog(REDIS_WARNING,"Unable to connect to MASTER: %s",
6329 strerror(errno));
6330 return REDIS_ERR;
6331 }
d0ccebcf 6332
6333 /* AUTH with the master if required. */
6334 if(server.masterauth) {
6335 snprintf(authcmd, 1024, "AUTH %s\r\n", server.masterauth);
6336 if (syncWrite(fd, authcmd, strlen(server.masterauth)+7, 5) == -1) {
6337 close(fd);
6338 redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",
6339 strerror(errno));
6340 return REDIS_ERR;
6341 }
6342 /* Read the AUTH result. */
6343 if (syncReadLine(fd,buf,1024,3600) == -1) {
6344 close(fd);
6345 redisLog(REDIS_WARNING,"I/O error reading auth result from MASTER: %s",
6346 strerror(errno));
6347 return REDIS_ERR;
6348 }
6349 if (buf[0] != '+') {
6350 close(fd);
6351 redisLog(REDIS_WARNING,"Cannot AUTH to MASTER, is the masterauth password correct?");
6352 return REDIS_ERR;
6353 }
6354 }
6355
ed9b544e 6356 /* Issue the SYNC command */
6357 if (syncWrite(fd,"SYNC \r\n",7,5) == -1) {
6358 close(fd);
6359 redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
6360 strerror(errno));
6361 return REDIS_ERR;
6362 }
6363 /* Read the bulk write count */
8c4d91fc 6364 if (syncReadLine(fd,buf,1024,3600) == -1) {
ed9b544e 6365 close(fd);
6366 redisLog(REDIS_WARNING,"I/O error reading bulk count from MASTER: %s",
6367 strerror(errno));
6368 return REDIS_ERR;
6369 }
4aa701c1 6370 if (buf[0] != '$') {
6371 close(fd);
6372 redisLog(REDIS_WARNING,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
6373 return REDIS_ERR;
6374 }
c937aa89 6375 dumpsize = atoi(buf+1);
ed9b544e 6376 redisLog(REDIS_NOTICE,"Receiving %d bytes data dump from MASTER",dumpsize);
6377 /* Read the bulk write data on a temp file */
6378 snprintf(tmpfile,256,"temp-%d.%ld.rdb",(int)time(NULL),(long int)random());
6379 dfd = open(tmpfile,O_CREAT|O_WRONLY,0644);
6380 if (dfd == -1) {
6381 close(fd);
6382 redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
6383 return REDIS_ERR;
6384 }
6385 while(dumpsize) {
6386 int nread, nwritten;
6387
6388 nread = read(fd,buf,(dumpsize < 1024)?dumpsize:1024);
6389 if (nread == -1) {
6390 redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
6391 strerror(errno));
6392 close(fd);
6393 close(dfd);
6394 return REDIS_ERR;
6395 }
6396 nwritten = write(dfd,buf,nread);
6397 if (nwritten == -1) {
6398 redisLog(REDIS_WARNING,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
6399 close(fd);
6400 close(dfd);
6401 return REDIS_ERR;
6402 }
6403 dumpsize -= nread;
6404 }
6405 close(dfd);
6406 if (rename(tmpfile,server.dbfilename) == -1) {
6407 redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
6408 unlink(tmpfile);
6409 close(fd);
6410 return REDIS_ERR;
6411 }
6412 emptyDb();
f78fd11b 6413 if (rdbLoad(server.dbfilename) != REDIS_OK) {
ed9b544e 6414 redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
6415 close(fd);
6416 return REDIS_ERR;
6417 }
6418 server.master = createClient(fd);
6419 server.master->flags |= REDIS_MASTER;
179b3952 6420 server.master->authenticated = 1;
ed9b544e 6421 server.replstate = REDIS_REPL_CONNECTED;
6422 return REDIS_OK;
6423}
6424
321b0e13 6425static void slaveofCommand(redisClient *c) {
6426 if (!strcasecmp(c->argv[1]->ptr,"no") &&
6427 !strcasecmp(c->argv[2]->ptr,"one")) {
6428 if (server.masterhost) {
6429 sdsfree(server.masterhost);
6430 server.masterhost = NULL;
6431 if (server.master) freeClient(server.master);
6432 server.replstate = REDIS_REPL_NONE;
6433 redisLog(REDIS_NOTICE,"MASTER MODE enabled (user request)");
6434 }
6435 } else {
6436 sdsfree(server.masterhost);
6437 server.masterhost = sdsdup(c->argv[1]->ptr);
6438 server.masterport = atoi(c->argv[2]->ptr);
6439 if (server.master) freeClient(server.master);
6440 server.replstate = REDIS_REPL_CONNECT;
6441 redisLog(REDIS_NOTICE,"SLAVE OF %s:%d enabled (user request)",
6442 server.masterhost, server.masterport);
6443 }
6444 addReply(c,shared.ok);
6445}
6446
3fd78bcd 6447/* ============================ Maxmemory directive ======================== */
6448
a5819310 6449/* Try to free one object form the pre-allocated objects free list.
6450 * This is useful under low mem conditions as by default we take 1 million
6451 * free objects allocated. On success REDIS_OK is returned, otherwise
6452 * REDIS_ERR. */
6453static int tryFreeOneObjectFromFreelist(void) {
f870935d 6454 robj *o;
6455
a5819310 6456 if (server.vm_enabled) pthread_mutex_lock(&server.obj_freelist_mutex);
6457 if (listLength(server.objfreelist)) {
6458 listNode *head = listFirst(server.objfreelist);
6459 o = listNodeValue(head);
6460 listDelNode(server.objfreelist,head);
6461 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
6462 zfree(o);
6463 return REDIS_OK;
6464 } else {
6465 if (server.vm_enabled) pthread_mutex_unlock(&server.obj_freelist_mutex);
6466 return REDIS_ERR;
6467 }
f870935d 6468}
6469
3fd78bcd 6470/* This function gets called when 'maxmemory' is set on the config file to limit
6471 * the max memory used by the server, and we are out of memory.
6472 * This function will try to, in order:
6473 *
6474 * - Free objects from the free list
6475 * - Try to remove keys with an EXPIRE set
6476 *
6477 * It is not possible to free enough memory to reach used-memory < maxmemory
6478 * the server will start refusing commands that will enlarge even more the
6479 * memory usage.
6480 */
6481static void freeMemoryIfNeeded(void) {
6482 while (server.maxmemory && zmalloc_used_memory() > server.maxmemory) {
a5819310 6483 int j, k, freed = 0;
6484
6485 if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
6486 for (j = 0; j < server.dbnum; j++) {
6487 int minttl = -1;
6488 robj *minkey = NULL;
6489 struct dictEntry *de;
6490
6491 if (dictSize(server.db[j].expires)) {
6492 freed = 1;
6493 /* From a sample of three keys drop the one nearest to
6494 * the natural expire */
6495 for (k = 0; k < 3; k++) {
6496 time_t t;
6497
6498 de = dictGetRandomKey(server.db[j].expires);
6499 t = (time_t) dictGetEntryVal(de);
6500 if (minttl == -1 || t < minttl) {
6501 minkey = dictGetEntryKey(de);
6502 minttl = t;
3fd78bcd 6503 }
3fd78bcd 6504 }
a5819310 6505 deleteKey(server.db+j,minkey);
3fd78bcd 6506 }
3fd78bcd 6507 }
a5819310 6508 if (!freed) return; /* nothing to free... */
3fd78bcd 6509 }
6510}
6511
f80dff62 6512/* ============================== Append Only file ========================== */
6513
6514static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {
6515 sds buf = sdsempty();
6516 int j;
6517 ssize_t nwritten;
6518 time_t now;
6519 robj *tmpargv[3];
6520
6521 /* The DB this command was targetting is not the same as the last command
6522 * we appendend. To issue a SELECT command is needed. */
6523 if (dictid != server.appendseldb) {
6524 char seldb[64];
6525
6526 snprintf(seldb,sizeof(seldb),"%d",dictid);
682ac724 6527 buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
83c6a618 6528 (unsigned long)strlen(seldb),seldb);
f80dff62 6529 server.appendseldb = dictid;
6530 }
6531
6532 /* "Fix" the argv vector if the command is EXPIRE. We want to translate
6533 * EXPIREs into EXPIREATs calls */
6534 if (cmd->proc == expireCommand) {
6535 long when;
6536
6537 tmpargv[0] = createStringObject("EXPIREAT",8);
6538 tmpargv[1] = argv[1];
6539 incrRefCount(argv[1]);
6540 when = time(NULL)+strtol(argv[2]->ptr,NULL,10);
6541 tmpargv[2] = createObject(REDIS_STRING,
6542 sdscatprintf(sdsempty(),"%ld",when));
6543 argv = tmpargv;
6544 }
6545
6546 /* Append the actual command */
6547 buf = sdscatprintf(buf,"*%d\r\n",argc);
6548 for (j = 0; j < argc; j++) {
6549 robj *o = argv[j];
6550
9d65a1bb 6551 o = getDecodedObject(o);
83c6a618 6552 buf = sdscatprintf(buf,"$%lu\r\n",(unsigned long)sdslen(o->ptr));
f80dff62 6553 buf = sdscatlen(buf,o->ptr,sdslen(o->ptr));
6554 buf = sdscatlen(buf,"\r\n",2);
9d65a1bb 6555 decrRefCount(o);
f80dff62 6556 }
6557
6558 /* Free the objects from the modified argv for EXPIREAT */
6559 if (cmd->proc == expireCommand) {
6560 for (j = 0; j < 3; j++)
6561 decrRefCount(argv[j]);
6562 }
6563
6564 /* We want to perform a single write. This should be guaranteed atomic
6565 * at least if the filesystem we are writing is a real physical one.
6566 * While this will save us against the server being killed I don't think
6567 * there is much to do about the whole server stopping for power problems
6568 * or alike */
6569 nwritten = write(server.appendfd,buf,sdslen(buf));
6570 if (nwritten != (signed)sdslen(buf)) {
6571 /* Ooops, we are in troubles. The best thing to do for now is
6572 * to simply exit instead to give the illusion that everything is
6573 * working as expected. */
6574 if (nwritten == -1) {
6575 redisLog(REDIS_WARNING,"Exiting on error writing to the append-only file: %s",strerror(errno));
6576 } else {
6577 redisLog(REDIS_WARNING,"Exiting on short write while writing to the append-only file: %s",strerror(errno));
6578 }
6579 exit(1);
6580 }
85a83172 6581 /* If a background append only file rewriting is in progress we want to
6582 * accumulate the differences between the child DB and the current one
6583 * in a buffer, so that when the child process will do its work we
6584 * can append the differences to the new append only file. */
6585 if (server.bgrewritechildpid != -1)
6586 server.bgrewritebuf = sdscatlen(server.bgrewritebuf,buf,sdslen(buf));
6587
6588 sdsfree(buf);
f80dff62 6589 now = time(NULL);
6590 if (server.appendfsync == APPENDFSYNC_ALWAYS ||
6591 (server.appendfsync == APPENDFSYNC_EVERYSEC &&
6592 now-server.lastfsync > 1))
6593 {
6594 fsync(server.appendfd); /* Let's try to get this data on the disk */
6595 server.lastfsync = now;
6596 }
6597}
6598
6599/* In Redis commands are always executed in the context of a client, so in
6600 * order to load the append only file we need to create a fake client. */
6601static struct redisClient *createFakeClient(void) {
6602 struct redisClient *c = zmalloc(sizeof(*c));
6603
6604 selectDb(c,0);
6605 c->fd = -1;
6606 c->querybuf = sdsempty();
6607 c->argc = 0;
6608 c->argv = NULL;
6609 c->flags = 0;
9387d17d 6610 /* We set the fake client as a slave waiting for the synchronization
6611 * so that Redis will not try to send replies to this client. */
6612 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
f80dff62 6613 c->reply = listCreate();
6614 listSetFreeMethod(c->reply,decrRefCount);
6615 listSetDupMethod(c->reply,dupClientReplyValue);
6616 return c;
6617}
6618
6619static void freeFakeClient(struct redisClient *c) {
6620 sdsfree(c->querybuf);
6621 listRelease(c->reply);
6622 zfree(c);
6623}
6624
6625/* Replay the append log file. On error REDIS_OK is returned. On non fatal
6626 * error (the append only file is zero-length) REDIS_ERR is returned. On
6627 * fatal error an error message is logged and the program exists. */
6628int loadAppendOnlyFile(char *filename) {
6629 struct redisClient *fakeClient;
6630 FILE *fp = fopen(filename,"r");
6631 struct redis_stat sb;
b492cf00 6632 unsigned long long loadedkeys = 0;
f80dff62 6633
6634 if (redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0)
6635 return REDIS_ERR;
6636
6637 if (fp == NULL) {
6638 redisLog(REDIS_WARNING,"Fatal error: can't open the append log file for reading: %s",strerror(errno));
6639 exit(1);
6640 }
6641
6642 fakeClient = createFakeClient();
6643 while(1) {
6644 int argc, j;
6645 unsigned long len;
6646 robj **argv;
6647 char buf[128];
6648 sds argsds;
6649 struct redisCommand *cmd;
6650
6651 if (fgets(buf,sizeof(buf),fp) == NULL) {
6652 if (feof(fp))
6653 break;
6654 else
6655 goto readerr;
6656 }
6657 if (buf[0] != '*') goto fmterr;
6658 argc = atoi(buf+1);
6659 argv = zmalloc(sizeof(robj*)*argc);
6660 for (j = 0; j < argc; j++) {
6661 if (fgets(buf,sizeof(buf),fp) == NULL) goto readerr;
6662 if (buf[0] != '$') goto fmterr;
6663 len = strtol(buf+1,NULL,10);
6664 argsds = sdsnewlen(NULL,len);
0f151ef1 6665 if (len && fread(argsds,len,1,fp) == 0) goto fmterr;
f80dff62 6666 argv[j] = createObject(REDIS_STRING,argsds);
6667 if (fread(buf,2,1,fp) == 0) goto fmterr; /* discard CRLF */
6668 }
6669
6670 /* Command lookup */
6671 cmd = lookupCommand(argv[0]->ptr);
6672 if (!cmd) {
6673 redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", argv[0]->ptr);
6674 exit(1);
6675 }
6676 /* Try object sharing and encoding */
6677 if (server.shareobjects) {
6678 int j;
6679 for(j = 1; j < argc; j++)
6680 argv[j] = tryObjectSharing(argv[j]);
6681 }
6682 if (cmd->flags & REDIS_CMD_BULK)
6683 tryObjectEncoding(argv[argc-1]);
6684 /* Run the command in the context of a fake client */
6685 fakeClient->argc = argc;
6686 fakeClient->argv = argv;
6687 cmd->proc(fakeClient);
6688 /* Discard the reply objects list from the fake client */
6689 while(listLength(fakeClient->reply))
6690 listDelNode(fakeClient->reply,listFirst(fakeClient->reply));
6691 /* Clean up, ready for the next command */
6692 for (j = 0; j < argc; j++) decrRefCount(argv[j]);
6693 zfree(argv);
b492cf00 6694 /* Handle swapping while loading big datasets when VM is on */
6695 loadedkeys++;
6696 if (server.vm_enabled && (loadedkeys % 5000) == 0) {
6697 while (zmalloc_used_memory() > server.vm_max_memory) {
a69a0c9c 6698 if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
b492cf00 6699 }
6700 }
f80dff62 6701 }
6702 fclose(fp);
6703 freeFakeClient(fakeClient);
6704 return REDIS_OK;
6705
6706readerr:
6707 if (feof(fp)) {
6708 redisLog(REDIS_WARNING,"Unexpected end of file reading the append only file");
6709 } else {
6710 redisLog(REDIS_WARNING,"Unrecoverable error reading the append only file: %s", strerror(errno));
6711 }
6712 exit(1);
6713fmterr:
6714 redisLog(REDIS_WARNING,"Bad file format reading the append only file");
6715 exit(1);
6716}
6717
9d65a1bb 6718/* Write an object into a file in the bulk format $<count>\r\n<payload>\r\n */
6719static int fwriteBulk(FILE *fp, robj *obj) {
6720 char buf[128];
b9bc0eef 6721 int decrrc = 0;
6722
f2d9f50f 6723 /* Avoid the incr/decr ref count business if possible to help
6724 * copy-on-write (we are often in a child process when this function
6725 * is called).
6726 * Also makes sure that key objects don't get incrRefCount-ed when VM
6727 * is enabled */
6728 if (obj->encoding != REDIS_ENCODING_RAW) {
b9bc0eef 6729 obj = getDecodedObject(obj);
6730 decrrc = 1;
6731 }
9d65a1bb 6732 snprintf(buf,sizeof(buf),"$%ld\r\n",(long)sdslen(obj->ptr));
6733 if (fwrite(buf,strlen(buf),1,fp) == 0) goto err;
e96e4fbf 6734 if (sdslen(obj->ptr) && fwrite(obj->ptr,sdslen(obj->ptr),1,fp) == 0)
6735 goto err;
9d65a1bb 6736 if (fwrite("\r\n",2,1,fp) == 0) goto err;
b9bc0eef 6737 if (decrrc) decrRefCount(obj);
9d65a1bb 6738 return 1;
6739err:
b9bc0eef 6740 if (decrrc) decrRefCount(obj);
9d65a1bb 6741 return 0;
6742}
6743
6744/* Write a double value in bulk format $<count>\r\n<payload>\r\n */
6745static int fwriteBulkDouble(FILE *fp, double d) {
6746 char buf[128], dbuf[128];
6747
6748 snprintf(dbuf,sizeof(dbuf),"%.17g\r\n",d);
6749 snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(dbuf)-2);
6750 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
6751 if (fwrite(dbuf,strlen(dbuf),1,fp) == 0) return 0;
6752 return 1;
6753}
6754
6755/* Write a long value in bulk format $<count>\r\n<payload>\r\n */
6756static int fwriteBulkLong(FILE *fp, long l) {
6757 char buf[128], lbuf[128];
6758
6759 snprintf(lbuf,sizeof(lbuf),"%ld\r\n",l);
6760 snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(lbuf)-2);
6761 if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
6762 if (fwrite(lbuf,strlen(lbuf),1,fp) == 0) return 0;
6763 return 1;
6764}
6765
6766/* Write a sequence of commands able to fully rebuild the dataset into
6767 * "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
6768static int rewriteAppendOnlyFile(char *filename) {
6769 dictIterator *di = NULL;
6770 dictEntry *de;
6771 FILE *fp;
6772 char tmpfile[256];
6773 int j;
6774 time_t now = time(NULL);
6775
6776 /* Note that we have to use a different temp name here compared to the
6777 * one used by rewriteAppendOnlyFileBackground() function. */
6778 snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid());
6779 fp = fopen(tmpfile,"w");
6780 if (!fp) {
6781 redisLog(REDIS_WARNING, "Failed rewriting the append only file: %s", strerror(errno));
6782 return REDIS_ERR;
6783 }
6784 for (j = 0; j < server.dbnum; j++) {
6785 char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n";
6786 redisDb *db = server.db+j;
6787 dict *d = db->dict;
6788 if (dictSize(d) == 0) continue;
6789 di = dictGetIterator(d);
6790 if (!di) {
6791 fclose(fp);
6792 return REDIS_ERR;
6793 }
6794
6795 /* SELECT the new DB */
6796 if (fwrite(selectcmd,sizeof(selectcmd)-1,1,fp) == 0) goto werr;
85a83172 6797 if (fwriteBulkLong(fp,j) == 0) goto werr;
9d65a1bb 6798
6799 /* Iterate this DB writing every entry */
6800 while((de = dictNext(di)) != NULL) {
e7546c63 6801 robj *key, *o;
6802 time_t expiretime;
6803 int swapped;
6804
6805 key = dictGetEntryKey(de);
b9bc0eef 6806 /* If the value for this key is swapped, load a preview in memory.
6807 * We use a "swapped" flag to remember if we need to free the
6808 * value object instead to just increment the ref count anyway
6809 * in order to avoid copy-on-write of pages if we are forked() */
996cb5f7 6810 if (!server.vm_enabled || key->storage == REDIS_VM_MEMORY ||
6811 key->storage == REDIS_VM_SWAPPING) {
e7546c63 6812 o = dictGetEntryVal(de);
6813 swapped = 0;
6814 } else {
6815 o = vmPreviewObject(key);
e7546c63 6816 swapped = 1;
6817 }
6818 expiretime = getExpire(db,key);
9d65a1bb 6819
6820 /* Save the key and associated value */
9d65a1bb 6821 if (o->type == REDIS_STRING) {
6822 /* Emit a SET command */
6823 char cmd[]="*3\r\n$3\r\nSET\r\n";
6824 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
6825 /* Key and value */
6826 if (fwriteBulk(fp,key) == 0) goto werr;
6827 if (fwriteBulk(fp,o) == 0) goto werr;
6828 } else if (o->type == REDIS_LIST) {
6829 /* Emit the RPUSHes needed to rebuild the list */
6830 list *list = o->ptr;
6831 listNode *ln;
c7df85a4 6832 listIter li;
9d65a1bb 6833
c7df85a4 6834 listRewind(list,&li);
6835 while((ln = listNext(&li))) {
9d65a1bb 6836 char cmd[]="*3\r\n$5\r\nRPUSH\r\n";
6837 robj *eleobj = listNodeValue(ln);
6838
6839 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
6840 if (fwriteBulk(fp,key) == 0) goto werr;
6841 if (fwriteBulk(fp,eleobj) == 0) goto werr;
6842 }
6843 } else if (o->type == REDIS_SET) {
6844 /* Emit the SADDs needed to rebuild the set */
6845 dict *set = o->ptr;
6846 dictIterator *di = dictGetIterator(set);
6847 dictEntry *de;
6848
6849 while((de = dictNext(di)) != NULL) {
6850 char cmd[]="*3\r\n$4\r\nSADD\r\n";
6851 robj *eleobj = dictGetEntryKey(de);
6852
6853 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
6854 if (fwriteBulk(fp,key) == 0) goto werr;
6855 if (fwriteBulk(fp,eleobj) == 0) goto werr;
6856 }
6857 dictReleaseIterator(di);
6858 } else if (o->type == REDIS_ZSET) {
6859 /* Emit the ZADDs needed to rebuild the sorted set */
6860 zset *zs = o->ptr;
6861 dictIterator *di = dictGetIterator(zs->dict);
6862 dictEntry *de;
6863
6864 while((de = dictNext(di)) != NULL) {
6865 char cmd[]="*4\r\n$4\r\nZADD\r\n";
6866 robj *eleobj = dictGetEntryKey(de);
6867 double *score = dictGetEntryVal(de);
6868
6869 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
6870 if (fwriteBulk(fp,key) == 0) goto werr;
6871 if (fwriteBulkDouble(fp,*score) == 0) goto werr;
6872 if (fwriteBulk(fp,eleobj) == 0) goto werr;
6873 }
6874 dictReleaseIterator(di);
6875 } else {
dfc5e96c 6876 redisAssert(0 != 0);
9d65a1bb 6877 }
6878 /* Save the expire time */
6879 if (expiretime != -1) {
e96e4fbf 6880 char cmd[]="*3\r\n$8\r\nEXPIREAT\r\n";
9d65a1bb 6881 /* If this key is already expired skip it */
6882 if (expiretime < now) continue;
6883 if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
6884 if (fwriteBulk(fp,key) == 0) goto werr;
6885 if (fwriteBulkLong(fp,expiretime) == 0) goto werr;
6886 }
b9bc0eef 6887 if (swapped) decrRefCount(o);
9d65a1bb 6888 }
6889 dictReleaseIterator(di);
6890 }
6891
6892 /* Make sure data will not remain on the OS's output buffers */
6893 fflush(fp);
6894 fsync(fileno(fp));
6895 fclose(fp);
6896
6897 /* Use RENAME to make sure the DB file is changed atomically only
6898 * if the generate DB file is ok. */
6899 if (rename(tmpfile,filename) == -1) {
6900 redisLog(REDIS_WARNING,"Error moving temp append only file on the final destination: %s", strerror(errno));
6901 unlink(tmpfile);
6902 return REDIS_ERR;
6903 }
6904 redisLog(REDIS_NOTICE,"SYNC append only file rewrite performed");
6905 return REDIS_OK;
6906
6907werr:
6908 fclose(fp);
6909 unlink(tmpfile);
e96e4fbf 6910 redisLog(REDIS_WARNING,"Write error writing append only file on disk: %s", strerror(errno));
9d65a1bb 6911 if (di) dictReleaseIterator(di);
6912 return REDIS_ERR;
6913}
6914
6915/* This is how rewriting of the append only file in background works:
6916 *
6917 * 1) The user calls BGREWRITEAOF
6918 * 2) Redis calls this function, that forks():
6919 * 2a) the child rewrite the append only file in a temp file.
6920 * 2b) the parent accumulates differences in server.bgrewritebuf.
6921 * 3) When the child finished '2a' exists.
6922 * 4) The parent will trap the exit code, if it's OK, will append the
6923 * data accumulated into server.bgrewritebuf into the temp file, and
6924 * finally will rename(2) the temp file in the actual file name.
6925 * The the new file is reopened as the new append only file. Profit!
6926 */
6927static int rewriteAppendOnlyFileBackground(void) {
6928 pid_t childpid;
6929
6930 if (server.bgrewritechildpid != -1) return REDIS_ERR;
054e426d 6931 if (server.vm_enabled) waitEmptyIOJobsQueue();
9d65a1bb 6932 if ((childpid = fork()) == 0) {
6933 /* Child */
6934 char tmpfile[256];
9d65a1bb 6935
054e426d 6936 if (server.vm_enabled) vmReopenSwapFile();
6937 close(server.fd);
9d65a1bb 6938 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
6939 if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
6940 exit(0);
6941 } else {
6942 exit(1);
6943 }
6944 } else {
6945 /* Parent */
6946 if (childpid == -1) {
6947 redisLog(REDIS_WARNING,
6948 "Can't rewrite append only file in background: fork: %s",
6949 strerror(errno));
6950 return REDIS_ERR;
6951 }
6952 redisLog(REDIS_NOTICE,
6953 "Background append only file rewriting started by pid %d",childpid);
6954 server.bgrewritechildpid = childpid;
85a83172 6955 /* We set appendseldb to -1 in order to force the next call to the
6956 * feedAppendOnlyFile() to issue a SELECT command, so the differences
6957 * accumulated by the parent into server.bgrewritebuf will start
6958 * with a SELECT statement and it will be safe to merge. */
6959 server.appendseldb = -1;
9d65a1bb 6960 return REDIS_OK;
6961 }
6962 return REDIS_OK; /* unreached */
6963}
6964
6965static void bgrewriteaofCommand(redisClient *c) {
6966 if (server.bgrewritechildpid != -1) {
6967 addReplySds(c,sdsnew("-ERR background append only file rewriting already in progress\r\n"));
6968 return;
6969 }
6970 if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
49b99ab4 6971 char *status = "+Background append only file rewriting started\r\n";
6972 addReplySds(c,sdsnew(status));
9d65a1bb 6973 } else {
6974 addReply(c,shared.err);
6975 }
6976}
6977
6978static void aofRemoveTempFile(pid_t childpid) {
6979 char tmpfile[256];
6980
6981 snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) childpid);
6982 unlink(tmpfile);
6983}
6984
996cb5f7 6985/* Virtual Memory is composed mainly of two subsystems:
6986 * - Blocking Virutal Memory
6987 * - Threaded Virtual Memory I/O
6988 * The two parts are not fully decoupled, but functions are split among two
6989 * different sections of the source code (delimited by comments) in order to
6990 * make more clear what functionality is about the blocking VM and what about
6991 * the threaded (not blocking) VM.
6992 *
6993 * Redis VM design:
6994 *
6995 * Redis VM is a blocking VM (one that blocks reading swapped values from
6996 * disk into memory when a value swapped out is needed in memory) that is made
6997 * unblocking by trying to examine the command argument vector in order to
6998 * load in background values that will likely be needed in order to exec
6999 * the command. The command is executed only once all the relevant keys
7000 * are loaded into memory.
7001 *
7002 * This basically is almost as simple of a blocking VM, but almost as parallel
7003 * as a fully non-blocking VM.
7004 */
7005
7006/* =================== Virtual Memory - Blocking Side ====================== */
054e426d 7007
7008/* substitute the first occurrence of '%p' with the process pid in the
7009 * swap file name. */
7010static void expandVmSwapFilename(void) {
7011 char *p = strstr(server.vm_swap_file,"%p");
7012 sds new;
7013
7014 if (!p) return;
7015 new = sdsempty();
7016 *p = '\0';
7017 new = sdscat(new,server.vm_swap_file);
7018 new = sdscatprintf(new,"%ld",(long) getpid());
7019 new = sdscat(new,p+2);
7020 zfree(server.vm_swap_file);
7021 server.vm_swap_file = new;
7022}
7023
75680a3c 7024static void vmInit(void) {
7025 off_t totsize;
996cb5f7 7026 int pipefds[2];
bcaa7a4f 7027 size_t stacksize;
75680a3c 7028
4ad37480 7029 if (server.vm_max_threads != 0)
7030 zmalloc_enable_thread_safeness(); /* we need thread safe zmalloc() */
7031
054e426d 7032 expandVmSwapFilename();
7033 redisLog(REDIS_NOTICE,"Using '%s' as swap file",server.vm_swap_file);
6fa987e3 7034 if ((server.vm_fp = fopen(server.vm_swap_file,"r+b")) == NULL) {
7035 server.vm_fp = fopen(server.vm_swap_file,"w+b");
7036 }
75680a3c 7037 if (server.vm_fp == NULL) {
6fa987e3 7038 redisLog(REDIS_WARNING,
7039 "Impossible to open the swap file: %s. Exiting.",
7040 strerror(errno));
75680a3c 7041 exit(1);
7042 }
7043 server.vm_fd = fileno(server.vm_fp);
7044 server.vm_next_page = 0;
7045 server.vm_near_pages = 0;
7d98e08c 7046 server.vm_stats_used_pages = 0;
7047 server.vm_stats_swapped_objects = 0;
7048 server.vm_stats_swapouts = 0;
7049 server.vm_stats_swapins = 0;
75680a3c 7050 totsize = server.vm_pages*server.vm_page_size;
7051 redisLog(REDIS_NOTICE,"Allocating %lld bytes of swap file",totsize);
7052 if (ftruncate(server.vm_fd,totsize) == -1) {
7053 redisLog(REDIS_WARNING,"Can't ftruncate swap file: %s. Exiting.",
7054 strerror(errno));
7055 exit(1);
7056 } else {
7057 redisLog(REDIS_NOTICE,"Swap file allocated with success");
7058 }
7d30035d 7059 server.vm_bitmap = zmalloc((server.vm_pages+7)/8);
f870935d 7060 redisLog(REDIS_VERBOSE,"Allocated %lld bytes page table for %lld pages",
4ef8de8a 7061 (long long) (server.vm_pages+7)/8, server.vm_pages);
7d30035d 7062 memset(server.vm_bitmap,0,(server.vm_pages+7)/8);
92f8e882 7063
996cb5f7 7064 /* Initialize threaded I/O (used by Virtual Memory) */
7065 server.io_newjobs = listCreate();
7066 server.io_processing = listCreate();
7067 server.io_processed = listCreate();
92f8e882 7068 server.io_clients = listCreate();
7069 pthread_mutex_init(&server.io_mutex,NULL);
a5819310 7070 pthread_mutex_init(&server.obj_freelist_mutex,NULL);
7071 pthread_mutex_init(&server.io_swapfile_mutex,NULL);
92f8e882 7072 server.io_active_threads = 0;
996cb5f7 7073 if (pipe(pipefds) == -1) {
7074 redisLog(REDIS_WARNING,"Unable to intialized VM: pipe(2): %s. Exiting."
7075 ,strerror(errno));
7076 exit(1);
7077 }
7078 server.io_ready_pipe_read = pipefds[0];
7079 server.io_ready_pipe_write = pipefds[1];
7080 redisAssert(anetNonBlock(NULL,server.io_ready_pipe_read) != ANET_ERR);
bcaa7a4f 7081 /* LZF requires a lot of stack */
7082 pthread_attr_init(&server.io_threads_attr);
7083 pthread_attr_getstacksize(&server.io_threads_attr, &stacksize);
7084 while (stacksize < REDIS_THREAD_STACK_SIZE) stacksize *= 2;
7085 pthread_attr_setstacksize(&server.io_threads_attr, stacksize);
b9bc0eef 7086 /* Listen for events in the threaded I/O pipe */
7087 if (aeCreateFileEvent(server.el, server.io_ready_pipe_read, AE_READABLE,
7088 vmThreadedIOCompletedJob, NULL) == AE_ERR)
7089 oom("creating file event");
75680a3c 7090}
7091
06224fec 7092/* Mark the page as used */
7093static void vmMarkPageUsed(off_t page) {
7094 off_t byte = page/8;
7095 int bit = page&7;
970e10bb 7096 redisAssert(vmFreePage(page) == 1);
06224fec 7097 server.vm_bitmap[byte] |= 1<<bit;
f870935d 7098 redisLog(REDIS_DEBUG,"Mark used: %lld (byte:%lld bit:%d)\n",
7099 (long long)page, (long long)byte, bit);
06224fec 7100}
7101
7102/* Mark N contiguous pages as used, with 'page' being the first. */
7103static void vmMarkPagesUsed(off_t page, off_t count) {
7104 off_t j;
7105
7106 for (j = 0; j < count; j++)
7d30035d 7107 vmMarkPageUsed(page+j);
7d98e08c 7108 server.vm_stats_used_pages += count;
06224fec 7109}
7110
7111/* Mark the page as free */
7112static void vmMarkPageFree(off_t page) {
7113 off_t byte = page/8;
7114 int bit = page&7;
970e10bb 7115 redisAssert(vmFreePage(page) == 0);
06224fec 7116 server.vm_bitmap[byte] &= ~(1<<bit);
970e10bb 7117 redisLog(REDIS_DEBUG,"Mark free: %lld (byte:%lld bit:%d)\n",
7118 (long long)page, (long long)byte, bit);
06224fec 7119}
7120
7121/* Mark N contiguous pages as free, with 'page' being the first. */
7122static void vmMarkPagesFree(off_t page, off_t count) {
7123 off_t j;
7124
7125 for (j = 0; j < count; j++)
7d30035d 7126 vmMarkPageFree(page+j);
7d98e08c 7127 server.vm_stats_used_pages -= count;
970e10bb 7128 if (server.vm_stats_used_pages > 100000000) {
7129 *((char*)-1) = 'x';
7130 }
06224fec 7131}
7132
7133/* Test if the page is free */
7134static int vmFreePage(off_t page) {
7135 off_t byte = page/8;
7136 int bit = page&7;
7d30035d 7137 return (server.vm_bitmap[byte] & (1<<bit)) == 0;
06224fec 7138}
7139
7140/* Find N contiguous free pages storing the first page of the cluster in *first.
3a66edc7 7141 * Returns REDIS_OK if it was able to find N contiguous pages, otherwise
7142 * REDIS_ERR is returned.
06224fec 7143 *
7144 * This function uses a simple algorithm: we try to allocate
7145 * REDIS_VM_MAX_NEAR_PAGES sequentially, when we reach this limit we start
7146 * again from the start of the swap file searching for free spaces.
7147 *
7148 * If it looks pretty clear that there are no free pages near our offset
7149 * we try to find less populated places doing a forward jump of
7150 * REDIS_VM_MAX_RANDOM_JUMP, then we start scanning again a few pages
7151 * without hurry, and then we jump again and so forth...
7152 *
7153 * This function can be improved using a free list to avoid to guess
7154 * too much, since we could collect data about freed pages.
7155 *
7156 * note: I implemented this function just after watching an episode of
7157 * Battlestar Galactica, where the hybrid was continuing to say "JUMP!"
7158 */
c7df85a4 7159static int vmFindContiguousPages(off_t *first, off_t n) {
06224fec 7160 off_t base, offset = 0, since_jump = 0, numfree = 0;
7161
7162 if (server.vm_near_pages == REDIS_VM_MAX_NEAR_PAGES) {
7163 server.vm_near_pages = 0;
7164 server.vm_next_page = 0;
7165 }
7166 server.vm_near_pages++; /* Yet another try for pages near to the old ones */
7167 base = server.vm_next_page;
7168
7169 while(offset < server.vm_pages) {
7170 off_t this = base+offset;
7171
7172 /* If we overflow, restart from page zero */
7173 if (this >= server.vm_pages) {
7174 this -= server.vm_pages;
7175 if (this == 0) {
7176 /* Just overflowed, what we found on tail is no longer
7177 * interesting, as it's no longer contiguous. */
7178 numfree = 0;
7179 }
7180 }
f6c0bba8 7181 redisLog(REDIS_DEBUG, "THIS: %lld (%c)\n", (long long) this, vmFreePage(this) ? 'F' : 'X');
06224fec 7182 if (vmFreePage(this)) {
7183 /* This is a free page */
7184 numfree++;
7185 /* Already got N free pages? Return to the caller, with success */
7186 if (numfree == n) {
7d30035d 7187 *first = this-(n-1);
7188 server.vm_next_page = this+1;
3a66edc7 7189 return REDIS_OK;
06224fec 7190 }
7191 } else {
7192 /* The current one is not a free page */
7193 numfree = 0;
7194 }
7195
7196 /* Fast-forward if the current page is not free and we already
7197 * searched enough near this place. */
7198 since_jump++;
7199 if (!numfree && since_jump >= REDIS_VM_MAX_RANDOM_JUMP/4) {
7200 offset += random() % REDIS_VM_MAX_RANDOM_JUMP;
7201 since_jump = 0;
7202 /* Note that even if we rewind after the jump, we are don't need
7203 * to make sure numfree is set to zero as we only jump *if* it
7204 * is set to zero. */
7205 } else {
7206 /* Otherwise just check the next page */
7207 offset++;
7208 }
7209 }
3a66edc7 7210 return REDIS_ERR;
7211}
7212
a5819310 7213/* Write the specified object at the specified page of the swap file */
7214static int vmWriteObjectOnSwap(robj *o, off_t page) {
7215 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
7216 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
7217 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
7218 redisLog(REDIS_WARNING,
7219 "Critical VM problem in vmSwapObjectBlocking(): can't seek: %s",
7220 strerror(errno));
7221 return REDIS_ERR;
7222 }
7223 rdbSaveObject(server.vm_fp,o);
7224 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
7225 return REDIS_OK;
7226}
7227
3a66edc7 7228/* Swap the 'val' object relative to 'key' into disk. Store all the information
7229 * needed to later retrieve the object into the key object.
7230 * If we can't find enough contiguous empty pages to swap the object on disk
7231 * REDIS_ERR is returned. */
a69a0c9c 7232static int vmSwapObjectBlocking(robj *key, robj *val) {
b9bc0eef 7233 off_t pages = rdbSavedObjectPages(val,NULL);
3a66edc7 7234 off_t page;
7235
7236 assert(key->storage == REDIS_VM_MEMORY);
4ef8de8a 7237 assert(key->refcount == 1);
3a66edc7 7238 if (vmFindContiguousPages(&page,pages) == REDIS_ERR) return REDIS_ERR;
a5819310 7239 if (vmWriteObjectOnSwap(val,page) == REDIS_ERR) return REDIS_ERR;
3a66edc7 7240 key->vm.page = page;
7241 key->vm.usedpages = pages;
7242 key->storage = REDIS_VM_SWAPPED;
d894161b 7243 key->vtype = val->type;
3a66edc7 7244 decrRefCount(val); /* Deallocate the object from memory. */
7245 vmMarkPagesUsed(page,pages);
7d30035d 7246 redisLog(REDIS_DEBUG,"VM: object %s swapped out at %lld (%lld pages)",
7247 (unsigned char*) key->ptr,
7248 (unsigned long long) page, (unsigned long long) pages);
7d98e08c 7249 server.vm_stats_swapped_objects++;
7250 server.vm_stats_swapouts++;
0841cc92 7251 fflush(server.vm_fp);
3a66edc7 7252 return REDIS_OK;
7253}
7254
a5819310 7255static robj *vmReadObjectFromSwap(off_t page, int type) {
7256 robj *o;
3a66edc7 7257
a5819310 7258 if (server.vm_enabled) pthread_mutex_lock(&server.io_swapfile_mutex);
7259 if (fseeko(server.vm_fp,page*server.vm_page_size,SEEK_SET) == -1) {
3a66edc7 7260 redisLog(REDIS_WARNING,
7261 "Unrecoverable VM problem in vmLoadObject(): can't seek: %s",
7262 strerror(errno));
7263 exit(1);
7264 }
a5819310 7265 o = rdbLoadObject(type,server.vm_fp);
7266 if (o == NULL) {
3a66edc7 7267 redisLog(REDIS_WARNING, "Unrecoverable VM problem in vmLoadObject(): can't load object from swap file: %s", strerror(errno));
7268 exit(1);
7269 }
a5819310 7270 if (server.vm_enabled) pthread_mutex_unlock(&server.io_swapfile_mutex);
7271 return o;
7272}
7273
7274/* Load the value object relative to the 'key' object from swap to memory.
7275 * The newly allocated object is returned.
7276 *
7277 * If preview is true the unserialized object is returned to the caller but
7278 * no changes are made to the key object, nor the pages are marked as freed */
7279static robj *vmGenericLoadObject(robj *key, int preview) {
7280 robj *val;
7281
7282 redisAssert(key->storage == REDIS_VM_SWAPPED);
7283 val = vmReadObjectFromSwap(key->vm.page,key->vtype);
7e69548d 7284 if (!preview) {
7285 key->storage = REDIS_VM_MEMORY;
7286 key->vm.atime = server.unixtime;
7287 vmMarkPagesFree(key->vm.page,key->vm.usedpages);
7288 redisLog(REDIS_DEBUG, "VM: object %s loaded from disk",
7289 (unsigned char*) key->ptr);
7d98e08c 7290 server.vm_stats_swapped_objects--;
38aba9a1 7291 } else {
7292 redisLog(REDIS_DEBUG, "VM: object %s previewed from disk",
7293 (unsigned char*) key->ptr);
7e69548d 7294 }
7d98e08c 7295 server.vm_stats_swapins++;
3a66edc7 7296 return val;
06224fec 7297}
7298
7e69548d 7299/* Plain object loading, from swap to memory */
7300static robj *vmLoadObject(robj *key) {
996cb5f7 7301 /* If we are loading the object in background, stop it, we
7302 * need to load this object synchronously ASAP. */
7303 if (key->storage == REDIS_VM_LOADING)
7304 vmCancelThreadedIOJob(key);
7e69548d 7305 return vmGenericLoadObject(key,0);
7306}
7307
7308/* Just load the value on disk, without to modify the key.
7309 * This is useful when we want to perform some operation on the value
7310 * without to really bring it from swap to memory, like while saving the
7311 * dataset or rewriting the append only log. */
7312static robj *vmPreviewObject(robj *key) {
7313 return vmGenericLoadObject(key,1);
7314}
7315
4ef8de8a 7316/* How a good candidate is this object for swapping?
7317 * The better candidate it is, the greater the returned value.
7318 *
7319 * Currently we try to perform a fast estimation of the object size in
7320 * memory, and combine it with aging informations.
7321 *
7322 * Basically swappability = idle-time * log(estimated size)
7323 *
7324 * Bigger objects are preferred over smaller objects, but not
7325 * proportionally, this is why we use the logarithm. This algorithm is
7326 * just a first try and will probably be tuned later. */
7327static double computeObjectSwappability(robj *o) {
7328 time_t age = server.unixtime - o->vm.atime;
7329 long asize = 0;
7330 list *l;
7331 dict *d;
7332 struct dictEntry *de;
7333 int z;
7334
7335 if (age <= 0) return 0;
7336 switch(o->type) {
7337 case REDIS_STRING:
7338 if (o->encoding != REDIS_ENCODING_RAW) {
7339 asize = sizeof(*o);
7340 } else {
7341 asize = sdslen(o->ptr)+sizeof(*o)+sizeof(long)*2;
7342 }
7343 break;
7344 case REDIS_LIST:
7345 l = o->ptr;
7346 listNode *ln = listFirst(l);
7347
7348 asize = sizeof(list);
7349 if (ln) {
7350 robj *ele = ln->value;
7351 long elesize;
7352
7353 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
7354 (sizeof(*o)+sdslen(ele->ptr)) :
7355 sizeof(*o);
7356 asize += (sizeof(listNode)+elesize)*listLength(l);
7357 }
7358 break;
7359 case REDIS_SET:
7360 case REDIS_ZSET:
7361 z = (o->type == REDIS_ZSET);
7362 d = z ? ((zset*)o->ptr)->dict : o->ptr;
7363
7364 asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
7365 if (z) asize += sizeof(zset)-sizeof(dict);
7366 if (dictSize(d)) {
7367 long elesize;
7368 robj *ele;
7369
7370 de = dictGetRandomKey(d);
7371 ele = dictGetEntryKey(de);
7372 elesize = (ele->encoding == REDIS_ENCODING_RAW) ?
7373 (sizeof(*o)+sdslen(ele->ptr)) :
7374 sizeof(*o);
7375 asize += (sizeof(struct dictEntry)+elesize)*dictSize(d);
7376 if (z) asize += sizeof(zskiplistNode)*dictSize(d);
7377 }
7378 break;
7379 }
7380 return (double)asize*log(1+asize);
7381}
7382
7383/* Try to swap an object that's a good candidate for swapping.
7384 * Returns REDIS_OK if the object was swapped, REDIS_ERR if it's not possible
a69a0c9c 7385 * to swap any object at all.
7386 *
7387 * If 'usethreaded' is true, Redis will try to swap the object in background
7388 * using I/O threads. */
7389static int vmSwapOneObject(int usethreads) {
4ef8de8a 7390 int j, i;
7391 struct dictEntry *best = NULL;
7392 double best_swappability = 0;
b9bc0eef 7393 redisDb *best_db = NULL;
4ef8de8a 7394 robj *key, *val;
7395
7396 for (j = 0; j < server.dbnum; j++) {
7397 redisDb *db = server.db+j;
e3cadb8a 7398 int maxtries = 1000;
4ef8de8a 7399
7400 if (dictSize(db->dict) == 0) continue;
7401 for (i = 0; i < 5; i++) {
7402 dictEntry *de;
7403 double swappability;
7404
e3cadb8a 7405 if (maxtries) maxtries--;
4ef8de8a 7406 de = dictGetRandomKey(db->dict);
7407 key = dictGetEntryKey(de);
7408 val = dictGetEntryVal(de);
1064ef87 7409 /* Only swap objects that are currently in memory.
7410 *
7411 * Also don't swap shared objects if threaded VM is on, as we
7412 * try to ensure that the main thread does not touch the
7413 * object while the I/O thread is using it, but we can't
7414 * control other keys without adding additional mutex. */
7415 if (key->storage != REDIS_VM_MEMORY ||
7416 (server.vm_max_threads != 0 && val->refcount != 1)) {
e3cadb8a 7417 if (maxtries) i--; /* don't count this try */
7418 continue;
7419 }
4ef8de8a 7420 swappability = computeObjectSwappability(val);
7421 if (!best || swappability > best_swappability) {
7422 best = de;
7423 best_swappability = swappability;
b9bc0eef 7424 best_db = db;
4ef8de8a 7425 }
7426 }
7427 }
e3cadb8a 7428 if (best == NULL) {
7429 redisLog(REDIS_DEBUG,"No swappable key found!");
7430 return REDIS_ERR;
7431 }
4ef8de8a 7432 key = dictGetEntryKey(best);
7433 val = dictGetEntryVal(best);
7434
e3cadb8a 7435 redisLog(REDIS_DEBUG,"Key with best swappability: %s, %f",
4ef8de8a 7436 key->ptr, best_swappability);
7437
7438 /* Unshare the key if needed */
7439 if (key->refcount > 1) {
7440 robj *newkey = dupStringObject(key);
7441 decrRefCount(key);
7442 key = dictGetEntryKey(best) = newkey;
7443 }
7444 /* Swap it */
a69a0c9c 7445 if (usethreads) {
b9bc0eef 7446 vmSwapObjectThreaded(key,val,best_db);
4ef8de8a 7447 return REDIS_OK;
7448 } else {
a69a0c9c 7449 if (vmSwapObjectBlocking(key,val) == REDIS_OK) {
7450 dictGetEntryVal(best) = NULL;
7451 return REDIS_OK;
7452 } else {
7453 return REDIS_ERR;
7454 }
4ef8de8a 7455 }
7456}
7457
a69a0c9c 7458static int vmSwapOneObjectBlocking() {
7459 return vmSwapOneObject(0);
7460}
7461
7462static int vmSwapOneObjectThreaded() {
7463 return vmSwapOneObject(1);
7464}
7465
7e69548d 7466/* Return true if it's safe to swap out objects in a given moment.
7467 * Basically we don't want to swap objects out while there is a BGSAVE
7468 * or a BGAEOREWRITE running in backgroud. */
7469static int vmCanSwapOut(void) {
7470 return (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1);
7471}
7472
1b03836c 7473/* Delete a key if swapped. Returns 1 if the key was found, was swapped
7474 * and was deleted. Otherwise 0 is returned. */
7475static int deleteIfSwapped(redisDb *db, robj *key) {
7476 dictEntry *de;
7477 robj *foundkey;
7478
7479 if ((de = dictFind(db->dict,key)) == NULL) return 0;
7480 foundkey = dictGetEntryKey(de);
7481 if (foundkey->storage == REDIS_VM_MEMORY) return 0;
7482 deleteKey(db,key);
7483 return 1;
7484}
7485
996cb5f7 7486/* =================== Virtual Memory - Threaded I/O ======================= */
7487
b9bc0eef 7488static void freeIOJob(iojob *j) {
7489 if (j->type == REDIS_IOJOB_PREPARE_SWAP ||
7490 j->type == REDIS_IOJOB_DO_SWAP)
7491 decrRefCount(j->val);
7492 decrRefCount(j->key);
7493 zfree(j);
7494}
7495
996cb5f7 7496/* Every time a thread finished a Job, it writes a byte into the write side
7497 * of an unix pipe in order to "awake" the main thread, and this function
7498 * is called. */
7499static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
7500 int mask)
7501{
7502 char buf[1];
7503 int retval;
c953f24b 7504 int processed = 0;
f6c0bba8 7505 int toprocess = -1;
996cb5f7 7506 REDIS_NOTUSED(el);
7507 REDIS_NOTUSED(mask);
7508 REDIS_NOTUSED(privdata);
7509
7510 /* For every byte we read in the read side of the pipe, there is one
7511 * I/O job completed to process. */
7512 while((retval = read(fd,buf,1)) == 1) {
b9bc0eef 7513 iojob *j;
7514 listNode *ln;
7515 robj *key;
7516 struct dictEntry *de;
7517
996cb5f7 7518 redisLog(REDIS_DEBUG,"Processing I/O completed job");
b9bc0eef 7519
7520 /* Get the processed element (the oldest one) */
7521 lockThreadedIO();
1064ef87 7522 assert(listLength(server.io_processed) != 0);
f6c0bba8 7523 if (toprocess == -1) {
7524 toprocess = (listLength(server.io_processed)*REDIS_MAX_COMPLETED_JOBS_PROCESSED)/100;
7525 if (toprocess <= 0) toprocess = 1;
7526 }
b9bc0eef 7527 ln = listFirst(server.io_processed);
7528 j = ln->value;
7529 listDelNode(server.io_processed,ln);
7530 unlockThreadedIO();
7531 /* If this job is marked as canceled, just ignore it */
7532 if (j->canceled) {
7533 freeIOJob(j);
7534 continue;
7535 }
7536 /* Post process it in the main thread, as there are things we
7537 * can do just here to avoid race conditions and/or invasive locks */
6c96ba7d 7538 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 7539 de = dictFind(j->db->dict,j->key);
7540 assert(de != NULL);
7541 key = dictGetEntryKey(de);
7542 if (j->type == REDIS_IOJOB_LOAD) {
7543 /* Key loaded, bring it at home */
7544 key->storage = REDIS_VM_MEMORY;
7545 key->vm.atime = server.unixtime;
7546 vmMarkPagesFree(key->vm.page,key->vm.usedpages);
7547 redisLog(REDIS_DEBUG, "VM: object %s loaded from disk (threaded)",
7548 (unsigned char*) key->ptr);
7549 server.vm_stats_swapped_objects--;
7550 server.vm_stats_swapins++;
7551 freeIOJob(j);
7552 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
7553 /* Now we know the amount of pages required to swap this object.
7554 * Let's find some space for it, and queue this task again
7555 * rebranded as REDIS_IOJOB_DO_SWAP. */
054e426d 7556 if (!vmCanSwapOut() ||
7557 vmFindContiguousPages(&j->page,j->pages) == REDIS_ERR)
7558 {
7559 /* Ooops... no space or we can't swap as there is
7560 * a fork()ed Redis trying to save stuff on disk. */
b9bc0eef 7561 freeIOJob(j);
054e426d 7562 key->storage = REDIS_VM_MEMORY; /* undo operation */
b9bc0eef 7563 } else {
c7df85a4 7564 /* Note that we need to mark this pages as used now,
7565 * if the job will be canceled, we'll mark them as freed
7566 * again. */
7567 vmMarkPagesUsed(j->page,j->pages);
b9bc0eef 7568 j->type = REDIS_IOJOB_DO_SWAP;
7569 lockThreadedIO();
7570 queueIOJob(j);
7571 unlockThreadedIO();
7572 }
7573 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
7574 robj *val;
7575
7576 /* Key swapped. We can finally free some memory. */
6c96ba7d 7577 if (key->storage != REDIS_VM_SWAPPING) {
7578 printf("key->storage: %d\n",key->storage);
7579 printf("key->name: %s\n",(char*)key->ptr);
7580 printf("key->refcount: %d\n",key->refcount);
7581 printf("val: %p\n",(void*)j->val);
7582 printf("val->type: %d\n",j->val->type);
7583 printf("val->ptr: %s\n",(char*)j->val->ptr);
7584 }
7585 redisAssert(key->storage == REDIS_VM_SWAPPING);
b9bc0eef 7586 val = dictGetEntryVal(de);
7587 key->vm.page = j->page;
7588 key->vm.usedpages = j->pages;
7589 key->storage = REDIS_VM_SWAPPED;
7590 key->vtype = j->val->type;
7591 decrRefCount(val); /* Deallocate the object from memory. */
f11b8647 7592 dictGetEntryVal(de) = NULL;
b9bc0eef 7593 redisLog(REDIS_DEBUG,
7594 "VM: object %s swapped out at %lld (%lld pages) (threaded)",
7595 (unsigned char*) key->ptr,
7596 (unsigned long long) j->page, (unsigned long long) j->pages);
7597 server.vm_stats_swapped_objects++;
7598 server.vm_stats_swapouts++;
7599 freeIOJob(j);
f11b8647 7600 /* Put a few more swap requests in queue if we are still
7601 * out of memory */
054e426d 7602 if (vmCanSwapOut() && zmalloc_used_memory() > server.vm_max_memory){
f11b8647 7603 int more = 1;
7604 while(more) {
7605 lockThreadedIO();
7606 more = listLength(server.io_newjobs) <
7607 (unsigned) server.vm_max_threads;
7608 unlockThreadedIO();
7609 /* Don't waste CPU time if swappable objects are rare. */
7610 if (vmSwapOneObjectThreaded() == REDIS_ERR) break;
7611 }
7612 }
b9bc0eef 7613 }
c953f24b 7614 processed++;
f6c0bba8 7615 if (processed == toprocess) return;
996cb5f7 7616 }
7617 if (retval < 0 && errno != EAGAIN) {
7618 redisLog(REDIS_WARNING,
7619 "WARNING: read(2) error in vmThreadedIOCompletedJob() %s",
7620 strerror(errno));
7621 }
7622}
7623
7624static void lockThreadedIO(void) {
7625 pthread_mutex_lock(&server.io_mutex);
7626}
7627
7628static void unlockThreadedIO(void) {
7629 pthread_mutex_unlock(&server.io_mutex);
7630}
7631
7632/* Remove the specified object from the threaded I/O queue if still not
7633 * processed, otherwise make sure to flag it as canceled. */
7634static void vmCancelThreadedIOJob(robj *o) {
7635 list *lists[3] = {
6c96ba7d 7636 server.io_newjobs, /* 0 */
7637 server.io_processing, /* 1 */
7638 server.io_processed /* 2 */
996cb5f7 7639 };
7640 int i;
7641
7642 assert(o->storage == REDIS_VM_LOADING || o->storage == REDIS_VM_SWAPPING);
2e111efe 7643again:
996cb5f7 7644 lockThreadedIO();
7645 /* Search for a matching key in one of the queues */
7646 for (i = 0; i < 3; i++) {
7647 listNode *ln;
c7df85a4 7648 listIter li;
996cb5f7 7649
c7df85a4 7650 listRewind(lists[i],&li);
7651 while ((ln = listNext(&li)) != NULL) {
996cb5f7 7652 iojob *job = ln->value;
7653
6c96ba7d 7654 if (job->canceled) continue; /* Skip this, already canceled. */
996cb5f7 7655 if (compareStringObjects(job->key,o) == 0) {
970e10bb 7656 redisLog(REDIS_DEBUG,"*** CANCELED %p (%s) (type %d) (LIST ID %d)\n",
7657 (void*)job, (char*)o->ptr, job->type, i);
427a2153 7658 /* Mark the pages as free since the swap didn't happened
7659 * or happened but is now discarded. */
970e10bb 7660 if (i != 1 && job->type == REDIS_IOJOB_DO_SWAP)
427a2153 7661 vmMarkPagesFree(job->page,job->pages);
7662 /* Cancel the job. It depends on the list the job is
7663 * living in. */
996cb5f7 7664 switch(i) {
7665 case 0: /* io_newjobs */
6c96ba7d 7666 /* If the job was yet not processed the best thing to do
996cb5f7 7667 * is to remove it from the queue at all */
6c96ba7d 7668 freeIOJob(job);
996cb5f7 7669 listDelNode(lists[i],ln);
7670 break;
7671 case 1: /* io_processing */
2e111efe 7672 /* Oh Shi- the thread is messing with the Job, and
7673 * probably with the object if this is a
7674 * PREPARE_SWAP or DO_SWAP job. Better to wait for the
7675 * job to move into the next queue... */
7676 if (job->type != REDIS_IOJOB_LOAD) {
7677 /* Yes, we try again and again until the job
7678 * is completed. */
7679 unlockThreadedIO();
7680 /* But let's wait some time for the I/O thread
7681 * to finish with this job. After all this condition
7682 * should be very rare. */
7683 usleep(1);
7684 goto again;
7685 } else {
7686 job->canceled = 1;
7687 break;
7688 }
996cb5f7 7689 case 2: /* io_processed */
2e111efe 7690 /* The job was already processed, that's easy...
7691 * just mark it as canceled so that we'll ignore it
7692 * when processing completed jobs. */
996cb5f7 7693 job->canceled = 1;
7694 break;
7695 }
c7df85a4 7696 /* Finally we have to adjust the storage type of the object
7697 * in order to "UNDO" the operaiton. */
996cb5f7 7698 if (o->storage == REDIS_VM_LOADING)
7699 o->storage = REDIS_VM_SWAPPED;
7700 else if (o->storage == REDIS_VM_SWAPPING)
7701 o->storage = REDIS_VM_MEMORY;
7702 unlockThreadedIO();
7703 return;
7704 }
7705 }
7706 }
7707 unlockThreadedIO();
7708 assert(1 != 1); /* We should never reach this */
7709}
7710
b9bc0eef 7711static void *IOThreadEntryPoint(void *arg) {
7712 iojob *j;
7713 listNode *ln;
7714 REDIS_NOTUSED(arg);
7715
7716 pthread_detach(pthread_self());
7717 while(1) {
7718 /* Get a new job to process */
7719 lockThreadedIO();
7720 if (listLength(server.io_newjobs) == 0) {
7721 /* No new jobs in queue, exit. */
b74880b4 7722 redisLog(REDIS_DEBUG,"Thread %lld exiting, nothing to do",
b9bc0eef 7723 (long long) pthread_self());
7724 server.io_active_threads--;
7725 unlockThreadedIO();
7726 return NULL;
7727 }
7728 ln = listFirst(server.io_newjobs);
7729 j = ln->value;
7730 listDelNode(server.io_newjobs,ln);
7731 /* Add the job in the processing queue */
7732 j->thread = pthread_self();
7733 listAddNodeTail(server.io_processing,j);
7734 ln = listLast(server.io_processing); /* We use ln later to remove it */
7735 unlockThreadedIO();
b74880b4 7736 redisLog(REDIS_DEBUG,"Thread %lld got a new job (type %d): %p about key '%s'",
6c96ba7d 7737 (long long) pthread_self(), j->type, (void*)j, (char*)j->key->ptr);
b9bc0eef 7738
7739 /* Process the Job */
7740 if (j->type == REDIS_IOJOB_LOAD) {
7741 } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) {
7742 FILE *fp = fopen("/dev/null","w+");
7743 j->pages = rdbSavedObjectPages(j->val,fp);
7744 fclose(fp);
7745 } else if (j->type == REDIS_IOJOB_DO_SWAP) {
a5819310 7746 if (vmWriteObjectOnSwap(j->val,j->page) == REDIS_ERR)
7747 j->canceled = 1;
b9bc0eef 7748 }
7749
7750 /* Done: insert the job into the processed queue */
b74880b4 7751 redisLog(REDIS_DEBUG,"Thread %lld completed the job: %p (key %s)",
6c96ba7d 7752 (long long) pthread_self(), (void*)j, (char*)j->key->ptr);
b9bc0eef 7753 lockThreadedIO();
7754 listDelNode(server.io_processing,ln);
7755 listAddNodeTail(server.io_processed,j);
7756 unlockThreadedIO();
7757
7758 /* Signal the main thread there is new stuff to process */
7759 assert(write(server.io_ready_pipe_write,"x",1) == 1);
7760 }
7761 return NULL; /* never reached */
7762}
7763
7764static void spawnIOThread(void) {
7765 pthread_t thread;
7766
bcaa7a4f 7767 pthread_create(&thread,&server.io_threads_attr,IOThreadEntryPoint,NULL);
b9bc0eef 7768 server.io_active_threads++;
7769}
7770
4ee9488d 7771/* We need to wait for the last thread to exit before we are able to
7772 * fork() in order to BGSAVE or BGREWRITEAOF. */
054e426d 7773static void waitEmptyIOJobsQueue(void) {
4ee9488d 7774 while(1) {
76b7233a 7775 int io_processed_len;
7776
4ee9488d 7777 lockThreadedIO();
054e426d 7778 if (listLength(server.io_newjobs) == 0 &&
7779 listLength(server.io_processing) == 0 &&
7780 server.io_active_threads == 0)
7781 {
4ee9488d 7782 unlockThreadedIO();
7783 return;
7784 }
76b7233a 7785 /* While waiting for empty jobs queue condition we post-process some
7786 * finshed job, as I/O threads may be hanging trying to write against
7787 * the io_ready_pipe_write FD but there are so much pending jobs that
7788 * it's blocking. */
7789 io_processed_len = listLength(server.io_processed);
4ee9488d 7790 unlockThreadedIO();
76b7233a 7791 if (io_processed_len) {
7792 vmThreadedIOCompletedJob(NULL,server.io_ready_pipe_read,NULL,0);
7793 usleep(1000); /* 1 millisecond */
7794 } else {
7795 usleep(10000); /* 10 milliseconds */
7796 }
4ee9488d 7797 }
7798}
7799
054e426d 7800static void vmReopenSwapFile(void) {
7801 fclose(server.vm_fp);
7802 server.vm_fp = fopen(server.vm_swap_file,"r+b");
7803 if (server.vm_fp == NULL) {
7804 redisLog(REDIS_WARNING,"Can't re-open the VM swap file: %s. Exiting.",
7805 server.vm_swap_file);
7806 exit(1);
7807 }
7808 server.vm_fd = fileno(server.vm_fp);
7809}
7810
b9bc0eef 7811/* This function must be called while with threaded IO locked */
7812static void queueIOJob(iojob *j) {
6c96ba7d 7813 redisLog(REDIS_DEBUG,"Queued IO Job %p type %d about key '%s'\n",
7814 (void*)j, j->type, (char*)j->key->ptr);
b9bc0eef 7815 listAddNodeTail(server.io_newjobs,j);
7816 if (server.io_active_threads < server.vm_max_threads)
7817 spawnIOThread();
7818}
7819
7820static int vmSwapObjectThreaded(robj *key, robj *val, redisDb *db) {
7821 iojob *j;
7822
7823 assert(key->storage == REDIS_VM_MEMORY);
7824 assert(key->refcount == 1);
7825
7826 j = zmalloc(sizeof(*j));
7827 j->type = REDIS_IOJOB_PREPARE_SWAP;
7828 j->db = db;
7829 j->key = dupStringObject(key);
7830 j->val = val;
7831 incrRefCount(val);
7832 j->canceled = 0;
7833 j->thread = (pthread_t) -1;
f11b8647 7834 key->storage = REDIS_VM_SWAPPING;
b9bc0eef 7835
7836 lockThreadedIO();
7837 queueIOJob(j);
7838 unlockThreadedIO();
7839 return REDIS_OK;
7840}
7841
7f957c92 7842/* ================================= Debugging ============================== */
7843
7844static void debugCommand(redisClient *c) {
7845 if (!strcasecmp(c->argv[1]->ptr,"segfault")) {
7846 *((char*)-1) = 'x';
210e29f7 7847 } else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
7848 if (rdbSave(server.dbfilename) != REDIS_OK) {
7849 addReply(c,shared.err);
7850 return;
7851 }
7852 emptyDb();
7853 if (rdbLoad(server.dbfilename) != REDIS_OK) {
7854 addReply(c,shared.err);
7855 return;
7856 }
7857 redisLog(REDIS_WARNING,"DB reloaded by DEBUG RELOAD");
7858 addReply(c,shared.ok);
71c2b467 7859 } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) {
7860 emptyDb();
7861 if (loadAppendOnlyFile(server.appendfilename) != REDIS_OK) {
7862 addReply(c,shared.err);
7863 return;
7864 }
7865 redisLog(REDIS_WARNING,"Append Only File loaded by DEBUG LOADAOF");
7866 addReply(c,shared.ok);
333298da 7867 } else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
7868 dictEntry *de = dictFind(c->db->dict,c->argv[2]);
7869 robj *key, *val;
7870
7871 if (!de) {
7872 addReply(c,shared.nokeyerr);
7873 return;
7874 }
7875 key = dictGetEntryKey(de);
7876 val = dictGetEntryVal(de);
b9bc0eef 7877 if (server.vm_enabled && (key->storage == REDIS_VM_MEMORY ||
7878 key->storage == REDIS_VM_SWAPPING)) {
ace06542 7879 addReplySds(c,sdscatprintf(sdsempty(),
7880 "+Key at:%p refcount:%d, value at:%p refcount:%d "
7881 "encoding:%d serializedlength:%lld\r\n",
682ac724 7882 (void*)key, key->refcount, (void*)val, val->refcount,
459f52a8 7883 val->encoding, (long long) rdbSavedObjectLen(val,NULL)));
ace06542 7884 } else {
7885 addReplySds(c,sdscatprintf(sdsempty(),
7886 "+Key at:%p refcount:%d, value swapped at: page %llu "
7887 "using %llu pages\r\n",
7888 (void*)key, key->refcount, (unsigned long long) key->vm.page,
7889 (unsigned long long) key->vm.usedpages));
7890 }
7d30035d 7891 } else if (!strcasecmp(c->argv[1]->ptr,"swapout") && c->argc == 3) {
7892 dictEntry *de = dictFind(c->db->dict,c->argv[2]);
7893 robj *key, *val;
7894
7895 if (!server.vm_enabled) {
7896 addReplySds(c,sdsnew("-ERR Virtual Memory is disabled\r\n"));
7897 return;
7898 }
7899 if (!de) {
7900 addReply(c,shared.nokeyerr);
7901 return;
7902 }
7903 key = dictGetEntryKey(de);
7904 val = dictGetEntryVal(de);
4ef8de8a 7905 /* If the key is shared we want to create a copy */
7906 if (key->refcount > 1) {
7907 robj *newkey = dupStringObject(key);
7908 decrRefCount(key);
7909 key = dictGetEntryKey(de) = newkey;
7910 }
7911 /* Swap it */
7d30035d 7912 if (key->storage != REDIS_VM_MEMORY) {
7913 addReplySds(c,sdsnew("-ERR This key is not in memory\r\n"));
a69a0c9c 7914 } else if (vmSwapObjectBlocking(key,val) == REDIS_OK) {
7d30035d 7915 dictGetEntryVal(de) = NULL;
7916 addReply(c,shared.ok);
7917 } else {
7918 addReply(c,shared.err);
7919 }
7f957c92 7920 } else {
333298da 7921 addReplySds(c,sdsnew(
7d30035d 7922 "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPOUT <key>|RELOAD]\r\n"));
7f957c92 7923 }
7924}
56906eef 7925
6c96ba7d 7926static void _redisAssert(char *estr, char *file, int line) {
dfc5e96c 7927 redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
6c96ba7d 7928 redisLog(REDIS_WARNING,"==> %s:%d '%s' is not true\n",file,line,estr);
dfc5e96c 7929#ifdef HAVE_BACKTRACE
7930 redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
7931 *((char*)-1) = 'x';
7932#endif
7933}
7934
bcfc686d 7935/* =================================== Main! ================================ */
56906eef 7936
bcfc686d 7937#ifdef __linux__
7938int linuxOvercommitMemoryValue(void) {
7939 FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
7940 char buf[64];
56906eef 7941
bcfc686d 7942 if (!fp) return -1;
7943 if (fgets(buf,64,fp) == NULL) {
7944 fclose(fp);
7945 return -1;
7946 }
7947 fclose(fp);
56906eef 7948
bcfc686d 7949 return atoi(buf);
7950}
7951
7952void linuxOvercommitMemoryWarning(void) {
7953 if (linuxOvercommitMemoryValue() == 0) {
7954 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.");
7955 }
7956}
7957#endif /* __linux__ */
7958
7959static void daemonize(void) {
7960 int fd;
7961 FILE *fp;
7962
7963 if (fork() != 0) exit(0); /* parent exits */
7964 setsid(); /* create a new session */
7965
7966 /* Every output goes to /dev/null. If Redis is daemonized but
7967 * the 'logfile' is set to 'stdout' in the configuration file
7968 * it will not log at all. */
7969 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
7970 dup2(fd, STDIN_FILENO);
7971 dup2(fd, STDOUT_FILENO);
7972 dup2(fd, STDERR_FILENO);
7973 if (fd > STDERR_FILENO) close(fd);
7974 }
7975 /* Try to write the pid file */
7976 fp = fopen(server.pidfile,"w");
7977 if (fp) {
7978 fprintf(fp,"%d\n",getpid());
7979 fclose(fp);
56906eef 7980 }
56906eef 7981}
7982
bcfc686d 7983int main(int argc, char **argv) {
7984 initServerConfig();
7985 if (argc == 2) {
7986 resetServerSaveParams();
7987 loadServerConfig(argv[1]);
7988 } else if (argc > 2) {
7989 fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");
7990 exit(1);
7991 } else {
7992 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'");
7993 }
bcfc686d 7994 if (server.daemonize) daemonize();
71c54b21 7995 initServer();
bcfc686d 7996 redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);
7997#ifdef __linux__
7998 linuxOvercommitMemoryWarning();
7999#endif
8000 if (server.appendonly) {
8001 if (loadAppendOnlyFile(server.appendfilename) == REDIS_OK)
8002 redisLog(REDIS_NOTICE,"DB loaded from append only file");
8003 } else {
8004 if (rdbLoad(server.dbfilename) == REDIS_OK)
8005 redisLog(REDIS_NOTICE,"DB loaded from disk");
8006 }
bcfc686d 8007 redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
8008 aeMain(server.el);
8009 aeDeleteEventLoop(server.el);
8010 return 0;
8011}
8012
8013/* ============================= Backtrace support ========================= */
8014
8015#ifdef HAVE_BACKTRACE
8016static char *findFuncName(void *pointer, unsigned long *offset);
8017
56906eef 8018static void *getMcontextEip(ucontext_t *uc) {
8019#if defined(__FreeBSD__)
8020 return (void*) uc->uc_mcontext.mc_eip;
8021#elif defined(__dietlibc__)
8022 return (void*) uc->uc_mcontext.eip;
06db1f50 8023#elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
da0a1620 8024 #if __x86_64__
8025 return (void*) uc->uc_mcontext->__ss.__rip;
8026 #else
56906eef 8027 return (void*) uc->uc_mcontext->__ss.__eip;
da0a1620 8028 #endif
06db1f50 8029#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
cb7e07cc 8030 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
06db1f50 8031 return (void*) uc->uc_mcontext->__ss.__rip;
cbc59b38 8032 #else
8033 return (void*) uc->uc_mcontext->__ss.__eip;
8034 #endif
c04c9ac9 8035#elif defined(__i386__) || defined(__X86_64__) || defined(__x86_64__)
8036 return (void*) uc->uc_mcontext.gregs[REG_EIP]; /* Linux 32/64 bit */
b91cf5ef 8037#elif defined(__ia64__) /* Linux IA64 */
8038 return (void*) uc->uc_mcontext.sc_ip;
8039#else
8040 return NULL;
56906eef 8041#endif
8042}
8043
8044static void segvHandler(int sig, siginfo_t *info, void *secret) {
8045 void *trace[100];
8046 char **messages = NULL;
8047 int i, trace_size = 0;
8048 unsigned long offset=0;
56906eef 8049 ucontext_t *uc = (ucontext_t*) secret;
1c85b79f 8050 sds infostring;
56906eef 8051 REDIS_NOTUSED(info);
8052
8053 redisLog(REDIS_WARNING,
8054 "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION, sig);
1c85b79f 8055 infostring = genRedisInfoString();
8056 redisLog(REDIS_WARNING, "%s",infostring);
8057 /* It's not safe to sdsfree() the returned string under memory
8058 * corruption conditions. Let it leak as we are going to abort */
56906eef 8059
8060 trace_size = backtrace(trace, 100);
de96dbfe 8061 /* overwrite sigaction with caller's address */
b91cf5ef 8062 if (getMcontextEip(uc) != NULL) {
8063 trace[1] = getMcontextEip(uc);
8064 }
56906eef 8065 messages = backtrace_symbols(trace, trace_size);
fe3bbfbe 8066
d76412d1 8067 for (i=1; i<trace_size; ++i) {
56906eef 8068 char *fn = findFuncName(trace[i], &offset), *p;
8069
8070 p = strchr(messages[i],'+');
8071 if (!fn || (p && ((unsigned long)strtol(p+1,NULL,10)) < offset)) {
8072 redisLog(REDIS_WARNING,"%s", messages[i]);
8073 } else {
8074 redisLog(REDIS_WARNING,"%d redis-server %p %s + %d", i, trace[i], fn, (unsigned int)offset);
8075 }
8076 }
b177fd30 8077 /* free(messages); Don't call free() with possibly corrupted memory. */
56906eef 8078 exit(0);
fe3bbfbe 8079}
56906eef 8080
8081static void setupSigSegvAction(void) {
8082 struct sigaction act;
8083
8084 sigemptyset (&act.sa_mask);
8085 /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
8086 * is used. Otherwise, sa_handler is used */
8087 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
8088 act.sa_sigaction = segvHandler;
8089 sigaction (SIGSEGV, &act, NULL);
8090 sigaction (SIGBUS, &act, NULL);
12fea928 8091 sigaction (SIGFPE, &act, NULL);
8092 sigaction (SIGILL, &act, NULL);
8093 sigaction (SIGBUS, &act, NULL);
e65fdc78 8094 return;
56906eef 8095}
e65fdc78 8096
bcfc686d 8097#include "staticsymbols.h"
8098/* This function try to convert a pointer into a function name. It's used in
8099 * oreder to provide a backtrace under segmentation fault that's able to
8100 * display functions declared as static (otherwise the backtrace is useless). */
8101static char *findFuncName(void *pointer, unsigned long *offset){
8102 int i, ret = -1;
8103 unsigned long off, minoff = 0;
ed9b544e 8104
bcfc686d 8105 /* Try to match against the Symbol with the smallest offset */
8106 for (i=0; symsTable[i].pointer; i++) {
8107 unsigned long lp = (unsigned long) pointer;
0bc03378 8108
bcfc686d 8109 if (lp != (unsigned long)-1 && lp >= symsTable[i].pointer) {
8110 off=lp-symsTable[i].pointer;
8111 if (ret < 0 || off < minoff) {
8112 minoff=off;
8113 ret=i;
8114 }
8115 }
0bc03378 8116 }
bcfc686d 8117 if (ret == -1) return NULL;
8118 *offset = minoff;
8119 return symsTable[ret].name;
0bc03378 8120}
bcfc686d 8121#else /* HAVE_BACKTRACE */
8122static void setupSigSegvAction(void) {
0bc03378 8123}
bcfc686d 8124#endif /* HAVE_BACKTRACE */
0bc03378 8125
ed9b544e 8126
ed9b544e 8127
bcfc686d 8128/* The End */
8129
8130
ed9b544e 8131