2  * Copyright (c) 2006-2009, Salvatore Sanfilippo <antirez at gmail dot com> 
   5  * Redistribution and use in source and binary forms, with or without 
   6  * modification, are permitted provided that the following conditions are met: 
   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. 
  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. 
  30 #define REDIS_VERSION "0.07" 
  44 #include <arpa/inet.h> 
  48 #include <sys/resource.h> 
  50 #include "ae.h"     /* Event driven programming library */ 
  51 #include "sds.h"    /* Dynamic safe strings */ 
  52 #include "anet.h"   /* Networking the easy way */ 
  53 #include "dict.h"   /* Hash tables */ 
  54 #include "adlist.h" /* Linked lists */ 
  55 #include "zmalloc.h" /* total memory usage aware version of malloc/free */ 
  61 /* Static server configuration */ 
  62 #define REDIS_SERVERPORT        6379    /* TCP port */ 
  63 #define REDIS_MAXIDLETIME       (60*5)  /* default client timeout */ 
  64 #define REDIS_QUERYBUF_LEN      1024 
  65 #define REDIS_LOADBUF_LEN       1024 
  66 #define REDIS_MAX_ARGS          16 
  67 #define REDIS_DEFAULT_DBNUM     16 
  68 #define REDIS_CONFIGLINE_MAX    1024 
  69 #define REDIS_OBJFREELIST_MAX   1000000 /* Max number of objects to cache */ 
  70 #define REDIS_MAX_SYNC_TIME     60      /* Slave can't take more to sync */ 
  72 /* Hash table parameters */ 
  73 #define REDIS_HT_MINFILL        10      /* Minimal hash table fill 10% */ 
  74 #define REDIS_HT_MINSLOTS       16384   /* Never resize the HT under this */ 
  77 #define REDIS_CMD_BULK          1 
  78 #define REDIS_CMD_INLINE        2 
  81 #define REDIS_STRING 0 
  85 #define REDIS_SELECTDB 254 
  89 #define REDIS_CLOSE 1       /* This client connection should be closed ASAP */ 
  90 #define REDIS_SLAVE 2       /* This client is a slave server */ 
  91 #define REDIS_MASTER 4      /* This client is a master server */ 
  92 #define REDIS_MONITOR 8      /* This client is a slave monitor, see MONITOR */ 
  94 /* Server replication state */ 
  95 #define REDIS_REPL_NONE 0   /* No active replication */ 
  96 #define REDIS_REPL_CONNECT 1    /* Must connect to master */ 
  97 #define REDIS_REPL_CONNECTED 2  /* Connected to master */ 
  99 /* List related stuff */ 
 103 /* Sort operations */ 
 104 #define REDIS_SORT_GET 0 
 105 #define REDIS_SORT_DEL 1 
 106 #define REDIS_SORT_INCR 2 
 107 #define REDIS_SORT_DECR 3 
 108 #define REDIS_SORT_ASC 4 
 109 #define REDIS_SORT_DESC 5 
 110 #define REDIS_SORTKEY_MAX 1024 
 113 #define REDIS_DEBUG 0 
 114 #define REDIS_NOTICE 1 
 115 #define REDIS_WARNING 2 
 117 /* Anti-warning macro... */ 
 118 #define REDIS_NOTUSED(V) ((void) V) 
 120 /*================================= Data types ============================== */ 
 122 /* A redis object, that is a type able to hold a string / list / set */ 
 123 typedef struct redisObject 
{ 
 129 /* With multiplexing we need to take per-clinet state. 
 130  * Clients are taken in a liked list. */ 
 131 typedef struct redisClient 
{ 
 136     robj 
*argv
[REDIS_MAX_ARGS
]; 
 138     int bulklen
;    /* bulk read len. -1 if not in bulk read mode */ 
 141     time_t lastinteraction
; /* time of the last interaction, used for timeout */ 
 142     int flags
; /* REDIS_CLOSE | REDIS_SLAVE | REDIS_MONITOR */ 
 143     int slaveseldb
; /* slave selected db, if this client is a slave */ 
 151 /* Global server state structure */ 
 156     long long dirty
;            /* changes to DB from the last save */ 
 158     list 
*slaves
, *monitors
; 
 159     char neterr
[ANET_ERR_LEN
]; 
 161     int cronloops
;              /* number of times the cron function run */ 
 162     list 
*objfreelist
;          /* A list of freed objects to avoid malloc() */ 
 163     time_t lastsave
;            /* Unix time of last save succeeede */ 
 164     int usedmemory
;             /* Used memory in megabytes */ 
 165     /* Fields used only for stats */ 
 166     time_t stat_starttime
;         /* server start time */ 
 167     long long stat_numcommands
;    /* number of processed commands */ 
 168     long long stat_numconnections
; /* number of connections received */ 
 176     int bgsaveinprogress
; 
 177     struct saveparam 
*saveparams
; 
 182     /* Replication related */ 
 188     /* Sort parameters - qsort_r() is only available under BSD so we 
 189      * have to take this state global, in order to pass it to sortCompare() */ 
 195 typedef void redisCommandProc(redisClient 
*c
); 
 196 struct redisCommand 
{ 
 198     redisCommandProc 
*proc
; 
 203 typedef struct _redisSortObject 
{ 
 211 typedef struct _redisSortOperation 
{ 
 214 } redisSortOperation
; 
 216 struct sharedObjectsStruct 
{ 
 217     robj 
*crlf
, *ok
, *err
, *zerobulk
, *nil
, *zero
, *one
, *pong
, *space
, 
 218     *minus1
, *minus2
, *minus3
, *minus4
, 
 219     *wrongtypeerr
, *nokeyerr
, *wrongtypeerrbulk
, *nokeyerrbulk
, 
 220     *syntaxerr
, *syntaxerrbulk
, 
 221     *select0
, *select1
, *select2
, *select3
, *select4
, 
 222     *select5
, *select6
, *select7
, *select8
, *select9
; 
 225 /*================================ Prototypes =============================== */ 
 227 static void freeStringObject(robj 
*o
); 
 228 static void freeListObject(robj 
*o
); 
 229 static void freeSetObject(robj 
*o
); 
 230 static void decrRefCount(void *o
); 
 231 static robj 
*createObject(int type
, void *ptr
); 
 232 static void freeClient(redisClient 
*c
); 
 233 static int loadDb(char *filename
); 
 234 static void addReply(redisClient 
*c
, robj 
*obj
); 
 235 static void addReplySds(redisClient 
*c
, sds s
); 
 236 static void incrRefCount(robj 
*o
); 
 237 static int saveDbBackground(char *filename
); 
 238 static robj 
*createStringObject(char *ptr
, size_t len
); 
 239 static void replicationFeedSlaves(list 
*slaves
, struct redisCommand 
*cmd
, int dictid
, robj 
**argv
, int argc
); 
 240 static int syncWithMaster(void); 
 242 static void pingCommand(redisClient 
*c
); 
 243 static void echoCommand(redisClient 
*c
); 
 244 static void setCommand(redisClient 
*c
); 
 245 static void setnxCommand(redisClient 
*c
); 
 246 static void getCommand(redisClient 
*c
); 
 247 static void delCommand(redisClient 
*c
); 
 248 static void existsCommand(redisClient 
*c
); 
 249 static void incrCommand(redisClient 
*c
); 
 250 static void decrCommand(redisClient 
*c
); 
 251 static void incrbyCommand(redisClient 
*c
); 
 252 static void decrbyCommand(redisClient 
*c
); 
 253 static void selectCommand(redisClient 
*c
); 
 254 static void randomkeyCommand(redisClient 
*c
); 
 255 static void keysCommand(redisClient 
*c
); 
 256 static void dbsizeCommand(redisClient 
*c
); 
 257 static void lastsaveCommand(redisClient 
*c
); 
 258 static void saveCommand(redisClient 
*c
); 
 259 static void bgsaveCommand(redisClient 
*c
); 
 260 static void shutdownCommand(redisClient 
*c
); 
 261 static void moveCommand(redisClient 
*c
); 
 262 static void renameCommand(redisClient 
*c
); 
 263 static void renamenxCommand(redisClient 
*c
); 
 264 static void lpushCommand(redisClient 
*c
); 
 265 static void rpushCommand(redisClient 
*c
); 
 266 static void lpopCommand(redisClient 
*c
); 
 267 static void rpopCommand(redisClient 
*c
); 
 268 static void llenCommand(redisClient 
*c
); 
 269 static void lindexCommand(redisClient 
*c
); 
 270 static void lrangeCommand(redisClient 
*c
); 
 271 static void ltrimCommand(redisClient 
*c
); 
 272 static void typeCommand(redisClient 
*c
); 
 273 static void lsetCommand(redisClient 
*c
); 
 274 static void saddCommand(redisClient 
*c
); 
 275 static void sremCommand(redisClient 
*c
); 
 276 static void sismemberCommand(redisClient 
*c
); 
 277 static void scardCommand(redisClient 
*c
); 
 278 static void sinterCommand(redisClient 
*c
); 
 279 static void sinterstoreCommand(redisClient 
*c
); 
 280 static void syncCommand(redisClient 
*c
); 
 281 static void flushdbCommand(redisClient 
*c
); 
 282 static void flushallCommand(redisClient 
*c
); 
 283 static void sortCommand(redisClient 
*c
); 
 284 static void lremCommand(redisClient 
*c
); 
 285 static void infoCommand(redisClient 
*c
); 
 286 static void mgetCommand(redisClient 
*c
); 
 287 static void monitorCommand(redisClient 
*c
); 
 289 /*================================= Globals ================================= */ 
 292 static struct redisServer server
; /* server global state */ 
 293 static struct redisCommand cmdTable
[] = { 
 294     {"get",getCommand
,2,REDIS_CMD_INLINE
}, 
 295     {"set",setCommand
,3,REDIS_CMD_BULK
}, 
 296     {"setnx",setnxCommand
,3,REDIS_CMD_BULK
}, 
 297     {"del",delCommand
,2,REDIS_CMD_INLINE
}, 
 298     {"exists",existsCommand
,2,REDIS_CMD_INLINE
}, 
 299     {"incr",incrCommand
,2,REDIS_CMD_INLINE
}, 
 300     {"decr",decrCommand
,2,REDIS_CMD_INLINE
}, 
 301     {"mget",mgetCommand
,-2,REDIS_CMD_INLINE
}, 
 302     {"rpush",rpushCommand
,3,REDIS_CMD_BULK
}, 
 303     {"lpush",lpushCommand
,3,REDIS_CMD_BULK
}, 
 304     {"rpop",rpopCommand
,2,REDIS_CMD_INLINE
}, 
 305     {"lpop",lpopCommand
,2,REDIS_CMD_INLINE
}, 
 306     {"llen",llenCommand
,2,REDIS_CMD_INLINE
}, 
 307     {"lindex",lindexCommand
,3,REDIS_CMD_INLINE
}, 
 308     {"lset",lsetCommand
,4,REDIS_CMD_BULK
}, 
 309     {"lrange",lrangeCommand
,4,REDIS_CMD_INLINE
}, 
 310     {"ltrim",ltrimCommand
,4,REDIS_CMD_INLINE
}, 
 311     {"lrem",lremCommand
,4,REDIS_CMD_BULK
}, 
 312     {"sadd",saddCommand
,3,REDIS_CMD_BULK
}, 
 313     {"srem",sremCommand
,3,REDIS_CMD_BULK
}, 
 314     {"sismember",sismemberCommand
,3,REDIS_CMD_BULK
}, 
 315     {"scard",scardCommand
,2,REDIS_CMD_INLINE
}, 
 316     {"sinter",sinterCommand
,-2,REDIS_CMD_INLINE
}, 
 317     {"sinterstore",sinterstoreCommand
,-3,REDIS_CMD_INLINE
}, 
 318     {"smembers",sinterCommand
,2,REDIS_CMD_INLINE
}, 
 319     {"incrby",incrbyCommand
,3,REDIS_CMD_INLINE
}, 
 320     {"decrby",decrbyCommand
,3,REDIS_CMD_INLINE
}, 
 321     {"randomkey",randomkeyCommand
,1,REDIS_CMD_INLINE
}, 
 322     {"select",selectCommand
,2,REDIS_CMD_INLINE
}, 
 323     {"move",moveCommand
,3,REDIS_CMD_INLINE
}, 
 324     {"rename",renameCommand
,3,REDIS_CMD_INLINE
}, 
 325     {"renamenx",renamenxCommand
,3,REDIS_CMD_INLINE
}, 
 326     {"keys",keysCommand
,2,REDIS_CMD_INLINE
}, 
 327     {"dbsize",dbsizeCommand
,1,REDIS_CMD_INLINE
}, 
 328     {"ping",pingCommand
,1,REDIS_CMD_INLINE
}, 
 329     {"echo",echoCommand
,2,REDIS_CMD_BULK
}, 
 330     {"save",saveCommand
,1,REDIS_CMD_INLINE
}, 
 331     {"bgsave",bgsaveCommand
,1,REDIS_CMD_INLINE
}, 
 332     {"shutdown",shutdownCommand
,1,REDIS_CMD_INLINE
}, 
 333     {"lastsave",lastsaveCommand
,1,REDIS_CMD_INLINE
}, 
 334     {"type",typeCommand
,2,REDIS_CMD_INLINE
}, 
 335     {"sync",syncCommand
,1,REDIS_CMD_INLINE
}, 
 336     {"flushdb",flushdbCommand
,1,REDIS_CMD_INLINE
}, 
 337     {"flushall",flushallCommand
,1,REDIS_CMD_INLINE
}, 
 338     {"sort",sortCommand
,-2,REDIS_CMD_INLINE
}, 
 339     {"info",infoCommand
,1,REDIS_CMD_INLINE
}, 
 340     {"monitor",monitorCommand
,1,REDIS_CMD_INLINE
}, 
 344 /*============================ Utility functions ============================ */ 
 346 /* Glob-style pattern matching. */ 
 347 int stringmatchlen(const char *pattern
, int patternLen
, 
 348         const char *string
, int stringLen
, int nocase
) 
 353             while (pattern
[1] == '*') { 
 358                 return 1; /* match */ 
 360                 if (stringmatchlen(pattern
+1, patternLen
-1, 
 361                             string
, stringLen
, nocase
)) 
 362                     return 1; /* match */ 
 366             return 0; /* no match */ 
 370                 return 0; /* no match */ 
 380             not = pattern
[0] == '^'; 
 387                 if (pattern
[0] == '\\') { 
 390                     if (pattern
[0] == string
[0]) 
 392                 } else if (pattern
[0] == ']') { 
 394                 } else if (patternLen 
== 0) { 
 398                 } else if (pattern
[1] == '-' && patternLen 
>= 3) { 
 399                     int start 
= pattern
[0]; 
 400                     int end 
= pattern
[2]; 
 408                         start 
= tolower(start
); 
 414                     if (c 
>= start 
&& c 
<= end
) 
 418                         if (pattern
[0] == string
[0]) 
 421                         if (tolower((int)pattern
[0]) == tolower((int)string
[0])) 
 431                 return 0; /* no match */ 
 437             if (patternLen 
>= 2) { 
 444                 if (pattern
[0] != string
[0]) 
 445                     return 0; /* no match */ 
 447                 if (tolower((int)pattern
[0]) != tolower((int)string
[0])) 
 448                     return 0; /* no match */ 
 456         if (stringLen 
== 0) { 
 457             while(*pattern 
== '*') { 
 464     if (patternLen 
== 0 && stringLen 
== 0) 
 469 void redisLog(int level
, const char *fmt
, ...) 
 474     fp 
= (server
.logfile 
== NULL
) ? stdout 
: fopen(server
.logfile
,"a"); 
 478     if (level 
>= server
.verbosity
) { 
 480         fprintf(fp
,"%c ",c
[level
]); 
 481         vfprintf(fp
, fmt
, ap
); 
 487     if (server
.logfile
) fclose(fp
); 
 490 /*====================== Hash table type implementation  ==================== */ 
 492 /* This is an hash table type that uses the SDS dynamic strings libary as 
 493  * keys and radis objects as values (objects can hold SDS strings, 
 496 static int sdsDictKeyCompare(void *privdata
, const void *key1
, 
 500     DICT_NOTUSED(privdata
); 
 502     l1 
= sdslen((sds
)key1
); 
 503     l2 
= sdslen((sds
)key2
); 
 504     if (l1 
!= l2
) return 0; 
 505     return memcmp(key1
, key2
, l1
) == 0; 
 508 static void dictRedisObjectDestructor(void *privdata
, void *val
) 
 510     DICT_NOTUSED(privdata
); 
 515 static int dictSdsKeyCompare(void *privdata
, const void *key1
, 
 518     const robj 
*o1 
= key1
, *o2 
= key2
; 
 519     return sdsDictKeyCompare(privdata
,o1
->ptr
,o2
->ptr
); 
 522 static unsigned int dictSdsHash(const void *key
) { 
 524     return dictGenHashFunction(o
->ptr
, sdslen((sds
)o
->ptr
)); 
 527 static dictType setDictType 
= { 
 528     dictSdsHash
,               /* hash function */ 
 531     dictSdsKeyCompare
,         /* key compare */ 
 532     dictRedisObjectDestructor
, /* key destructor */ 
 533     NULL                       
/* val destructor */ 
 536 static dictType hashDictType 
= { 
 537     dictSdsHash
,                /* hash function */ 
 540     dictSdsKeyCompare
,          /* key compare */ 
 541     dictRedisObjectDestructor
,  /* key destructor */ 
 542     dictRedisObjectDestructor   
/* val destructor */ 
 545 /* ========================= Random utility functions ======================= */ 
 547 /* Redis generally does not try to recover from out of memory conditions 
 548  * when allocating objects or strings, it is not clear if it will be possible 
 549  * to report this condition to the client since the networking layer itself 
 550  * is based on heap allocation for send buffers, so we simply abort. 
 551  * At least the code will be simpler to read... */ 
 552 static void oom(const char *msg
) { 
 553     fprintf(stderr
, "%s: Out of memory\n",msg
); 
 559 /* ====================== Redis server networking stuff ===================== */ 
 560 void closeTimedoutClients(void) { 
 564     time_t now 
= time(NULL
); 
 566     li 
= listGetIterator(server
.clients
,AL_START_HEAD
); 
 568     while ((ln 
= listNextElement(li
)) != NULL
) { 
 569         c 
= listNodeValue(ln
); 
 570         if (!(c
->flags 
& REDIS_SLAVE
) &&    /* no timeout for slaves */ 
 571              (now 
- c
->lastinteraction 
> server
.maxidletime
)) { 
 572             redisLog(REDIS_DEBUG
,"Closing idle client"); 
 576     listReleaseIterator(li
); 
 579 int serverCron(struct aeEventLoop 
*eventLoop
, long long id
, void *clientData
) { 
 580     int j
, size
, used
, loops 
= server
.cronloops
++; 
 581     REDIS_NOTUSED(eventLoop
); 
 583     REDIS_NOTUSED(clientData
); 
 585     /* Update the global state with the amount of used memory */ 
 586     server
.usedmemory 
= zmalloc_used_memory(); 
 588     /* If the percentage of used slots in the HT reaches REDIS_HT_MINFILL 
 589      * we resize the hash table to save memory */ 
 590     for (j 
= 0; j 
< server
.dbnum
; j
++) { 
 591         size 
= dictGetHashTableSize(server
.dict
[j
]); 
 592         used 
= dictGetHashTableUsed(server
.dict
[j
]); 
 593         if (!(loops 
% 5) && used 
> 0) { 
 594             redisLog(REDIS_DEBUG
,"DB %d: %d keys in %d slots HT.",j
,used
,size
); 
 595             // dictPrintStats(server.dict); 
 597         if (size 
&& used 
&& size 
> REDIS_HT_MINSLOTS 
&& 
 598             (used
*100/size 
< REDIS_HT_MINFILL
)) { 
 599             redisLog(REDIS_NOTICE
,"The hash table %d is too sparse, resize it...",j
); 
 600             dictResize(server
.dict
[j
]); 
 601             redisLog(REDIS_NOTICE
,"Hash table %d resized.",j
); 
 605     /* Show information about connected clients */ 
 607         redisLog(REDIS_DEBUG
,"%d clients connected (%d slaves), %d bytes in use", 
 608             listLength(server
.clients
)-listLength(server
.slaves
), 
 609             listLength(server
.slaves
), 
 613     /* Close connections of timedout clients */ 
 615         closeTimedoutClients(); 
 617     /* Check if a background saving in progress terminated */ 
 618     if (server
.bgsaveinprogress
) { 
 620         if (wait4(-1,&statloc
,WNOHANG
,NULL
)) { 
 621             int exitcode 
= WEXITSTATUS(statloc
); 
 623                 redisLog(REDIS_NOTICE
, 
 624                     "Background saving terminated with success"); 
 626                 server
.lastsave 
= time(NULL
); 
 628                 redisLog(REDIS_WARNING
, 
 629                     "Background saving error"); 
 631             server
.bgsaveinprogress 
= 0; 
 634         /* If there is not a background saving in progress check if 
 635          * we have to save now */ 
 636          time_t now 
= time(NULL
); 
 637          for (j 
= 0; j 
< server
.saveparamslen
; j
++) { 
 638             struct saveparam 
*sp 
= server
.saveparams
+j
; 
 640             if (server
.dirty 
>= sp
->changes 
&& 
 641                 now
-server
.lastsave 
> sp
->seconds
) { 
 642                 redisLog(REDIS_NOTICE
,"%d changes in %d seconds. Saving...", 
 643                     sp
->changes
, sp
->seconds
); 
 644                 saveDbBackground(server
.dbfilename
); 
 649     /* Check if we should connect to a MASTER */ 
 650     if (server
.replstate 
== REDIS_REPL_CONNECT
) { 
 651         redisLog(REDIS_NOTICE
,"Connecting to MASTER..."); 
 652         if (syncWithMaster() == REDIS_OK
) { 
 653             redisLog(REDIS_NOTICE
,"MASTER <-> SLAVE sync succeeded"); 
 659 static void createSharedObjects(void) { 
 660     shared
.crlf 
= createObject(REDIS_STRING
,sdsnew("\r\n")); 
 661     shared
.ok 
= createObject(REDIS_STRING
,sdsnew("+OK\r\n")); 
 662     shared
.err 
= createObject(REDIS_STRING
,sdsnew("-ERR\r\n")); 
 663     shared
.zerobulk 
= createObject(REDIS_STRING
,sdsnew("0\r\n\r\n")); 
 664     shared
.nil 
= createObject(REDIS_STRING
,sdsnew("nil\r\n")); 
 665     shared
.zero 
= createObject(REDIS_STRING
,sdsnew("0\r\n")); 
 666     shared
.one 
= createObject(REDIS_STRING
,sdsnew("1\r\n")); 
 668     shared
.minus1 
= createObject(REDIS_STRING
,sdsnew("-1\r\n")); 
 669     /* operation against key holding a value of the wrong type */ 
 670     shared
.minus2 
= createObject(REDIS_STRING
,sdsnew("-2\r\n")); 
 671     /* src and dest objects are the same */ 
 672     shared
.minus3 
= createObject(REDIS_STRING
,sdsnew("-3\r\n")); 
 673     /* out of range argument */ 
 674     shared
.minus4 
= createObject(REDIS_STRING
,sdsnew("-4\r\n")); 
 675     shared
.pong 
= createObject(REDIS_STRING
,sdsnew("+PONG\r\n")); 
 676     shared
.wrongtypeerr 
= createObject(REDIS_STRING
,sdsnew( 
 677         "-ERR Operation against a key holding the wrong kind of value\r\n")); 
 678     shared
.wrongtypeerrbulk 
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%d\r\n%s",-sdslen(shared
.wrongtypeerr
->ptr
)+2,shared
.wrongtypeerr
->ptr
)); 
 679     shared
.nokeyerr 
= createObject(REDIS_STRING
,sdsnew( 
 680         "-ERR no such key\r\n")); 
 681     shared
.nokeyerrbulk 
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%d\r\n%s",-sdslen(shared
.nokeyerr
->ptr
)+2,shared
.nokeyerr
->ptr
)); 
 682     shared
.syntaxerr 
= createObject(REDIS_STRING
,sdsnew( 
 683         "-ERR syntax error\r\n")); 
 684     shared
.syntaxerrbulk 
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%d\r\n%s",-sdslen(shared
.syntaxerr
->ptr
)+2,shared
.syntaxerr
->ptr
)); 
 685     shared
.space 
= createObject(REDIS_STRING
,sdsnew(" ")); 
 686     shared
.select0 
= createStringObject("select 0\r\n",10); 
 687     shared
.select1 
= createStringObject("select 1\r\n",10); 
 688     shared
.select2 
= createStringObject("select 2\r\n",10); 
 689     shared
.select3 
= createStringObject("select 3\r\n",10); 
 690     shared
.select4 
= createStringObject("select 4\r\n",10); 
 691     shared
.select5 
= createStringObject("select 5\r\n",10); 
 692     shared
.select6 
= createStringObject("select 6\r\n",10); 
 693     shared
.select7 
= createStringObject("select 7\r\n",10); 
 694     shared
.select8 
= createStringObject("select 8\r\n",10); 
 695     shared
.select9 
= createStringObject("select 9\r\n",10); 
 698 static void appendServerSaveParams(time_t seconds
, int changes
) { 
 699     server
.saveparams 
= zrealloc(server
.saveparams
,sizeof(struct saveparam
)*(server
.saveparamslen
+1)); 
 700     if (server
.saveparams 
== NULL
) oom("appendServerSaveParams"); 
 701     server
.saveparams
[server
.saveparamslen
].seconds 
= seconds
; 
 702     server
.saveparams
[server
.saveparamslen
].changes 
= changes
; 
 703     server
.saveparamslen
++; 
 706 static void ResetServerSaveParams() { 
 707     zfree(server
.saveparams
); 
 708     server
.saveparams 
= NULL
; 
 709     server
.saveparamslen 
= 0; 
 712 static void initServerConfig() { 
 713     server
.dbnum 
= REDIS_DEFAULT_DBNUM
; 
 714     server
.port 
= REDIS_SERVERPORT
; 
 715     server
.verbosity 
= REDIS_DEBUG
; 
 716     server
.maxidletime 
= REDIS_MAXIDLETIME
; 
 717     server
.saveparams 
= NULL
; 
 718     server
.logfile 
= NULL
; /* NULL = log on standard output */ 
 719     server
.bindaddr 
= NULL
; 
 720     server
.glueoutputbuf 
= 1; 
 721     server
.daemonize 
= 0; 
 722     server
.pidfile 
= "/var/run/redis.pid"; 
 723     server
.dbfilename 
= "dump.rdb"; 
 724     ResetServerSaveParams(); 
 726     appendServerSaveParams(60*60,1);  /* save after 1 hour and 1 change */ 
 727     appendServerSaveParams(300,100);  /* save after 5 minutes and 100 changes */ 
 728     appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */ 
 729     /* Replication related */ 
 731     server
.masterhost 
= NULL
; 
 732     server
.masterport 
= 6379; 
 733     server
.master 
= NULL
; 
 734     server
.replstate 
= REDIS_REPL_NONE
; 
 737 static void initServer() { 
 740     signal(SIGHUP
, SIG_IGN
); 
 741     signal(SIGPIPE
, SIG_IGN
); 
 743     server
.clients 
= listCreate(); 
 744     server
.slaves 
= listCreate(); 
 745     server
.monitors 
= listCreate(); 
 746     server
.objfreelist 
= listCreate(); 
 747     createSharedObjects(); 
 748     server
.el 
= aeCreateEventLoop(); 
 749     server
.dict 
= zmalloc(sizeof(dict
*)*server
.dbnum
); 
 750     if (!server
.dict 
|| !server
.clients 
|| !server
.slaves 
|| !server
.monitors 
|| !server
.el 
|| !server
.objfreelist
) 
 751         oom("server initialization"); /* Fatal OOM */ 
 752     server
.fd 
= anetTcpServer(server
.neterr
, server
.port
, server
.bindaddr
); 
 753     if (server
.fd 
== -1) { 
 754         redisLog(REDIS_WARNING
, "Opening TCP port: %s", server
.neterr
); 
 757     for (j 
= 0; j 
< server
.dbnum
; j
++) { 
 758         server
.dict
[j
] = dictCreate(&hashDictType
,NULL
); 
 760             oom("dictCreate"); /* Fatal OOM */ 
 762     server
.cronloops 
= 0; 
 763     server
.bgsaveinprogress 
= 0; 
 764     server
.lastsave 
= time(NULL
); 
 766     server
.usedmemory 
= 0; 
 767     server
.stat_numcommands 
= 0; 
 768     server
.stat_numconnections 
= 0; 
 769     server
.stat_starttime 
= time(NULL
); 
 770     aeCreateTimeEvent(server
.el
, 1000, serverCron
, NULL
, NULL
); 
 773 /* Empty the whole database */ 
 774 static void emptyDb() { 
 777     for (j 
= 0; j 
< server
.dbnum
; j
++) 
 778         dictEmpty(server
.dict
[j
]); 
 781 /* I agree, this is a very rudimental way to load a configuration... 
 782    will improve later if the config gets more complex */ 
 783 static void loadServerConfig(char *filename
) { 
 784     FILE *fp 
= fopen(filename
,"r"); 
 785     char buf
[REDIS_CONFIGLINE_MAX
+1], *err 
= NULL
; 
 790         redisLog(REDIS_WARNING
,"Fatal error, can't open config file"); 
 793     while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) { 
 799         line 
= sdstrim(line
," \t\r\n"); 
 801         /* Skip comments and blank lines*/ 
 802         if (line
[0] == '#' || line
[0] == '\0') { 
 807         /* Split into arguments */ 
 808         argv 
= sdssplitlen(line
,sdslen(line
)," ",1,&argc
); 
 811         /* Execute config directives */ 
 812         if (!strcmp(argv
[0],"timeout") && argc 
== 2) { 
 813             server
.maxidletime 
= atoi(argv
[1]); 
 814             if (server
.maxidletime 
< 1) { 
 815                 err 
= "Invalid timeout value"; goto loaderr
; 
 817         } else if (!strcmp(argv
[0],"port") && argc 
== 2) { 
 818             server
.port 
= atoi(argv
[1]); 
 819             if (server
.port 
< 1 || server
.port 
> 65535) { 
 820                 err 
= "Invalid port"; goto loaderr
; 
 822         } else if (!strcmp(argv
[0],"bind") && argc 
== 2) { 
 823             server
.bindaddr 
= zstrdup(argv
[1]); 
 824         } else if (!strcmp(argv
[0],"save") && argc 
== 3) { 
 825             int seconds 
= atoi(argv
[1]); 
 826             int changes 
= atoi(argv
[2]); 
 827             if (seconds 
< 1 || changes 
< 0) { 
 828                 err 
= "Invalid save parameters"; goto loaderr
; 
 830             appendServerSaveParams(seconds
,changes
); 
 831         } else if (!strcmp(argv
[0],"dir") && argc 
== 2) { 
 832             if (chdir(argv
[1]) == -1) { 
 833                 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s", 
 834                     argv
[1], strerror(errno
)); 
 837         } else if (!strcmp(argv
[0],"loglevel") && argc 
== 2) { 
 838             if (!strcmp(argv
[1],"debug")) server
.verbosity 
= REDIS_DEBUG
; 
 839             else if (!strcmp(argv
[1],"notice")) server
.verbosity 
= REDIS_NOTICE
; 
 840             else if (!strcmp(argv
[1],"warning")) server
.verbosity 
= REDIS_WARNING
; 
 842                 err 
= "Invalid log level. Must be one of debug, notice, warning"; 
 845         } else if (!strcmp(argv
[0],"logfile") && argc 
== 2) { 
 848             server
.logfile 
= zstrdup(argv
[1]); 
 849             if (!strcmp(server
.logfile
,"stdout")) { 
 850                 zfree(server
.logfile
); 
 851                 server
.logfile 
= NULL
; 
 853             if (server
.logfile
) { 
 854                 /* Test if we are able to open the file. The server will not 
 855                  * be able to abort just for this problem later... */ 
 856                 fp 
= fopen(server
.logfile
,"a"); 
 858                     err 
= sdscatprintf(sdsempty(), 
 859                         "Can't open the log file: %s", strerror(errno
)); 
 864         } else if (!strcmp(argv
[0],"databases") && argc 
== 2) { 
 865             server
.dbnum 
= atoi(argv
[1]); 
 866             if (server
.dbnum 
< 1) { 
 867                 err 
= "Invalid number of databases"; goto loaderr
; 
 869         } else if (!strcmp(argv
[0],"slaveof") && argc 
== 3) { 
 870             server
.masterhost 
= sdsnew(argv
[1]); 
 871             server
.masterport 
= atoi(argv
[2]); 
 872             server
.replstate 
= REDIS_REPL_CONNECT
; 
 873         } else if (!strcmp(argv
[0],"glueoutputbuf") && argc 
== 2) { 
 875             if (!strcmp(argv
[1],"yes")) server
.glueoutputbuf 
= 1; 
 876             else if (!strcmp(argv
[1],"no")) server
.glueoutputbuf 
= 0; 
 878                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 880         } else if (!strcmp(argv
[0],"daemonize") && argc 
== 2) { 
 882             if (!strcmp(argv
[1],"yes")) server
.daemonize 
= 1; 
 883             else if (!strcmp(argv
[1],"no")) server
.daemonize 
= 0; 
 885                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 887         } else if (!strcmp(argv
[0],"pidfile") && argc 
== 2) { 
 888           server
.pidfile 
= zstrdup(argv
[1]); 
 890             err 
= "Bad directive or wrong number of arguments"; goto loaderr
; 
 892         for (j 
= 0; j 
< argc
; j
++) 
 901     fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n"); 
 902     fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
); 
 903     fprintf(stderr
, ">>> '%s'\n", line
); 
 904     fprintf(stderr
, "%s\n", err
); 
 908 static void freeClientArgv(redisClient 
*c
) { 
 911     for (j 
= 0; j 
< c
->argc
; j
++) 
 912         decrRefCount(c
->argv
[j
]); 
 916 static void freeClient(redisClient 
*c
) { 
 919     aeDeleteFileEvent(server
.el
,c
->fd
,AE_READABLE
); 
 920     aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
); 
 921     sdsfree(c
->querybuf
); 
 922     listRelease(c
->reply
); 
 925     ln 
= listSearchKey(server
.clients
,c
); 
 927     listDelNode(server
.clients
,ln
); 
 928     if (c
->flags 
& REDIS_SLAVE
) { 
 929         list 
*l 
= (c
->flags 
& REDIS_MONITOR
) ? server
.monitors 
: server
.slaves
; 
 930         ln 
= listSearchKey(l
,c
); 
 934     if (c
->flags 
& REDIS_MASTER
) { 
 935         server
.master 
= NULL
; 
 936         server
.replstate 
= REDIS_REPL_CONNECT
; 
 941 static void glueReplyBuffersIfNeeded(redisClient 
*c
) { 
 943     listNode 
*ln 
= c
->reply
->head
, *next
; 
 948         totlen 
+= sdslen(o
->ptr
); 
 950         /* This optimization makes more sense if we don't have to copy 
 952         if (totlen 
> 1024) return; 
 962             memcpy(buf
+copylen
,o
->ptr
,sdslen(o
->ptr
)); 
 963             copylen 
+= sdslen(o
->ptr
); 
 964             listDelNode(c
->reply
,ln
); 
 967         /* Now the output buffer is empty, add the new single element */ 
 968         addReplySds(c
,sdsnewlen(buf
,totlen
)); 
 972 static void sendReplyToClient(aeEventLoop 
*el
, int fd
, void *privdata
, int mask
) { 
 973     redisClient 
*c 
= privdata
; 
 974     int nwritten 
= 0, totwritten 
= 0, objlen
; 
 979     if (server
.glueoutputbuf 
&& listLength(c
->reply
) > 1) 
 980         glueReplyBuffersIfNeeded(c
); 
 981     while(listLength(c
->reply
)) { 
 982         o 
= listNodeValue(listFirst(c
->reply
)); 
 983         objlen 
= sdslen(o
->ptr
); 
 986             listDelNode(c
->reply
,listFirst(c
->reply
)); 
 990         if (c
->flags 
& REDIS_MASTER
) { 
 991             nwritten 
= objlen 
- c
->sentlen
; 
 993             nwritten 
= write(fd
, o
->ptr
+c
->sentlen
, objlen 
- c
->sentlen
); 
 994             if (nwritten 
<= 0) break; 
 996         c
->sentlen 
+= nwritten
; 
 997         totwritten 
+= nwritten
; 
 998         /* If we fully sent the object on head go to the next one */ 
 999         if (c
->sentlen 
== objlen
) { 
1000             listDelNode(c
->reply
,listFirst(c
->reply
)); 
1004     if (nwritten 
== -1) { 
1005         if (errno 
== EAGAIN
) { 
1008             redisLog(REDIS_DEBUG
, 
1009                 "Error writing to client: %s", strerror(errno
)); 
1014     if (totwritten 
> 0) c
->lastinteraction 
= time(NULL
); 
1015     if (listLength(c
->reply
) == 0) { 
1017         aeDeleteFileEvent(server
.el
,c
->fd
,AE_WRITABLE
); 
1021 static struct redisCommand 
*lookupCommand(char *name
) { 
1023     while(cmdTable
[j
].name 
!= NULL
) { 
1024         if (!strcmp(name
,cmdTable
[j
].name
)) return &cmdTable
[j
]; 
1030 /* resetClient prepare the client to process the next command */ 
1031 static void resetClient(redisClient 
*c
) { 
1036 /* If this function gets called we already read a whole 
1037  * command, argments are in the client argv/argc fields. 
1038  * processCommand() execute the command or prepare the 
1039  * server for a bulk read from the client. 
1041  * If 1 is returned the client is still alive and valid and 
1042  * and other operations can be performed by the caller. Otherwise 
1043  * if 0 is returned the client was destroied (i.e. after QUIT). */ 
1044 static int processCommand(redisClient 
*c
) { 
1045     struct redisCommand 
*cmd
; 
1048     sdstolower(c
->argv
[0]->ptr
); 
1049     /* The QUIT command is handled as a special case. Normal command 
1050      * procs are unable to close the client connection safely */ 
1051     if (!strcmp(c
->argv
[0]->ptr
,"quit")) { 
1055     cmd 
= lookupCommand(c
->argv
[0]->ptr
); 
1057         addReplySds(c
,sdsnew("-ERR unknown command\r\n")); 
1060     } else if ((cmd
->arity 
> 0 && cmd
->arity 
!= c
->argc
) || 
1061                (c
->argc 
< -cmd
->arity
)) { 
1062         addReplySds(c
,sdsnew("-ERR wrong number of arguments\r\n")); 
1065     } else if (cmd
->flags 
& REDIS_CMD_BULK 
&& c
->bulklen 
== -1) { 
1066         int bulklen 
= atoi(c
->argv
[c
->argc
-1]->ptr
); 
1068         decrRefCount(c
->argv
[c
->argc
-1]); 
1069         if (bulklen 
< 0 || bulklen 
> 1024*1024*1024) { 
1071             addReplySds(c
,sdsnew("-ERR invalid bulk write count\r\n")); 
1076         c
->bulklen 
= bulklen
+2; /* add two bytes for CR+LF */ 
1077         /* It is possible that the bulk read is already in the 
1078          * buffer. Check this condition and handle it accordingly */ 
1079         if ((signed)sdslen(c
->querybuf
) >= c
->bulklen
) { 
1080             c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2); 
1082             c
->querybuf 
= sdsrange(c
->querybuf
,c
->bulklen
,-1); 
1087     /* Exec the command */ 
1088     dirty 
= server
.dirty
; 
1090     if (server
.dirty
-dirty 
!= 0 && listLength(server
.slaves
)) 
1091         replicationFeedSlaves(server
.slaves
,cmd
,c
->dictid
,c
->argv
,c
->argc
); 
1092     if (listLength(server
.monitors
)) 
1093         replicationFeedSlaves(server
.monitors
,cmd
,c
->dictid
,c
->argv
,c
->argc
); 
1094     server
.stat_numcommands
++; 
1096     /* Prepare the client for the next command */ 
1097     if (c
->flags 
& REDIS_CLOSE
) { 
1105 static void replicationFeedSlaves(list 
*slaves
, struct redisCommand 
*cmd
, int dictid
, robj 
**argv
, int argc
) { 
1106     listNode 
*ln 
= slaves
->head
; 
1107     robj 
*outv
[REDIS_MAX_ARGS
*4]; /* enough room for args, spaces, newlines */ 
1110     for (j 
= 0; j 
< argc
; j
++) { 
1111         if (j 
!= 0) outv
[outc
++] = shared
.space
; 
1112         if ((cmd
->flags 
& REDIS_CMD_BULK
) && j 
== argc
-1) { 
1115             lenobj 
= createObject(REDIS_STRING
, 
1116                 sdscatprintf(sdsempty(),"%d\r\n",sdslen(argv
[j
]->ptr
))); 
1117             lenobj
->refcount 
= 0; 
1118             outv
[outc
++] = lenobj
; 
1120         outv
[outc
++] = argv
[j
]; 
1122     outv
[outc
++] = shared
.crlf
; 
1125         redisClient 
*slave 
= ln
->value
; 
1126         if (slave
->slaveseldb 
!= dictid
) { 
1130             case 0: selectcmd 
= shared
.select0
; break; 
1131             case 1: selectcmd 
= shared
.select1
; break; 
1132             case 2: selectcmd 
= shared
.select2
; break; 
1133             case 3: selectcmd 
= shared
.select3
; break; 
1134             case 4: selectcmd 
= shared
.select4
; break; 
1135             case 5: selectcmd 
= shared
.select5
; break; 
1136             case 6: selectcmd 
= shared
.select6
; break; 
1137             case 7: selectcmd 
= shared
.select7
; break; 
1138             case 8: selectcmd 
= shared
.select8
; break; 
1139             case 9: selectcmd 
= shared
.select9
; break; 
1141                 selectcmd 
= createObject(REDIS_STRING
, 
1142                     sdscatprintf(sdsempty(),"select %d\r\n",dictid
)); 
1143                 selectcmd
->refcount 
= 0; 
1146             addReply(slave
,selectcmd
); 
1147             slave
->slaveseldb 
= dictid
; 
1149         for (j 
= 0; j 
< outc
; j
++) addReply(slave
,outv
[j
]); 
1154 static void readQueryFromClient(aeEventLoop 
*el
, int fd
, void *privdata
, int mask
) { 
1155     redisClient 
*c 
= (redisClient
*) privdata
; 
1156     char buf
[REDIS_QUERYBUF_LEN
]; 
1159     REDIS_NOTUSED(mask
); 
1161     nread 
= read(fd
, buf
, REDIS_QUERYBUF_LEN
); 
1163         if (errno 
== EAGAIN
) { 
1166             redisLog(REDIS_DEBUG
, "Reading from client: %s",strerror(errno
)); 
1170     } else if (nread 
== 0) { 
1171         redisLog(REDIS_DEBUG
, "Client closed connection"); 
1176         c
->querybuf 
= sdscatlen(c
->querybuf
, buf
, nread
); 
1177         c
->lastinteraction 
= time(NULL
); 
1183     if (c
->bulklen 
== -1) { 
1184         /* Read the first line of the query */ 
1185         char *p 
= strchr(c
->querybuf
,'\n'); 
1191             query 
= c
->querybuf
; 
1192             c
->querybuf 
= sdsempty(); 
1193             querylen 
= 1+(p
-(query
)); 
1194             if (sdslen(query
) > querylen
) { 
1195                 /* leave data after the first line of the query in the buffer */ 
1196                 c
->querybuf 
= sdscatlen(c
->querybuf
,query
+querylen
,sdslen(query
)-querylen
); 
1198             *p 
= '\0'; /* remove "\n" */ 
1199             if (*(p
-1) == '\r') *(p
-1) = '\0'; /* and "\r" if any */ 
1200             sdsupdatelen(query
); 
1202             /* Now we can split the query in arguments */ 
1203             if (sdslen(query
) == 0) { 
1204                 /* Ignore empty query */ 
1208             argv 
= sdssplitlen(query
,sdslen(query
)," ",1,&argc
); 
1210             if (argv 
== NULL
) oom("sdssplitlen"); 
1211             for (j 
= 0; j 
< argc 
&& j 
< REDIS_MAX_ARGS
; j
++) { 
1212                 if (sdslen(argv
[j
])) { 
1213                     c
->argv
[c
->argc
] = createObject(REDIS_STRING
,argv
[j
]); 
1220             /* Execute the command. If the client is still valid 
1221              * after processCommand() return and there is something 
1222              * on the query buffer try to process the next command. */ 
1223             if (processCommand(c
) && sdslen(c
->querybuf
)) goto again
; 
1225         } else if (sdslen(c
->querybuf
) >= 1024) { 
1226             redisLog(REDIS_DEBUG
, "Client protocol error"); 
1231         /* Bulk read handling. Note that if we are at this point 
1232            the client already sent a command terminated with a newline, 
1233            we are reading the bulk data that is actually the last 
1234            argument of the command. */ 
1235         int qbl 
= sdslen(c
->querybuf
); 
1237         if (c
->bulklen 
<= qbl
) { 
1238             /* Copy everything but the final CRLF as final argument */ 
1239             c
->argv
[c
->argc
] = createStringObject(c
->querybuf
,c
->bulklen
-2); 
1241             c
->querybuf 
= sdsrange(c
->querybuf
,c
->bulklen
,-1); 
1248 static int selectDb(redisClient 
*c
, int id
) { 
1249     if (id 
< 0 || id 
>= server
.dbnum
) 
1251     c
->dict 
= server
.dict
[id
]; 
1256 static redisClient 
*createClient(int fd
) { 
1257     redisClient 
*c 
= zmalloc(sizeof(*c
)); 
1259     anetNonBlock(NULL
,fd
); 
1260     anetTcpNoDelay(NULL
,fd
); 
1261     if (!c
) return NULL
; 
1264     c
->querybuf 
= sdsempty(); 
1269     c
->lastinteraction 
= time(NULL
); 
1270     if ((c
->reply 
= listCreate()) == NULL
) oom("listCreate"); 
1271     listSetFreeMethod(c
->reply
,decrRefCount
); 
1272     if (aeCreateFileEvent(server
.el
, c
->fd
, AE_READABLE
, 
1273         readQueryFromClient
, c
, NULL
) == AE_ERR
) { 
1277     if (!listAddNodeTail(server
.clients
,c
)) oom("listAddNodeTail"); 
1281 static void addReply(redisClient 
*c
, robj 
*obj
) { 
1282     if (listLength(c
->reply
) == 0 && 
1283         aeCreateFileEvent(server
.el
, c
->fd
, AE_WRITABLE
, 
1284         sendReplyToClient
, c
, NULL
) == AE_ERR
) return; 
1285     if (!listAddNodeTail(c
->reply
,obj
)) oom("listAddNodeTail"); 
1289 static void addReplySds(redisClient 
*c
, sds s
) { 
1290     robj 
*o 
= createObject(REDIS_STRING
,s
); 
1295 static void acceptHandler(aeEventLoop 
*el
, int fd
, void *privdata
, int mask
) { 
1299     REDIS_NOTUSED(mask
); 
1300     REDIS_NOTUSED(privdata
); 
1302     cfd 
= anetAccept(server
.neterr
, fd
, cip
, &cport
); 
1303     if (cfd 
== AE_ERR
) { 
1304         redisLog(REDIS_DEBUG
,"Accepting client connection: %s", server
.neterr
); 
1307     redisLog(REDIS_DEBUG
,"Accepted %s:%d", cip
, cport
); 
1308     if (createClient(cfd
) == NULL
) { 
1309         redisLog(REDIS_WARNING
,"Error allocating resoures for the client"); 
1310         close(cfd
); /* May be already closed, just ingore errors */ 
1313     server
.stat_numconnections
++; 
1316 /* ======================= Redis objects implementation ===================== */ 
1318 static robj 
*createObject(int type
, void *ptr
) { 
1321     if (listLength(server
.objfreelist
)) { 
1322         listNode 
*head 
= listFirst(server
.objfreelist
); 
1323         o 
= listNodeValue(head
); 
1324         listDelNode(server
.objfreelist
,head
); 
1326         o 
= zmalloc(sizeof(*o
)); 
1328     if (!o
) oom("createObject"); 
1335 static robj 
*createStringObject(char *ptr
, size_t len
) { 
1336     return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
)); 
1339 static robj 
*createListObject(void) { 
1340     list 
*l 
= listCreate(); 
1342     if (!l
) oom("listCreate"); 
1343     listSetFreeMethod(l
,decrRefCount
); 
1344     return createObject(REDIS_LIST
,l
); 
1347 static robj 
*createSetObject(void) { 
1348     dict 
*d 
= dictCreate(&setDictType
,NULL
); 
1349     if (!d
) oom("dictCreate"); 
1350     return createObject(REDIS_SET
,d
); 
1354 static robj 
*createHashObject(void) { 
1355     dict 
*d 
= dictCreate(&hashDictType
,NULL
); 
1356     if (!d
) oom("dictCreate"); 
1357     return createObject(REDIS_SET
,d
); 
1361 static void freeStringObject(robj 
*o
) { 
1365 static void freeListObject(robj 
*o
) { 
1366     listRelease((list
*) o
->ptr
); 
1369 static void freeSetObject(robj 
*o
) { 
1370     dictRelease((dict
*) o
->ptr
); 
1373 static void freeHashObject(robj 
*o
) { 
1374     dictRelease((dict
*) o
->ptr
); 
1377 static void incrRefCount(robj 
*o
) { 
1381 static void decrRefCount(void *obj
) { 
1383     if (--(o
->refcount
) == 0) { 
1385         case REDIS_STRING
: freeStringObject(o
); break; 
1386         case REDIS_LIST
: freeListObject(o
); break; 
1387         case REDIS_SET
: freeSetObject(o
); break; 
1388         case REDIS_HASH
: freeHashObject(o
); break; 
1389         default: assert(0 != 0); break; 
1391         if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX 
|| 
1392             !listAddNodeHead(server
.objfreelist
,o
)) 
1397 /*============================ DB saving/loading ============================ */ 
1399 /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */ 
1400 static int saveDb(char *filename
) { 
1401     dictIterator 
*di 
= NULL
; 
1409     snprintf(tmpfile
,256,"temp-%d.%ld.rdb",(int)time(NULL
),(long int)random()); 
1410     fp 
= fopen(tmpfile
,"w"); 
1412         redisLog(REDIS_WARNING
, "Failed saving the DB: %s", strerror(errno
)); 
1415     if (fwrite("REDIS0000",9,1,fp
) == 0) goto werr
; 
1416     for (j 
= 0; j 
< server
.dbnum
; j
++) { 
1417         dict 
*d 
= server
.dict
[j
]; 
1418         if (dictGetHashTableUsed(d
) == 0) continue; 
1419         di 
= dictGetIterator(d
); 
1425         /* Write the SELECT DB opcode */ 
1426         type 
= REDIS_SELECTDB
; 
1428         if (fwrite(&type
,1,1,fp
) == 0) goto werr
; 
1429         if (fwrite(&len
,4,1,fp
) == 0) goto werr
; 
1431         /* Iterate this DB writing every entry */ 
1432         while((de 
= dictNext(di
)) != NULL
) { 
1433             robj 
*key 
= dictGetEntryKey(de
); 
1434             robj 
*o 
= dictGetEntryVal(de
); 
1437             len 
= htonl(sdslen(key
->ptr
)); 
1438             if (fwrite(&type
,1,1,fp
) == 0) goto werr
; 
1439             if (fwrite(&len
,4,1,fp
) == 0) goto werr
; 
1440             if (fwrite(key
->ptr
,sdslen(key
->ptr
),1,fp
) == 0) goto werr
; 
1441             if (type 
== REDIS_STRING
) { 
1442                 /* Save a string value */ 
1444                 len 
= htonl(sdslen(sval
)); 
1445                 if (fwrite(&len
,4,1,fp
) == 0) goto werr
; 
1447                     fwrite(sval
,sdslen(sval
),1,fp
) == 0) goto werr
; 
1448             } else if (type 
== REDIS_LIST
) { 
1449                 /* Save a list value */ 
1450                 list 
*list 
= o
->ptr
; 
1451                 listNode 
*ln 
= list
->head
; 
1453                 len 
= htonl(listLength(list
)); 
1454                 if (fwrite(&len
,4,1,fp
) == 0) goto werr
; 
1456                     robj 
*eleobj 
= listNodeValue(ln
); 
1457                     len 
= htonl(sdslen(eleobj
->ptr
)); 
1458                     if (fwrite(&len
,4,1,fp
) == 0) goto werr
; 
1459                     if (sdslen(eleobj
->ptr
) && fwrite(eleobj
->ptr
,sdslen(eleobj
->ptr
),1,fp
) == 0) 
1463             } else if (type 
== REDIS_SET
) { 
1464                 /* Save a set value */ 
1466                 dictIterator 
*di 
= dictGetIterator(set
); 
1469                 if (!set
) oom("dictGetIteraotr"); 
1470                 len 
= htonl(dictGetHashTableUsed(set
)); 
1471                 if (fwrite(&len
,4,1,fp
) == 0) goto werr
; 
1472                 while((de 
= dictNext(di
)) != NULL
) { 
1475                     eleobj 
= dictGetEntryKey(de
); 
1476                     len 
= htonl(sdslen(eleobj
->ptr
)); 
1477                     if (fwrite(&len
,4,1,fp
) == 0) goto werr
; 
1478                     if (sdslen(eleobj
->ptr
) && fwrite(eleobj
->ptr
,sdslen(eleobj
->ptr
),1,fp
) == 0) 
1481                 dictReleaseIterator(di
); 
1486         dictReleaseIterator(di
); 
1490     if (fwrite(&type
,1,1,fp
) == 0) goto werr
; 
1495     /* Use RENAME to make sure the DB file is changed atomically only 
1496      * if the generate DB file is ok. */ 
1497     if (rename(tmpfile
,filename
) == -1) { 
1498         redisLog(REDIS_WARNING
,"Error moving temp DB file on the final destionation: %s", strerror(errno
)); 
1502     redisLog(REDIS_NOTICE
,"DB saved on disk"); 
1504     server
.lastsave 
= time(NULL
); 
1510     redisLog(REDIS_WARNING
,"Write error saving DB on disk: %s", strerror(errno
)); 
1511     if (di
) dictReleaseIterator(di
); 
1515 static int saveDbBackground(char *filename
) { 
1518     if (server
.bgsaveinprogress
) return REDIS_ERR
; 
1519     if ((childpid 
= fork()) == 0) { 
1522         if (saveDb(filename
) == REDIS_OK
) { 
1529         redisLog(REDIS_NOTICE
,"Background saving started by pid %d",childpid
); 
1530         server
.bgsaveinprogress 
= 1; 
1533     return REDIS_OK
; /* unreached */ 
1536 static int loadDb(char *filename
) { 
1538     char buf
[REDIS_LOADBUF_LEN
];    /* Try to use this buffer instead of */ 
1539     char vbuf
[REDIS_LOADBUF_LEN
];   /* malloc() when the element is small */ 
1540     char *key 
= NULL
, *val 
= NULL
; 
1541     uint32_t klen
,vlen
,dbid
; 
1544     dict 
*d 
= server
.dict
[0]; 
1546     fp 
= fopen(filename
,"r"); 
1547     if (!fp
) return REDIS_ERR
; 
1548     if (fread(buf
,9,1,fp
) == 0) goto eoferr
; 
1549     if (memcmp(buf
,"REDIS0000",9) != 0) { 
1551         redisLog(REDIS_WARNING
,"Wrong signature trying to load DB from file"); 
1558         if (fread(&type
,1,1,fp
) == 0) goto eoferr
; 
1559         if (type 
== REDIS_EOF
) break; 
1560         /* Handle SELECT DB opcode as a special case */ 
1561         if (type 
== REDIS_SELECTDB
) { 
1562             if (fread(&dbid
,4,1,fp
) == 0) goto eoferr
; 
1564             if (dbid 
>= (unsigned)server
.dbnum
) { 
1565                 redisLog(REDIS_WARNING
,"FATAL: Data file was created with a Redis server compiled to handle more than %d databases. Exiting\n", server
.dbnum
); 
1568             d 
= server
.dict
[dbid
]; 
1572         if (fread(&klen
,4,1,fp
) == 0) goto eoferr
; 
1574         if (klen 
<= REDIS_LOADBUF_LEN
) { 
1577             key 
= zmalloc(klen
); 
1578             if (!key
) oom("Loading DB from file"); 
1580         if (fread(key
,klen
,1,fp
) == 0) goto eoferr
; 
1582         if (type 
== REDIS_STRING
) { 
1583             /* Read string value */ 
1584             if (fread(&vlen
,4,1,fp
) == 0) goto eoferr
; 
1586             if (vlen 
<= REDIS_LOADBUF_LEN
) { 
1589                 val 
= zmalloc(vlen
); 
1590                 if (!val
) oom("Loading DB from file"); 
1592             if (vlen 
&& fread(val
,vlen
,1,fp
) == 0) goto eoferr
; 
1593             o 
= createObject(REDIS_STRING
,sdsnewlen(val
,vlen
)); 
1594         } else if (type 
== REDIS_LIST 
|| type 
== REDIS_SET
) { 
1595             /* Read list/set value */ 
1597             if (fread(&listlen
,4,1,fp
) == 0) goto eoferr
; 
1598             listlen 
= ntohl(listlen
); 
1599             o 
= (type 
== REDIS_LIST
) ? createListObject() : createSetObject(); 
1600             /* Load every single element of the list/set */ 
1604                 if (fread(&vlen
,4,1,fp
) == 0) goto eoferr
; 
1606                 if (vlen 
<= REDIS_LOADBUF_LEN
) { 
1609                     val 
= zmalloc(vlen
); 
1610                     if (!val
) oom("Loading DB from file"); 
1612                 if (vlen 
&& fread(val
,vlen
,1,fp
) == 0) goto eoferr
; 
1613                 ele 
= createObject(REDIS_STRING
,sdsnewlen(val
,vlen
)); 
1614                 if (type 
== REDIS_LIST
) { 
1615                     if (!listAddNodeTail((list
*)o
->ptr
,ele
)) 
1616                         oom("listAddNodeTail"); 
1618                     if (dictAdd((dict
*)o
->ptr
,ele
,NULL
) == DICT_ERR
) 
1621                 /* free the temp buffer if needed */ 
1622                 if (val 
!= vbuf
) zfree(val
); 
1628         /* Add the new object in the hash table */ 
1629         retval 
= dictAdd(d
,createStringObject(key
,klen
),o
); 
1630         if (retval 
== DICT_ERR
) { 
1631             redisLog(REDIS_WARNING
,"Loading DB, duplicated key found! Unrecoverable error, exiting now."); 
1634         /* Iteration cleanup */ 
1635         if (key 
!= buf
) zfree(key
); 
1636         if (val 
!= vbuf
) zfree(val
); 
1642 eoferr
: /* unexpected end of file is handled here with a fatal exit */ 
1643     if (key 
!= buf
) zfree(key
); 
1644     if (val 
!= vbuf
) zfree(val
); 
1645     redisLog(REDIS_WARNING
,"Short read loading DB. Unrecoverable error, exiting now."); 
1647     return REDIS_ERR
; /* Just to avoid warning */ 
1650 /*================================== Commands =============================== */ 
1652 static void pingCommand(redisClient 
*c
) { 
1653     addReply(c
,shared
.pong
); 
1656 static void echoCommand(redisClient 
*c
) { 
1657     addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n", 
1658         (int)sdslen(c
->argv
[1]->ptr
))); 
1659     addReply(c
,c
->argv
[1]); 
1660     addReply(c
,shared
.crlf
); 
1663 /*=================================== Strings =============================== */ 
1665 static void setGenericCommand(redisClient 
*c
, int nx
) { 
1668     retval 
= dictAdd(c
->dict
,c
->argv
[1],c
->argv
[2]); 
1669     if (retval 
== DICT_ERR
) { 
1671             dictReplace(c
->dict
,c
->argv
[1],c
->argv
[2]); 
1672             incrRefCount(c
->argv
[2]); 
1674             addReply(c
,shared
.zero
); 
1678         incrRefCount(c
->argv
[1]); 
1679         incrRefCount(c
->argv
[2]); 
1682     addReply(c
, nx 
? shared
.one 
: shared
.ok
); 
1685 static void setCommand(redisClient 
*c
) { 
1686     return setGenericCommand(c
,0); 
1689 static void setnxCommand(redisClient 
*c
) { 
1690     return setGenericCommand(c
,1); 
1693 static void getCommand(redisClient 
*c
) { 
1696     de 
= dictFind(c
->dict
,c
->argv
[1]); 
1698         addReply(c
,shared
.nil
); 
1700         robj 
*o 
= dictGetEntryVal(de
); 
1702         if (o
->type 
!= REDIS_STRING
) { 
1703             addReply(c
,shared
.wrongtypeerrbulk
); 
1705             addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(o
->ptr
))); 
1707             addReply(c
,shared
.crlf
); 
1712 static void mgetCommand(redisClient 
*c
) { 
1716     addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",c
->argc
-1)); 
1717     for (j 
= 1; j 
< c
->argc
; j
++) { 
1718         de 
= dictFind(c
->dict
,c
->argv
[j
]); 
1720             addReply(c
,shared
.minus1
); 
1722             robj 
*o 
= dictGetEntryVal(de
); 
1724             if (o
->type 
!= REDIS_STRING
) { 
1725                 addReply(c
,shared
.minus1
); 
1727                 addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(o
->ptr
))); 
1729                 addReply(c
,shared
.crlf
); 
1735 static void incrDecrCommand(redisClient 
*c
, int incr
) { 
1741     de 
= dictFind(c
->dict
,c
->argv
[1]); 
1745         robj 
*o 
= dictGetEntryVal(de
); 
1747         if (o
->type 
!= REDIS_STRING
) { 
1752             value 
= strtoll(o
->ptr
, &eptr
, 10); 
1757     o 
= createObject(REDIS_STRING
,sdscatprintf(sdsempty(),"%lld",value
)); 
1758     retval 
= dictAdd(c
->dict
,c
->argv
[1],o
); 
1759     if (retval 
== DICT_ERR
) { 
1760         dictReplace(c
->dict
,c
->argv
[1],o
); 
1762         incrRefCount(c
->argv
[1]); 
1766     addReply(c
,shared
.crlf
); 
1769 static void incrCommand(redisClient 
*c
) { 
1770     return incrDecrCommand(c
,1); 
1773 static void decrCommand(redisClient 
*c
) { 
1774     return incrDecrCommand(c
,-1); 
1777 static void incrbyCommand(redisClient 
*c
) { 
1778     int incr 
= atoi(c
->argv
[2]->ptr
); 
1779     return incrDecrCommand(c
,incr
); 
1782 static void decrbyCommand(redisClient 
*c
) { 
1783     int incr 
= atoi(c
->argv
[2]->ptr
); 
1784     return incrDecrCommand(c
,-incr
); 
1787 /* ========================= Type agnostic commands ========================= */ 
1789 static void delCommand(redisClient 
*c
) { 
1790     if (dictDelete(c
->dict
,c
->argv
[1]) == DICT_OK
) { 
1792         addReply(c
,shared
.one
); 
1794         addReply(c
,shared
.zero
); 
1798 static void existsCommand(redisClient 
*c
) { 
1801     de 
= dictFind(c
->dict
,c
->argv
[1]); 
1803         addReply(c
,shared
.zero
); 
1805         addReply(c
,shared
.one
); 
1808 static void selectCommand(redisClient 
*c
) { 
1809     int id 
= atoi(c
->argv
[1]->ptr
); 
1811     if (selectDb(c
,id
) == REDIS_ERR
) { 
1812         addReplySds(c
,"-ERR invalid DB index\r\n"); 
1814         addReply(c
,shared
.ok
); 
1818 static void randomkeyCommand(redisClient 
*c
) { 
1821     de 
= dictGetRandomKey(c
->dict
); 
1823         addReply(c
,shared
.crlf
); 
1825         addReply(c
,dictGetEntryKey(de
)); 
1826         addReply(c
,shared
.crlf
); 
1830 static void keysCommand(redisClient 
*c
) { 
1833     sds pattern 
= c
->argv
[1]->ptr
; 
1834     int plen 
= sdslen(pattern
); 
1835     int numkeys 
= 0, keyslen 
= 0; 
1836     robj 
*lenobj 
= createObject(REDIS_STRING
,NULL
); 
1838     di 
= dictGetIterator(c
->dict
); 
1839     if (!di
) oom("dictGetIterator"); 
1841     decrRefCount(lenobj
); 
1842     while((de 
= dictNext(di
)) != NULL
) { 
1843         robj 
*keyobj 
= dictGetEntryKey(de
); 
1844         sds key 
= keyobj
->ptr
; 
1845         if ((pattern
[0] == '*' && pattern
[1] == '\0') || 
1846             stringmatchlen(pattern
,plen
,key
,sdslen(key
),0)) { 
1848                 addReply(c
,shared
.space
); 
1851             keyslen 
+= sdslen(key
); 
1854     dictReleaseIterator(di
); 
1855     lenobj
->ptr 
= sdscatprintf(sdsempty(),"%lu\r\n",keyslen
+(numkeys 
? (numkeys
-1) : 0)); 
1856     addReply(c
,shared
.crlf
); 
1859 static void dbsizeCommand(redisClient 
*c
) { 
1861         sdscatprintf(sdsempty(),"%lu\r\n",dictGetHashTableUsed(c
->dict
))); 
1864 static void lastsaveCommand(redisClient 
*c
) { 
1866         sdscatprintf(sdsempty(),"%lu\r\n",server
.lastsave
)); 
1869 static void typeCommand(redisClient 
*c
) { 
1873     de 
= dictFind(c
->dict
,c
->argv
[1]); 
1877         robj 
*o 
= dictGetEntryVal(de
); 
1880         case REDIS_STRING
: type 
= "string"; break; 
1881         case REDIS_LIST
: type 
= "list"; break; 
1882         case REDIS_SET
: type 
= "set"; break; 
1883         default: type 
= "unknown"; break; 
1886     addReplySds(c
,sdsnew(type
)); 
1887     addReply(c
,shared
.crlf
); 
1890 static void saveCommand(redisClient 
*c
) { 
1891     if (saveDb(server
.dbfilename
) == REDIS_OK
) { 
1892         addReply(c
,shared
.ok
); 
1894         addReply(c
,shared
.err
); 
1898 static void bgsaveCommand(redisClient 
*c
) { 
1899     if (server
.bgsaveinprogress
) { 
1900         addReplySds(c
,sdsnew("-ERR background save already in progress\r\n")); 
1903     if (saveDbBackground(server
.dbfilename
) == REDIS_OK
) { 
1904         addReply(c
,shared
.ok
); 
1906         addReply(c
,shared
.err
); 
1910 static void shutdownCommand(redisClient 
*c
) { 
1911     redisLog(REDIS_WARNING
,"User requested shutdown, saving DB..."); 
1912     if (saveDb(server
.dbfilename
) == REDIS_OK
) { 
1913         if (server
.daemonize
) { 
1914           unlink(server
.pidfile
); 
1916         redisLog(REDIS_WARNING
,"Server exit now, bye bye..."); 
1919         redisLog(REDIS_WARNING
,"Error trying to save the DB, can't exit");  
1920         addReplySds(c
,sdsnew("-ERR can't quit, problems saving the DB\r\n")); 
1924 static void renameGenericCommand(redisClient 
*c
, int nx
) { 
1928     /* To use the same key as src and dst is probably an error */ 
1929     if (sdscmp(c
->argv
[1]->ptr
,c
->argv
[2]->ptr
) == 0) { 
1931             addReply(c
,shared
.minus3
); 
1933             addReplySds(c
,sdsnew("-ERR src and dest key are the same\r\n")); 
1937     de 
= dictFind(c
->dict
,c
->argv
[1]); 
1940             addReply(c
,shared
.minus1
); 
1942             addReply(c
,shared
.nokeyerr
); 
1945     o 
= dictGetEntryVal(de
); 
1947     if (dictAdd(c
->dict
,c
->argv
[2],o
) == DICT_ERR
) { 
1950             addReply(c
,shared
.zero
); 
1953         dictReplace(c
->dict
,c
->argv
[2],o
); 
1955         incrRefCount(c
->argv
[2]); 
1957     dictDelete(c
->dict
,c
->argv
[1]); 
1959     addReply(c
,nx 
? shared
.one 
: shared
.ok
); 
1962 static void renameCommand(redisClient 
*c
) { 
1963     renameGenericCommand(c
,0); 
1966 static void renamenxCommand(redisClient 
*c
) { 
1967     renameGenericCommand(c
,1); 
1970 static void moveCommand(redisClient 
*c
) { 
1976     /* Obtain source and target DB pointers */ 
1979     if (selectDb(c
,atoi(c
->argv
[2]->ptr
)) == REDIS_ERR
) { 
1980         addReply(c
,shared
.minus4
); 
1987     /* If the user is moving using as target the same 
1988      * DB as the source DB it is probably an error. */ 
1990         addReply(c
,shared
.minus3
); 
1994     /* Check if the element exists and get a reference */ 
1995     de 
= dictFind(c
->dict
,c
->argv
[1]); 
1997         addReply(c
,shared
.zero
); 
2001     /* Try to add the element to the target DB */ 
2002     key 
= dictGetEntryKey(de
); 
2003     o 
= dictGetEntryVal(de
); 
2004     if (dictAdd(dst
,key
,o
) == DICT_ERR
) { 
2005         addReply(c
,shared
.zero
); 
2011     /* OK! key moved, free the entry in the source DB */ 
2012     dictDelete(src
,c
->argv
[1]); 
2014     addReply(c
,shared
.one
); 
2017 /* =================================== Lists ================================ */ 
2018 static void pushGenericCommand(redisClient 
*c
, int where
) { 
2023     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2025         lobj 
= createListObject(); 
2027         if (where 
== REDIS_HEAD
) { 
2028             if (!listAddNodeHead(list
,c
->argv
[2])) oom("listAddNodeHead"); 
2030             if (!listAddNodeTail(list
,c
->argv
[2])) oom("listAddNodeTail"); 
2032         dictAdd(c
->dict
,c
->argv
[1],lobj
); 
2033         incrRefCount(c
->argv
[1]); 
2034         incrRefCount(c
->argv
[2]); 
2036         lobj 
= dictGetEntryVal(de
); 
2037         if (lobj
->type 
!= REDIS_LIST
) { 
2038             addReply(c
,shared
.wrongtypeerr
); 
2042         if (where 
== REDIS_HEAD
) { 
2043             if (!listAddNodeHead(list
,c
->argv
[2])) oom("listAddNodeHead"); 
2045             if (!listAddNodeTail(list
,c
->argv
[2])) oom("listAddNodeTail"); 
2047         incrRefCount(c
->argv
[2]); 
2050     addReply(c
,shared
.ok
); 
2053 static void lpushCommand(redisClient 
*c
) { 
2054     pushGenericCommand(c
,REDIS_HEAD
); 
2057 static void rpushCommand(redisClient 
*c
) { 
2058     pushGenericCommand(c
,REDIS_TAIL
); 
2061 static void llenCommand(redisClient 
*c
) { 
2065     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2067         addReply(c
,shared
.zero
); 
2070         robj 
*o 
= dictGetEntryVal(de
); 
2071         if (o
->type 
!= REDIS_LIST
) { 
2072             addReply(c
,shared
.minus2
); 
2075             addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",listLength(l
))); 
2080 static void lindexCommand(redisClient 
*c
) { 
2082     int index 
= atoi(c
->argv
[2]->ptr
); 
2084     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2086         addReply(c
,shared
.nil
); 
2088         robj 
*o 
= dictGetEntryVal(de
); 
2090         if (o
->type 
!= REDIS_LIST
) { 
2091             addReply(c
,shared
.wrongtypeerrbulk
); 
2093             list 
*list 
= o
->ptr
; 
2096             ln 
= listIndex(list
, index
); 
2098                 addReply(c
,shared
.nil
); 
2100                 robj 
*ele 
= listNodeValue(ln
); 
2101                 addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(ele
->ptr
))); 
2103                 addReply(c
,shared
.crlf
); 
2109 static void lsetCommand(redisClient 
*c
) { 
2111     int index 
= atoi(c
->argv
[2]->ptr
); 
2113     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2115         addReply(c
,shared
.nokeyerr
); 
2117         robj 
*o 
= dictGetEntryVal(de
); 
2119         if (o
->type 
!= REDIS_LIST
) { 
2120             addReply(c
,shared
.wrongtypeerr
); 
2122             list 
*list 
= o
->ptr
; 
2125             ln 
= listIndex(list
, index
); 
2127                 addReplySds(c
,sdsnew("-ERR index out of range\r\n")); 
2129                 robj 
*ele 
= listNodeValue(ln
); 
2132                 listNodeValue(ln
) = c
->argv
[3]; 
2133                 incrRefCount(c
->argv
[3]); 
2134                 addReply(c
,shared
.ok
); 
2141 static void popGenericCommand(redisClient 
*c
, int where
) { 
2144     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2146         addReply(c
,shared
.nil
); 
2148         robj 
*o 
= dictGetEntryVal(de
); 
2150         if (o
->type 
!= REDIS_LIST
) { 
2151             addReply(c
,shared
.wrongtypeerrbulk
); 
2153             list 
*list 
= o
->ptr
; 
2156             if (where 
== REDIS_HEAD
) 
2157                 ln 
= listFirst(list
); 
2159                 ln 
= listLast(list
); 
2162                 addReply(c
,shared
.nil
); 
2164                 robj 
*ele 
= listNodeValue(ln
); 
2165                 addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(ele
->ptr
))); 
2167                 addReply(c
,shared
.crlf
); 
2168                 listDelNode(list
,ln
); 
2175 static void lpopCommand(redisClient 
*c
) { 
2176     popGenericCommand(c
,REDIS_HEAD
); 
2179 static void rpopCommand(redisClient 
*c
) { 
2180     popGenericCommand(c
,REDIS_TAIL
); 
2183 static void lrangeCommand(redisClient 
*c
) { 
2185     int start 
= atoi(c
->argv
[2]->ptr
); 
2186     int end 
= atoi(c
->argv
[3]->ptr
); 
2188     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2190         addReply(c
,shared
.nil
); 
2192         robj 
*o 
= dictGetEntryVal(de
); 
2194         if (o
->type 
!= REDIS_LIST
) { 
2195             addReply(c
,shared
.wrongtypeerrbulk
); 
2197             list 
*list 
= o
->ptr
; 
2199             int llen 
= listLength(list
); 
2203             /* convert negative indexes */ 
2204             if (start 
< 0) start 
= llen
+start
; 
2205             if (end 
< 0) end 
= llen
+end
; 
2206             if (start 
< 0) start 
= 0; 
2207             if (end 
< 0) end 
= 0; 
2209             /* indexes sanity checks */ 
2210             if (start 
> end 
|| start 
>= llen
) { 
2211                 /* Out of range start or start > end result in empty list */ 
2212                 addReply(c
,shared
.zero
); 
2215             if (end 
>= llen
) end 
= llen
-1; 
2216             rangelen 
= (end
-start
)+1; 
2218             /* Return the result in form of a multi-bulk reply */ 
2219             ln 
= listIndex(list
, start
); 
2220             addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",rangelen
)); 
2221             for (j 
= 0; j 
< rangelen
; j
++) { 
2222                 ele 
= listNodeValue(ln
); 
2223                 addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(ele
->ptr
))); 
2225                 addReply(c
,shared
.crlf
); 
2232 static void ltrimCommand(redisClient 
*c
) { 
2234     int start 
= atoi(c
->argv
[2]->ptr
); 
2235     int end 
= atoi(c
->argv
[3]->ptr
); 
2237     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2239         addReply(c
,shared
.nokeyerr
); 
2241         robj 
*o 
= dictGetEntryVal(de
); 
2243         if (o
->type 
!= REDIS_LIST
) { 
2244             addReply(c
,shared
.wrongtypeerr
); 
2246             list 
*list 
= o
->ptr
; 
2248             int llen 
= listLength(list
); 
2249             int j
, ltrim
, rtrim
; 
2251             /* convert negative indexes */ 
2252             if (start 
< 0) start 
= llen
+start
; 
2253             if (end 
< 0) end 
= llen
+end
; 
2254             if (start 
< 0) start 
= 0; 
2255             if (end 
< 0) end 
= 0; 
2257             /* indexes sanity checks */ 
2258             if (start 
> end 
|| start 
>= llen
) { 
2259                 /* Out of range start or start > end result in empty list */ 
2263                 if (end 
>= llen
) end 
= llen
-1; 
2268             /* Remove list elements to perform the trim */ 
2269             for (j 
= 0; j 
< ltrim
; j
++) { 
2270                 ln 
= listFirst(list
); 
2271                 listDelNode(list
,ln
); 
2273             for (j 
= 0; j 
< rtrim
; j
++) { 
2274                 ln 
= listLast(list
); 
2275                 listDelNode(list
,ln
); 
2277             addReply(c
,shared
.ok
); 
2283 static void lremCommand(redisClient 
*c
) { 
2286     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2288         addReply(c
,shared
.minus1
); 
2290         robj 
*o 
= dictGetEntryVal(de
); 
2292         if (o
->type 
!= REDIS_LIST
) { 
2293             addReply(c
,shared
.minus2
); 
2295             list 
*list 
= o
->ptr
; 
2296             listNode 
*ln
, *next
; 
2297             int toremove 
= atoi(c
->argv
[2]->ptr
); 
2302                 toremove 
= -toremove
; 
2305             ln 
= fromtail 
? list
->tail 
: list
->head
; 
2307                 next 
= fromtail 
? ln
->prev 
: ln
->next
; 
2308                 robj 
*ele 
= listNodeValue(ln
); 
2309                 if (sdscmp(ele
->ptr
,c
->argv
[3]->ptr
) == 0) { 
2310                     listDelNode(list
,ln
); 
2313                     if (toremove 
&& removed 
== toremove
) break; 
2317             addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",removed
)); 
2322 /* ==================================== Sets ================================ */ 
2324 static void saddCommand(redisClient 
*c
) { 
2328     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2330         set 
= createSetObject(); 
2331         dictAdd(c
->dict
,c
->argv
[1],set
); 
2332         incrRefCount(c
->argv
[1]); 
2334         set 
= dictGetEntryVal(de
); 
2335         if (set
->type 
!= REDIS_SET
) { 
2336             addReply(c
,shared
.minus2
); 
2340     if (dictAdd(set
->ptr
,c
->argv
[2],NULL
) == DICT_OK
) { 
2341         incrRefCount(c
->argv
[2]); 
2343         addReply(c
,shared
.one
); 
2345         addReply(c
,shared
.zero
); 
2349 static void sremCommand(redisClient 
*c
) { 
2352     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2354         addReply(c
,shared
.zero
); 
2358         set 
= dictGetEntryVal(de
); 
2359         if (set
->type 
!= REDIS_SET
) { 
2360             addReply(c
,shared
.minus2
); 
2363         if (dictDelete(set
->ptr
,c
->argv
[2]) == DICT_OK
) { 
2365             addReply(c
,shared
.one
); 
2367             addReply(c
,shared
.zero
); 
2372 static void sismemberCommand(redisClient 
*c
) { 
2375     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2377         addReply(c
,shared
.zero
); 
2381         set 
= dictGetEntryVal(de
); 
2382         if (set
->type 
!= REDIS_SET
) { 
2383             addReply(c
,shared
.minus2
); 
2386         if (dictFind(set
->ptr
,c
->argv
[2])) 
2387             addReply(c
,shared
.one
); 
2389             addReply(c
,shared
.zero
); 
2393 static void scardCommand(redisClient 
*c
) { 
2397     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2399         addReply(c
,shared
.zero
); 
2402         robj 
*o 
= dictGetEntryVal(de
); 
2403         if (o
->type 
!= REDIS_SET
) { 
2404             addReply(c
,shared
.minus2
); 
2407             addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n", 
2408                 dictGetHashTableUsed(s
))); 
2413 static int qsortCompareSetsByCardinality(const void *s1
, const void *s2
) { 
2414     dict 
**d1 
= (void*) s1
, **d2 
= (void*) s2
; 
2416     return dictGetHashTableUsed(*d1
)-dictGetHashTableUsed(*d2
); 
2419 static void sinterGenericCommand(redisClient 
*c
, robj 
**setskeys
, int setsnum
, robj 
*dstkey
) { 
2420     dict 
**dv 
= zmalloc(sizeof(dict
*)*setsnum
); 
2423     robj 
*lenobj 
= NULL
, *dstset 
= NULL
; 
2424     int j
, cardinality 
= 0; 
2426     if (!dv
) oom("sinterCommand"); 
2427     for (j 
= 0; j 
< setsnum
; j
++) { 
2431         de 
= dictFind(c
->dict
,setskeys
[j
]); 
2434             addReply(c
,dstkey 
? shared
.nokeyerr 
: shared
.nil
); 
2437         setobj 
= dictGetEntryVal(de
); 
2438         if (setobj
->type 
!= REDIS_SET
) { 
2440             addReply(c
,dstkey 
? shared
.wrongtypeerr 
: shared
.wrongtypeerrbulk
); 
2443         dv
[j
] = setobj
->ptr
; 
2445     /* Sort sets from the smallest to largest, this will improve our 
2446      * algorithm's performace */ 
2447     qsort(dv
,setsnum
,sizeof(dict
*),qsortCompareSetsByCardinality
); 
2449     /* The first thing we should output is the total number of elements... 
2450      * since this is a multi-bulk write, but at this stage we don't know 
2451      * the intersection set size, so we use a trick, append an empty object 
2452      * to the output list and save the pointer to later modify it with the 
2455         lenobj 
= createObject(REDIS_STRING
,NULL
); 
2457         decrRefCount(lenobj
); 
2459         /* If we have a target key where to store the resulting set 
2460          * create this key with an empty set inside */ 
2461         dstset 
= createSetObject(); 
2462         dictDelete(c
->dict
,dstkey
); 
2463         dictAdd(c
->dict
,dstkey
,dstset
); 
2464         incrRefCount(dstkey
); 
2467     /* Iterate all the elements of the first (smallest) set, and test 
2468      * the element against all the other sets, if at least one set does 
2469      * not include the element it is discarded */ 
2470     di 
= dictGetIterator(dv
[0]); 
2471     if (!di
) oom("dictGetIterator"); 
2473     while((de 
= dictNext(di
)) != NULL
) { 
2476         for (j 
= 1; j 
< setsnum
; j
++) 
2477             if (dictFind(dv
[j
],dictGetEntryKey(de
)) == NULL
) break; 
2479             continue; /* at least one set does not contain the member */ 
2480         ele 
= dictGetEntryKey(de
); 
2482             addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",sdslen(ele
->ptr
))); 
2484             addReply(c
,shared
.crlf
); 
2487             dictAdd(dstset
->ptr
,ele
,NULL
); 
2491     dictReleaseIterator(di
); 
2494         lenobj
->ptr 
= sdscatprintf(sdsempty(),"%d\r\n",cardinality
); 
2496         addReply(c
,shared
.ok
); 
2500 static void sinterCommand(redisClient 
*c
) { 
2501     sinterGenericCommand(c
,c
->argv
+1,c
->argc
-1,NULL
); 
2504 static void sinterstoreCommand(redisClient 
*c
) { 
2505     sinterGenericCommand(c
,c
->argv
+2,c
->argc
-2,c
->argv
[1]); 
2508 static void flushdbCommand(redisClient 
*c
) { 
2510     addReply(c
,shared
.ok
); 
2511     saveDb(server
.dbfilename
); 
2514 static void flushallCommand(redisClient 
*c
) { 
2516     addReply(c
,shared
.ok
); 
2517     saveDb(server
.dbfilename
); 
2520 redisSortOperation 
*createSortOperation(int type
, robj 
*pattern
) { 
2521     redisSortOperation 
*so 
= zmalloc(sizeof(*so
)); 
2522     if (!so
) oom("createSortOperation"); 
2524     so
->pattern 
= pattern
; 
2528 /* Return the value associated to the key with a name obtained 
2529  * substituting the first occurence of '*' in 'pattern' with 'subst' */ 
2530 robj 
*lookupKeyByPattern(dict 
*dict
, robj 
*pattern
, robj 
*subst
) { 
2534     int prefixlen
, sublen
, postfixlen
; 
2536     /* Expoit the internal sds representation to create a sds string allocated on the stack in order to make this function faster */ 
2540         char buf
[REDIS_SORTKEY_MAX
+1]; 
2544     spat 
= pattern
->ptr
; 
2546     if (sdslen(spat
)+sdslen(ssub
)-1 > REDIS_SORTKEY_MAX
) return NULL
; 
2547     p 
= strchr(spat
,'*'); 
2548     if (!p
) return NULL
; 
2551     sublen 
= sdslen(ssub
); 
2552     postfixlen 
= sdslen(spat
)-(prefixlen
+1); 
2553     memcpy(keyname
.buf
,spat
,prefixlen
); 
2554     memcpy(keyname
.buf
+prefixlen
,ssub
,sublen
); 
2555     memcpy(keyname
.buf
+prefixlen
+sublen
,p
+1,postfixlen
); 
2556     keyname
.buf
[prefixlen
+sublen
+postfixlen
] = '\0'; 
2557     keyname
.len 
= prefixlen
+sublen
+postfixlen
; 
2559     keyobj
.refcount 
= 1; 
2560     keyobj
.type 
= REDIS_STRING
; 
2561     keyobj
.ptr 
= ((char*)&keyname
)+(sizeof(long)*2); 
2563     de 
= dictFind(dict
,&keyobj
); 
2564     // printf("lookup '%s' => %p\n", keyname.buf,de); 
2565     if (!de
) return NULL
; 
2566     return dictGetEntryVal(de
); 
2569 /* sortCompare() is used by qsort in sortCommand(). Given that qsort_r with 
2570  * the additional parameter is not standard but a BSD-specific we have to 
2571  * pass sorting parameters via the global 'server' structure */ 
2572 static int sortCompare(const void *s1
, const void *s2
) { 
2573     const redisSortObject 
*so1 
= s1
, *so2 
= s2
; 
2576     if (!server
.sort_alpha
) { 
2577         /* Numeric sorting. Here it's trivial as we precomputed scores */ 
2578         if (so1
->u
.score 
> so2
->u
.score
) { 
2580         } else if (so1
->u
.score 
< so2
->u
.score
) { 
2586         /* Alphanumeric sorting */ 
2587         if (server
.sort_bypattern
) { 
2588             if (!so1
->u
.cmpobj 
|| !so2
->u
.cmpobj
) { 
2589                 /* At least one compare object is NULL */ 
2590                 if (so1
->u
.cmpobj 
== so2
->u
.cmpobj
) 
2592                 else if (so1
->u
.cmpobj 
== NULL
) 
2597                 /* We have both the objects, use strcoll */ 
2598                 cmp 
= strcoll(so1
->u
.cmpobj
->ptr
,so2
->u
.cmpobj
->ptr
); 
2601             /* Compare elements directly */ 
2602             cmp 
= strcoll(so1
->obj
->ptr
,so2
->obj
->ptr
); 
2605     return server
.sort_desc 
? -cmp 
: cmp
; 
2608 /* The SORT command is the most complex command in Redis. Warning: this code 
2609  * is optimized for speed and a bit less for readability */ 
2610 static void sortCommand(redisClient 
*c
) { 
2614     int desc 
= 0, alpha 
= 0; 
2615     int limit_start 
= 0, limit_count 
= -1, start
, end
; 
2616     int j
, dontsort 
= 0, vectorlen
; 
2617     int getop 
= 0; /* GET operation counter */ 
2618     robj 
*sortval
, *sortby 
= NULL
; 
2619     redisSortObject 
*vector
; /* Resulting vector to sort */ 
2621     /* Lookup the key to sort. It must be of the right types */ 
2622     de 
= dictFind(c
->dict
,c
->argv
[1]); 
2624         addReply(c
,shared
.nokeyerrbulk
); 
2627     sortval 
= dictGetEntryVal(de
); 
2628     if (sortval
->type 
!= REDIS_SET 
&& sortval
->type 
!= REDIS_LIST
) { 
2629         addReply(c
,shared
.wrongtypeerrbulk
); 
2633     /* Create a list of operations to perform for every sorted element. 
2634      * Operations can be GET/DEL/INCR/DECR */ 
2635     operations 
= listCreate(); 
2636     listSetFreeMethod(operations
,zfree
); 
2639     /* Now we need to protect sortval incrementing its count, in the future 
2640      * SORT may have options able to overwrite/delete keys during the sorting 
2641      * and the sorted key itself may get destroied */ 
2642     incrRefCount(sortval
); 
2644     /* The SORT command has an SQL-alike syntax, parse it */ 
2645     while(j 
< c
->argc
) { 
2646         int leftargs 
= c
->argc
-j
-1; 
2647         if (!strcasecmp(c
->argv
[j
]->ptr
,"asc")) { 
2649         } else if (!strcasecmp(c
->argv
[j
]->ptr
,"desc")) { 
2651         } else if (!strcasecmp(c
->argv
[j
]->ptr
,"alpha")) { 
2653         } else if (!strcasecmp(c
->argv
[j
]->ptr
,"limit") && leftargs 
>= 2) { 
2654             limit_start 
= atoi(c
->argv
[j
+1]->ptr
); 
2655             limit_count 
= atoi(c
->argv
[j
+2]->ptr
); 
2657         } else if (!strcasecmp(c
->argv
[j
]->ptr
,"by") && leftargs 
>= 1) { 
2658             sortby 
= c
->argv
[j
+1]; 
2659             /* If the BY pattern does not contain '*', i.e. it is constant, 
2660              * we don't need to sort nor to lookup the weight keys. */ 
2661             if (strchr(c
->argv
[j
+1]->ptr
,'*') == NULL
) dontsort 
= 1; 
2663         } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs 
>= 1) { 
2664             listAddNodeTail(operations
,createSortOperation( 
2665                 REDIS_SORT_GET
,c
->argv
[j
+1])); 
2668         } else if (!strcasecmp(c
->argv
[j
]->ptr
,"del") && leftargs 
>= 1) { 
2669             listAddNodeTail(operations
,createSortOperation( 
2670                 REDIS_SORT_DEL
,c
->argv
[j
+1])); 
2672         } else if (!strcasecmp(c
->argv
[j
]->ptr
,"incr") && leftargs 
>= 1) { 
2673             listAddNodeTail(operations
,createSortOperation( 
2674                 REDIS_SORT_INCR
,c
->argv
[j
+1])); 
2676         } else if (!strcasecmp(c
->argv
[j
]->ptr
,"get") && leftargs 
>= 1) { 
2677             listAddNodeTail(operations
,createSortOperation( 
2678                 REDIS_SORT_DECR
,c
->argv
[j
+1])); 
2681             decrRefCount(sortval
); 
2682             listRelease(operations
); 
2683             addReply(c
,shared
.syntaxerrbulk
); 
2689     /* Load the sorting vector with all the objects to sort */ 
2690     vectorlen 
= (sortval
->type 
== REDIS_LIST
) ? 
2691         listLength((list
*)sortval
->ptr
) : 
2692         dictGetHashTableUsed((dict
*)sortval
->ptr
); 
2693     vector 
= zmalloc(sizeof(redisSortObject
)*vectorlen
); 
2694     if (!vector
) oom("allocating objects vector for SORT"); 
2696     if (sortval
->type 
== REDIS_LIST
) { 
2697         list 
*list 
= sortval
->ptr
; 
2698         listNode 
*ln 
= list
->head
; 
2700             robj 
*ele 
= ln
->value
; 
2701             vector
[j
].obj 
= ele
; 
2702             vector
[j
].u
.score 
= 0; 
2703             vector
[j
].u
.cmpobj 
= NULL
; 
2708         dict 
*set 
= sortval
->ptr
; 
2712         di 
= dictGetIterator(set
); 
2713         if (!di
) oom("dictGetIterator"); 
2714         while((setele 
= dictNext(di
)) != NULL
) { 
2715             vector
[j
].obj 
= dictGetEntryKey(setele
); 
2716             vector
[j
].u
.score 
= 0; 
2717             vector
[j
].u
.cmpobj 
= NULL
; 
2720         dictReleaseIterator(di
); 
2722     assert(j 
== vectorlen
); 
2724     /* Now it's time to load the right scores in the sorting vector */ 
2725     if (dontsort 
== 0) { 
2726         for (j 
= 0; j 
< vectorlen
; j
++) { 
2730                 byval 
= lookupKeyByPattern(c
->dict
,sortby
,vector
[j
].obj
); 
2731                 if (!byval 
|| byval
->type 
!= REDIS_STRING
) continue; 
2733                     vector
[j
].u
.cmpobj 
= byval
; 
2734                     incrRefCount(byval
); 
2736                     vector
[j
].u
.score 
= strtod(byval
->ptr
,NULL
); 
2739                 if (!alpha
) vector
[j
].u
.score 
= strtod(vector
[j
].obj
->ptr
,NULL
); 
2744     /* We are ready to sort the vector... perform a bit of sanity check 
2745      * on the LIMIT option too. We'll use a partial version of quicksort. */ 
2746     start 
= (limit_start 
< 0) ? 0 : limit_start
; 
2747     end 
= (limit_count 
< 0) ? vectorlen
-1 : start
+limit_count
-1; 
2748     if (start 
>= vectorlen
) { 
2749         start 
= vectorlen
-1; 
2752     if (end 
>= vectorlen
) end 
= vectorlen
-1; 
2754     if (dontsort 
== 0) { 
2755         server
.sort_desc 
= desc
; 
2756         server
.sort_alpha 
= alpha
; 
2757         server
.sort_bypattern 
= sortby 
? 1 : 0; 
2758         qsort(vector
,vectorlen
,sizeof(redisSortObject
),sortCompare
); 
2761     /* Send command output to the output buffer, performing the specified 
2762      * GET/DEL/INCR/DECR operations if any. */ 
2763     outputlen 
= getop 
? getop
*(end
-start
+1) : end
-start
+1; 
2764     addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",outputlen
)); 
2765     for (j 
= start
; j 
<= end
; j
++) { 
2766         listNode 
*ln 
= operations
->head
; 
2768             addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n", 
2769                 sdslen(vector
[j
].obj
->ptr
))); 
2770             addReply(c
,vector
[j
].obj
); 
2771             addReply(c
,shared
.crlf
); 
2774             redisSortOperation 
*sop 
= ln
->value
; 
2775             robj 
*val 
= lookupKeyByPattern(c
->dict
,sop
->pattern
, 
2778             if (sop
->type 
== REDIS_SORT_GET
) { 
2779                 if (!val 
|| val
->type 
!= REDIS_STRING
) { 
2780                     addReply(c
,shared
.minus1
); 
2782                     addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n", 
2785                     addReply(c
,shared
.crlf
); 
2787             } else if (sop
->type 
== REDIS_SORT_DEL
) { 
2795     decrRefCount(sortval
); 
2796     listRelease(operations
); 
2797     for (j 
= 0; j 
< vectorlen
; j
++) { 
2798         if (sortby 
&& alpha 
&& vector
[j
].u
.cmpobj
) 
2799             decrRefCount(vector
[j
].u
.cmpobj
); 
2804 static void infoCommand(redisClient 
*c
) { 
2806     time_t uptime 
= time(NULL
)-server
.stat_starttime
; 
2808     info 
= sdscatprintf(sdsempty(), 
2809         "redis_version:%s\r\n" 
2810         "connected_clients:%d\r\n" 
2811         "connected_slaves:%d\r\n" 
2812         "used_memory:%d\r\n" 
2813         "changes_since_last_save:%lld\r\n" 
2814         "last_save_time:%d\r\n" 
2815         "total_connections_received:%lld\r\n" 
2816         "total_commands_processed:%lld\r\n" 
2817         "uptime_in_seconds:%d\r\n" 
2818         "uptime_in_days:%d\r\n" 
2820         listLength(server
.clients
)-listLength(server
.slaves
), 
2821         listLength(server
.slaves
), 
2825         server
.stat_numconnections
, 
2826         server
.stat_numcommands
, 
2830     addReplySds(c
,sdscatprintf(sdsempty(),"%d\r\n",sdslen(info
))); 
2831     addReplySds(c
,info
); 
2832     addReply(c
,shared
.crlf
); 
2835 /* =============================== Replication  ============================= */ 
2837 /* Send the whole output buffer syncronously to the slave. This a general operation in theory, but it is actually useful only for replication. */ 
2838 static int flushClientOutput(redisClient 
*c
) { 
2840     time_t start 
= time(NULL
); 
2842     while(listLength(c
->reply
)) { 
2843         if (time(NULL
)-start 
> 5) return REDIS_ERR
; /* 5 seconds timeout */ 
2844         retval 
= aeWait(c
->fd
,AE_WRITABLE
,1000); 
2847         } else if (retval 
& AE_WRITABLE
) { 
2848             sendReplyToClient(NULL
, c
->fd
, c
, AE_WRITABLE
); 
2854 static int syncWrite(int fd
, void *ptr
, ssize_t size
, int timeout
) { 
2855     ssize_t nwritten
, ret 
= size
; 
2856     time_t start 
= time(NULL
); 
2860         if (aeWait(fd
,AE_WRITABLE
,1000) & AE_WRITABLE
) { 
2861             nwritten 
= write(fd
,ptr
,size
); 
2862             if (nwritten 
== -1) return -1; 
2866         if ((time(NULL
)-start
) > timeout
) { 
2874 static int syncRead(int fd
, void *ptr
, ssize_t size
, int timeout
) { 
2875     ssize_t nread
, totread 
= 0; 
2876     time_t start 
= time(NULL
); 
2880         if (aeWait(fd
,AE_READABLE
,1000) & AE_READABLE
) { 
2881             nread 
= read(fd
,ptr
,size
); 
2882             if (nread 
== -1) return -1; 
2887         if ((time(NULL
)-start
) > timeout
) { 
2895 static int syncReadLine(int fd
, char *ptr
, ssize_t size
, int timeout
) { 
2902         if (syncRead(fd
,&c
,1,timeout
) == -1) return -1; 
2905             if (nread 
&& *(ptr
-1) == '\r') *(ptr
-1) = '\0'; 
2916 static void syncCommand(redisClient 
*c
) { 
2919     time_t start 
= time(NULL
); 
2922     /* ignore SYNC if aleady slave or in monitor mode */ 
2923     if (c
->flags 
& REDIS_SLAVE
) return; 
2925     redisLog(REDIS_NOTICE
,"Slave ask for syncronization"); 
2926     if (flushClientOutput(c
) == REDIS_ERR 
|| saveDb(server
.dbfilename
) != REDIS_OK
) 
2929     fd 
= open(server
.dbfilename
, O_RDONLY
); 
2930     if (fd 
== -1 || fstat(fd
,&sb
) == -1) goto closeconn
; 
2933     snprintf(sizebuf
,32,"%d\r\n",len
); 
2934     if (syncWrite(c
->fd
,sizebuf
,strlen(sizebuf
),5) == -1) goto closeconn
; 
2939         if (time(NULL
)-start 
> REDIS_MAX_SYNC_TIME
) goto closeconn
; 
2940         nread 
= read(fd
,buf
,1024); 
2941         if (nread 
== -1) goto closeconn
; 
2943         if (syncWrite(c
->fd
,buf
,nread
,5) == -1) goto closeconn
; 
2945     if (syncWrite(c
->fd
,"\r\n",2,5) == -1) goto closeconn
; 
2947     c
->flags 
|= REDIS_SLAVE
; 
2949     if (!listAddNodeTail(server
.slaves
,c
)) oom("listAddNodeTail"); 
2950     redisLog(REDIS_NOTICE
,"Syncronization with slave succeeded"); 
2954     if (fd 
!= -1) close(fd
); 
2955     c
->flags 
|= REDIS_CLOSE
; 
2956     redisLog(REDIS_WARNING
,"Syncronization with slave failed"); 
2960 static int syncWithMaster(void) { 
2961     char buf
[1024], tmpfile
[256]; 
2963     int fd 
= anetTcpConnect(NULL
,server
.masterhost
,server
.masterport
); 
2967         redisLog(REDIS_WARNING
,"Unable to connect to MASTER: %s", 
2971     /* Issue the SYNC command */ 
2972     if (syncWrite(fd
,"SYNC \r\n",7,5) == -1) { 
2974         redisLog(REDIS_WARNING
,"I/O error writing to MASTER: %s", 
2978     /* Read the bulk write count */ 
2979     if (syncReadLine(fd
,buf
,1024,5) == -1) { 
2981         redisLog(REDIS_WARNING
,"I/O error reading bulk count from MASTER: %s", 
2985     dumpsize 
= atoi(buf
); 
2986     redisLog(REDIS_NOTICE
,"Receiving %d bytes data dump from MASTER",dumpsize
); 
2987     /* Read the bulk write data on a temp file */ 
2988     snprintf(tmpfile
,256,"temp-%d.%ld.rdb",(int)time(NULL
),(long int)random()); 
2989     dfd 
= open(tmpfile
,O_CREAT
|O_WRONLY
,0644); 
2992         redisLog(REDIS_WARNING
,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno
)); 
2996         int nread
, nwritten
; 
2998         nread 
= read(fd
,buf
,(dumpsize 
< 1024)?dumpsize
:1024); 
3000             redisLog(REDIS_WARNING
,"I/O error trying to sync with MASTER: %s", 
3006         nwritten 
= write(dfd
,buf
,nread
); 
3007         if (nwritten 
== -1) { 
3008             redisLog(REDIS_WARNING
,"Write error writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno
)); 
3016     if (rename(tmpfile
,server
.dbfilename
) == -1) { 
3017         redisLog(REDIS_WARNING
,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno
)); 
3023     if (loadDb(server
.dbfilename
) != REDIS_OK
) { 
3024         redisLog(REDIS_WARNING
,"Failed trying to load the MASTER synchronization DB from disk"); 
3028     server
.master 
= createClient(fd
); 
3029     server
.master
->flags 
|= REDIS_MASTER
; 
3030     server
.replstate 
= REDIS_REPL_CONNECTED
; 
3034 static void monitorCommand(redisClient 
*c
) { 
3035     /* ignore MONITOR if aleady slave or in monitor mode */ 
3036     if (c
->flags 
& REDIS_SLAVE
) return; 
3038     c
->flags 
|= (REDIS_SLAVE
|REDIS_MONITOR
); 
3040     if (!listAddNodeTail(server
.monitors
,c
)) oom("listAddNodeTail"); 
3041     addReply(c
,shared
.ok
); 
3044 /* =================================== Main! ================================ */ 
3046 static void daemonize(void) { 
3050     if (fork() != 0) exit(0); /* parent exits */ 
3051     setsid(); /* create a new session */ 
3053     /* Every output goes to /dev/null. If Redis is daemonized but 
3054      * the 'logfile' is set to 'stdout' in the configuration file 
3055      * it will not log at all. */ 
3056     if ((fd 
= open("/dev/null", O_RDWR
, 0)) != -1) { 
3057         dup2(fd
, STDIN_FILENO
); 
3058         dup2(fd
, STDOUT_FILENO
); 
3059         dup2(fd
, STDERR_FILENO
); 
3060         if (fd 
> STDERR_FILENO
) close(fd
); 
3062     /* Try to write the pid file */ 
3063     fp 
= fopen(server
.pidfile
,"w"); 
3065         fprintf(fp
,"%d\n",getpid()); 
3070 int main(int argc
, char **argv
) { 
3073         ResetServerSaveParams(); 
3074         loadServerConfig(argv
[1]); 
3075     } else if (argc 
> 2) { 
3076         fprintf(stderr
,"Usage: ./redis-server [/path/to/redis.conf]\n"); 
3080     if (server
.daemonize
) daemonize(); 
3081     redisLog(REDIS_NOTICE
,"Server started, Redis version " REDIS_VERSION
); 
3082     if (loadDb(server
.dbfilename
) == REDIS_OK
) 
3083         redisLog(REDIS_NOTICE
,"DB loaded from disk"); 
3084     if (aeCreateFileEvent(server
.el
, server
.fd
, AE_READABLE
, 
3085         acceptHandler
, NULL
, NULL
) == AE_ERR
) oom("creating file event"); 
3086     redisLog(REDIS_NOTICE
,"The server is now ready to accept connections on port %d", server
.port
); 
3088     aeDeleteEventLoop(server
.el
);