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