]> git.saurik.com Git - redis.git/blobdiff - src/redis.c
show node with myself flag always as connected in CLUSTER NODES output.
[redis.git] / src / redis.c
index 1d7501f9376edcb462a9f48a4c3a665b2152b212..94daf3488771c3e9f597b85cf0b8511c65eadee8 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "redis.h"
 #include "slowlog.h"
+#include "bio.h"
 
 #ifdef HAVE_BACKTRACE
 #include <execinfo.h>
@@ -57,7 +58,7 @@
 
 struct sharedObjectsStruct shared;
 
-/* Global vars that are actally used as constants. The following double
+/* Global vars that are actually used as constants. The following double
  * values are used for double on-disk serialization, and are initialized
  * at runtime to avoid strange compiler optimizations. */
 
@@ -68,135 +69,152 @@ double R_Zero, R_PosInf, R_NegInf, R_Nan;
 /* Global vars */
 struct redisServer server; /* server global state */
 struct redisCommand *commandTable;
+
+/* Our command table. Command flags are expressed using strings where every
+ * character represents a flag. Later the populateCommandTable() function will
+ * take care of populating the real 'flags' field using this characters.
+ *
+ * This is the meaning of the flags:
+ *
+ * w: write command (may modify the key space).
+ * r: read command  (will never modify the key space).
+ * m: may increase memory usage once called. Don't allow if out of memory.
+ * a: admin command, like SAVE or SHUTDOWN.
+ * p: Pub/Sub related command.
+ * f: force replication of this command, regarless of server.dirty.
+ * s: command not allowed in scripts.
+ * r: random command. Command is not deterministic, that is, the same command
+ *    with the same arguments, with the same key space, may have different
+ *    results. For instance SPOP and RANDOMKEY are two random commands. */
 struct redisCommand redisCommandTable[] = {
-    {"get",getCommand,2,0,NULL,1,1,1,0,0},
-    {"set",setCommand,3,REDIS_CMD_DENYOOM,noPreloadGetKeys,1,1,1,0,0},
-    {"setnx",setnxCommand,3,REDIS_CMD_DENYOOM,noPreloadGetKeys,1,1,1,0,0},
-    {"setex",setexCommand,4,REDIS_CMD_DENYOOM,noPreloadGetKeys,2,2,1,0,0},
-    {"append",appendCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"strlen",strlenCommand,2,0,NULL,1,1,1,0,0},
-    {"del",delCommand,-2,0,noPreloadGetKeys,1,-1,1,0,0},
-    {"exists",existsCommand,2,0,NULL,1,1,1,0,0},
-    {"setbit",setbitCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"getbit",getbitCommand,3,0,NULL,1,1,1,0,0},
-    {"setrange",setrangeCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"getrange",getrangeCommand,4,0,NULL,1,1,1,0,0},
-    {"substr",getrangeCommand,4,0,NULL,1,1,1,0,0},
-    {"incr",incrCommand,2,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"decr",decrCommand,2,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"mget",mgetCommand,-2,0,NULL,1,-1,1,0,0},
-    {"rpush",rpushCommand,-3,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"lpush",lpushCommand,-3,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"rpushx",rpushxCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"lpushx",lpushxCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"linsert",linsertCommand,5,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"rpop",rpopCommand,2,0,NULL,1,1,1,0,0},
-    {"lpop",lpopCommand,2,0,NULL,1,1,1,0,0},
-    {"brpop",brpopCommand,-3,0,NULL,1,1,1,0,0},
-    {"brpoplpush",brpoplpushCommand,4,REDIS_CMD_DENYOOM,NULL,1,2,1,0,0},
-    {"blpop",blpopCommand,-3,0,NULL,1,-2,1,0,0},
-    {"llen",llenCommand,2,0,NULL,1,1,1,0,0},
-    {"lindex",lindexCommand,3,0,NULL,1,1,1,0,0},
-    {"lset",lsetCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"lrange",lrangeCommand,4,0,NULL,1,1,1,0,0},
-    {"ltrim",ltrimCommand,4,0,NULL,1,1,1,0,0},
-    {"lrem",lremCommand,4,0,NULL,1,1,1,0,0},
-    {"rpoplpush",rpoplpushCommand,3,REDIS_CMD_DENYOOM,NULL,1,2,1,0,0},
-    {"sadd",saddCommand,-3,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"srem",sremCommand,-3,0,NULL,1,1,1,0,0},
-    {"smove",smoveCommand,4,0,NULL,1,2,1,0,0},
-    {"sismember",sismemberCommand,3,0,NULL,1,1,1,0,0},
-    {"scard",scardCommand,2,0,NULL,1,1,1,0,0},
-    {"spop",spopCommand,2,0,NULL,1,1,1,0,0},
-    {"srandmember",srandmemberCommand,2,0,NULL,1,1,1,0,0},
-    {"sinter",sinterCommand,-2,REDIS_CMD_DENYOOM,NULL,1,-1,1,0,0},
-    {"sinterstore",sinterstoreCommand,-3,REDIS_CMD_DENYOOM,NULL,2,-1,1,0,0},
-    {"sunion",sunionCommand,-2,REDIS_CMD_DENYOOM,NULL,1,-1,1,0,0},
-    {"sunionstore",sunionstoreCommand,-3,REDIS_CMD_DENYOOM,NULL,2,-1,1,0,0},
-    {"sdiff",sdiffCommand,-2,REDIS_CMD_DENYOOM,NULL,1,-1,1,0,0},
-    {"sdiffstore",sdiffstoreCommand,-3,REDIS_CMD_DENYOOM,NULL,2,-1,1,0,0},
-    {"smembers",sinterCommand,2,0,NULL,1,1,1,0,0},
-    {"zadd",zaddCommand,-4,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"zincrby",zincrbyCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"zrem",zremCommand,-3,0,NULL,1,1,1,0,0},
-    {"zremrangebyscore",zremrangebyscoreCommand,4,0,NULL,1,1,1,0,0},
-    {"zremrangebyrank",zremrangebyrankCommand,4,0,NULL,1,1,1,0,0},
-    {"zunionstore",zunionstoreCommand,-4,REDIS_CMD_DENYOOM,zunionInterGetKeys,0,0,0,0,0},
-    {"zinterstore",zinterstoreCommand,-4,REDIS_CMD_DENYOOM,zunionInterGetKeys,0,0,0,0,0},
-    {"zrange",zrangeCommand,-4,0,NULL,1,1,1,0,0},
-    {"zrangebyscore",zrangebyscoreCommand,-4,0,NULL,1,1,1,0,0},
-    {"zrevrangebyscore",zrevrangebyscoreCommand,-4,0,NULL,1,1,1,0,0},
-    {"zcount",zcountCommand,4,0,NULL,1,1,1,0,0},
-    {"zrevrange",zrevrangeCommand,-4,0,NULL,1,1,1,0,0},
-    {"zcard",zcardCommand,2,0,NULL,1,1,1,0,0},
-    {"zscore",zscoreCommand,3,0,NULL,1,1,1,0,0},
-    {"zrank",zrankCommand,3,0,NULL,1,1,1,0,0},
-    {"zrevrank",zrevrankCommand,3,0,NULL,1,1,1,0,0},
-    {"hset",hsetCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"hsetnx",hsetnxCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"hget",hgetCommand,3,0,NULL,1,1,1,0,0},
-    {"hmset",hmsetCommand,-4,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"hmget",hmgetCommand,-3,0,NULL,1,1,1,0,0},
-    {"hincrby",hincrbyCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"hdel",hdelCommand,-3,0,NULL,1,1,1,0,0},
-    {"hlen",hlenCommand,2,0,NULL,1,1,1,0,0},
-    {"hkeys",hkeysCommand,2,0,NULL,1,1,1,0,0},
-    {"hvals",hvalsCommand,2,0,NULL,1,1,1,0,0},
-    {"hgetall",hgetallCommand,2,0,NULL,1,1,1,0,0},
-    {"hexists",hexistsCommand,3,0,NULL,1,1,1,0,0},
-    {"incrby",incrbyCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"decrby",decrbyCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"getset",getsetCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"mset",msetCommand,-3,REDIS_CMD_DENYOOM,NULL,1,-1,2,0,0},
-    {"msetnx",msetnxCommand,-3,REDIS_CMD_DENYOOM,NULL,1,-1,2,0,0},
-    {"randomkey",randomkeyCommand,1,0,NULL,0,0,0,0,0},
-    {"select",selectCommand,2,0,NULL,0,0,0,0,0},
-    {"move",moveCommand,3,0,NULL,1,1,1,0,0},
-    {"rename",renameCommand,3,0,renameGetKeys,1,2,1,0,0},
-    {"renamenx",renamenxCommand,3,0,renameGetKeys,1,2,1,0,0},
-    {"expire",expireCommand,3,0,NULL,1,1,1,0,0},
-    {"expireat",expireatCommand,3,0,NULL,1,1,1,0,0},
-    {"keys",keysCommand,2,0,NULL,0,0,0,0,0},
-    {"dbsize",dbsizeCommand,1,0,NULL,0,0,0,0,0},
-    {"auth",authCommand,2,0,NULL,0,0,0,0,0},
-    {"ping",pingCommand,1,0,NULL,0,0,0,0,0},
-    {"echo",echoCommand,2,0,NULL,0,0,0,0,0},
-    {"save",saveCommand,1,0,NULL,0,0,0,0,0},
-    {"bgsave",bgsaveCommand,1,0,NULL,0,0,0,0,0},
-    {"bgrewriteaof",bgrewriteaofCommand,1,0,NULL,0,0,0,0,0},
-    {"shutdown",shutdownCommand,1,0,NULL,0,0,0,0,0},
-    {"lastsave",lastsaveCommand,1,0,NULL,0,0,0,0,0},
-    {"type",typeCommand,2,0,NULL,1,1,1,0,0},
-    {"multi",multiCommand,1,0,NULL,0,0,0,0,0},
-    {"exec",execCommand,1,REDIS_CMD_DENYOOM,NULL,0,0,0,0,0},
-    {"discard",discardCommand,1,0,NULL,0,0,0,0,0},
-    {"sync",syncCommand,1,0,NULL,0,0,0,0,0},
-    {"flushdb",flushdbCommand,1,0,NULL,0,0,0,0,0},
-    {"flushall",flushallCommand,1,0,NULL,0,0,0,0,0},
-    {"sort",sortCommand,-2,REDIS_CMD_DENYOOM,NULL,1,1,1,0,0},
-    {"info",infoCommand,-1,0,NULL,0,0,0,0,0},
-    {"monitor",monitorCommand,1,0,NULL,0,0,0,0,0},
-    {"ttl",ttlCommand,2,0,NULL,1,1,1,0,0},
-    {"persist",persistCommand,2,0,NULL,1,1,1,0,0},
-    {"slaveof",slaveofCommand,3,0,NULL,0,0,0,0,0},
-    {"debug",debugCommand,-2,0,NULL,0,0,0,0,0},
-    {"config",configCommand,-2,0,NULL,0,0,0,0,0},
-    {"subscribe",subscribeCommand,-2,0,NULL,0,0,0,0,0},
-    {"unsubscribe",unsubscribeCommand,-1,0,NULL,0,0,0,0,0},
-    {"psubscribe",psubscribeCommand,-2,0,NULL,0,0,0,0,0},
-    {"punsubscribe",punsubscribeCommand,-1,0,NULL,0,0,0,0,0},
-    {"publish",publishCommand,3,REDIS_CMD_FORCE_REPLICATION,NULL,0,0,0,0,0},
-    {"watch",watchCommand,-2,0,noPreloadGetKeys,1,-1,1,0,0},
-    {"unwatch",unwatchCommand,1,0,NULL,0,0,0,0,0},
-    {"cluster",clusterCommand,-2,0,NULL,0,0,0,0,0},
-    {"restore",restoreCommand,4,0,NULL,0,0,0,0,0},
-    {"migrate",migrateCommand,6,0,NULL,0,0,0,0,0},
-    {"dump",dumpCommand,2,0,NULL,0,0,0,0,0},
-    {"object",objectCommand,-2,0,NULL,0,0,0,0,0},
-    {"client",clientCommand,-2,0,NULL,0,0,0,0,0},
-    {"eval",evalCommand,-3,REDIS_CMD_DENYOOM,zunionInterGetKeys,0,0,0,0,0},
-    {"evalsha",evalShaCommand,-3,REDIS_CMD_DENYOOM,zunionInterGetKeys,0,0,0,0,0},
-    {"slowlog",slowlogCommand,-2,0,NULL,0,0,0,0,0}
+    {"get",getCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"set",setCommand,3,"wm",0,noPreloadGetKeys,1,1,1,0,0},
+    {"setnx",setnxCommand,3,"wm",0,noPreloadGetKeys,1,1,1,0,0},
+    {"setex",setexCommand,4,"wm",0,noPreloadGetKeys,2,2,1,0,0},
+    {"append",appendCommand,3,"wm",0,NULL,1,1,1,0,0},
+    {"strlen",strlenCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"del",delCommand,-2,"w",0,noPreloadGetKeys,1,-1,1,0,0},
+    {"exists",existsCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"setbit",setbitCommand,4,"wm",0,NULL,1,1,1,0,0},
+    {"getbit",getbitCommand,3,"r",0,NULL,1,1,1,0,0},
+    {"setrange",setrangeCommand,4,"wm",0,NULL,1,1,1,0,0},
+    {"getrange",getrangeCommand,4,"r",0,NULL,1,1,1,0,0},
+    {"substr",getrangeCommand,4,"r",0,NULL,1,1,1,0,0},
+    {"incr",incrCommand,2,"wm",0,NULL,1,1,1,0,0},
+    {"decr",decrCommand,2,"wm",0,NULL,1,1,1,0,0},
+    {"mget",mgetCommand,-2,"r",0,NULL,1,-1,1,0,0},
+    {"rpush",rpushCommand,-3,"wm",0,NULL,1,1,1,0,0},
+    {"lpush",lpushCommand,-3,"wm",0,NULL,1,1,1,0,0},
+    {"rpushx",rpushxCommand,3,"wm",0,NULL,1,1,1,0,0},
+    {"lpushx",lpushxCommand,3,"wm",0,NULL,1,1,1,0,0},
+    {"linsert",linsertCommand,5,"wm",0,NULL,1,1,1,0,0},
+    {"rpop",rpopCommand,2,"w",0,NULL,1,1,1,0,0},
+    {"lpop",lpopCommand,2,"w",0,NULL,1,1,1,0,0},
+    {"brpop",brpopCommand,-3,"w",0,NULL,1,1,1,0,0},
+    {"brpoplpush",brpoplpushCommand,4,"wm",0,NULL,1,2,1,0,0},
+    {"blpop",blpopCommand,-3,"w",0,NULL,1,-2,1,0,0},
+    {"llen",llenCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"lindex",lindexCommand,3,"r",0,NULL,1,1,1,0,0},
+    {"lset",lsetCommand,4,"wm",0,NULL,1,1,1,0,0},
+    {"lrange",lrangeCommand,4,"r",0,NULL,1,1,1,0,0},
+    {"ltrim",ltrimCommand,4,"w",0,NULL,1,1,1,0,0},
+    {"lrem",lremCommand,4,"w",0,NULL,1,1,1,0,0},
+    {"rpoplpush",rpoplpushCommand,3,"wm",0,NULL,1,2,1,0,0},
+    {"sadd",saddCommand,-3,"wm",0,NULL,1,1,1,0,0},
+    {"srem",sremCommand,-3,"w",0,NULL,1,1,1,0,0},
+    {"smove",smoveCommand,4,"w",0,NULL,1,2,1,0,0},
+    {"sismember",sismemberCommand,3,"r",0,NULL,1,1,1,0,0},
+    {"scard",scardCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"spop",spopCommand,2,"wRs",0,NULL,1,1,1,0,0},
+    {"srandmember",srandmemberCommand,2,"rR",0,NULL,1,1,1,0,0},
+    {"sinter",sinterCommand,-2,"r",0,NULL,1,-1,1,0,0},
+    {"sinterstore",sinterstoreCommand,-3,"wm",0,NULL,2,-1,1,0,0},
+    {"sunion",sunionCommand,-2,"r",0,NULL,1,-1,1,0,0},
+    {"sunionstore",sunionstoreCommand,-3,"wm",0,NULL,2,-1,1,0,0},
+    {"sdiff",sdiffCommand,-2,"r",0,NULL,1,-1,1,0,0},
+    {"sdiffstore",sdiffstoreCommand,-3,"wm",0,NULL,2,-1,1,0,0},
+    {"smembers",sinterCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"zadd",zaddCommand,-4,"wm",0,NULL,1,1,1,0,0},
+    {"zincrby",zincrbyCommand,4,"wm",0,NULL,1,1,1,0,0},
+    {"zrem",zremCommand,-3,"w",0,NULL,1,1,1,0,0},
+    {"zremrangebyscore",zremrangebyscoreCommand,4,"w",0,NULL,1,1,1,0,0},
+    {"zremrangebyrank",zremrangebyrankCommand,4,"w",0,NULL,1,1,1,0,0},
+    {"zunionstore",zunionstoreCommand,-4,"wm",0,zunionInterGetKeys,0,0,0,0,0},
+    {"zinterstore",zinterstoreCommand,-4,"wm",0,zunionInterGetKeys,0,0,0,0,0},
+    {"zrange",zrangeCommand,-4,"r",0,NULL,1,1,1,0,0},
+    {"zrangebyscore",zrangebyscoreCommand,-4,"r",0,NULL,1,1,1,0,0},
+    {"zrevrangebyscore",zrevrangebyscoreCommand,-4,"r",0,NULL,1,1,1,0,0},
+    {"zcount",zcountCommand,4,"r",0,NULL,1,1,1,0,0},
+    {"zrevrange",zrevrangeCommand,-4,"r",0,NULL,1,1,1,0,0},
+    {"zcard",zcardCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"zscore",zscoreCommand,3,"r",0,NULL,1,1,1,0,0},
+    {"zrank",zrankCommand,3,"r",0,NULL,1,1,1,0,0},
+    {"zrevrank",zrevrankCommand,3,"r",0,NULL,1,1,1,0,0},
+    {"hset",hsetCommand,4,"wm",0,NULL,1,1,1,0,0},
+    {"hsetnx",hsetnxCommand,4,"wm",0,NULL,1,1,1,0,0},
+    {"hget",hgetCommand,3,"r",0,NULL,1,1,1,0,0},
+    {"hmset",hmsetCommand,-4,"wm",0,NULL,1,1,1,0,0},
+    {"hmget",hmgetCommand,-3,"r",0,NULL,1,1,1,0,0},
+    {"hincrby",hincrbyCommand,4,"wm",0,NULL,1,1,1,0,0},
+    {"hdel",hdelCommand,-3,"w",0,NULL,1,1,1,0,0},
+    {"hlen",hlenCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"hkeys",hkeysCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"hvals",hvalsCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"hgetall",hgetallCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"hexists",hexistsCommand,3,"r",0,NULL,1,1,1,0,0},
+    {"incrby",incrbyCommand,3,"wm",0,NULL,1,1,1,0,0},
+    {"decrby",decrbyCommand,3,"wm",0,NULL,1,1,1,0,0},
+    {"getset",getsetCommand,3,"wm",0,NULL,1,1,1,0,0},
+    {"mset",msetCommand,-3,"wm",0,NULL,1,-1,2,0,0},
+    {"msetnx",msetnxCommand,-3,"wm",0,NULL,1,-1,2,0,0},
+    {"randomkey",randomkeyCommand,1,"rR",0,NULL,0,0,0,0,0},
+    {"select",selectCommand,2,"r",0,NULL,0,0,0,0,0},
+    {"move",moveCommand,3,"w",0,NULL,1,1,1,0,0},
+    {"rename",renameCommand,3,"w",0,renameGetKeys,1,2,1,0,0},
+    {"renamenx",renamenxCommand,3,"w",0,renameGetKeys,1,2,1,0,0},
+    {"expire",expireCommand,3,"w",0,NULL,1,1,1,0,0},
+    {"expireat",expireatCommand,3,"w",0,NULL,1,1,1,0,0},
+    {"keys",keysCommand,2,"r",0,NULL,0,0,0,0,0},
+    {"dbsize",dbsizeCommand,1,"r",0,NULL,0,0,0,0,0},
+    {"auth",authCommand,2,"r",0,NULL,0,0,0,0,0},
+    {"ping",pingCommand,1,"r",0,NULL,0,0,0,0,0},
+    {"echo",echoCommand,2,"r",0,NULL,0,0,0,0,0},
+    {"save",saveCommand,1,"ar",0,NULL,0,0,0,0,0},
+    {"bgsave",bgsaveCommand,1,"ar",0,NULL,0,0,0,0,0},
+    {"bgrewriteaof",bgrewriteaofCommand,1,"ar",0,NULL,0,0,0,0,0},
+    {"shutdown",shutdownCommand,1,"ar",0,NULL,0,0,0,0,0},
+    {"lastsave",lastsaveCommand,1,"r",0,NULL,0,0,0,0,0},
+    {"type",typeCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"multi",multiCommand,1,"rs",0,NULL,0,0,0,0,0},
+    {"exec",execCommand,1,"wms",0,NULL,0,0,0,0,0},
+    {"discard",discardCommand,1,"rs",0,NULL,0,0,0,0,0},
+    {"sync",syncCommand,1,"ars",0,NULL,0,0,0,0,0},
+    {"flushdb",flushdbCommand,1,"w",0,NULL,0,0,0,0,0},
+    {"flushall",flushallCommand,1,"w",0,NULL,0,0,0,0,0},
+    {"sort",sortCommand,-2,"wm",0,NULL,1,1,1,0,0},
+    {"info",infoCommand,-1,"r",0,NULL,0,0,0,0,0},
+    {"monitor",monitorCommand,1,"ars",0,NULL,0,0,0,0,0},
+    {"ttl",ttlCommand,2,"r",0,NULL,1,1,1,0,0},
+    {"persist",persistCommand,2,"w",0,NULL,1,1,1,0,0},
+    {"slaveof",slaveofCommand,3,"aws",0,NULL,0,0,0,0,0},
+    {"debug",debugCommand,-2,"aw",0,NULL,0,0,0,0,0},
+    {"config",configCommand,-2,"ar",0,NULL,0,0,0,0,0},
+    {"subscribe",subscribeCommand,-2,"rps",0,NULL,0,0,0,0,0},
+    {"unsubscribe",unsubscribeCommand,-1,"rps",0,NULL,0,0,0,0,0},
+    {"psubscribe",psubscribeCommand,-2,"rps",0,NULL,0,0,0,0,0},
+    {"punsubscribe",punsubscribeCommand,-1,"rps",0,NULL,0,0,0,0,0},
+    {"publish",publishCommand,3,"rpf",0,NULL,0,0,0,0,0},
+    {"watch",watchCommand,-2,"rs",0,noPreloadGetKeys,1,-1,1,0,0},
+    {"unwatch",unwatchCommand,1,"rs",0,NULL,0,0,0,0,0},
+    {"cluster",clusterCommand,-2,"ar",0,NULL,0,0,0,0,0},
+    {"restore",restoreCommand,4,"awm",0,NULL,0,0,0,0,0},
+    {"migrate",migrateCommand,6,"aw",0,NULL,0,0,0,0,0},
+    {"dump",dumpCommand,2,"ar",0,NULL,0,0,0,0,0},
+    {"object",objectCommand,-2,"r",0,NULL,0,0,0,0,0},
+    {"client",clientCommand,-2,"ar",0,NULL,0,0,0,0,0},
+    {"eval",evalCommand,-3,"wms",0,zunionInterGetKeys,0,0,0,0,0},
+    {"evalsha",evalShaCommand,-3,"wms",0,zunionInterGetKeys,0,0,0,0,0},
+    {"slowlog",slowlogCommand,-2,"r",0,NULL,0,0,0,0,0}
 };
 
 /*============================ Utility functions ============================ */
@@ -575,6 +593,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
      * in objects at every object access, and accuracy is not needed.
      * To access a global var is faster than calling time(NULL) */
     server.unixtime = time(NULL);
+
     /* We have just 22 bits per object for LRU information.
      * So we use an (eventually wrapping) LRU clock with 10 seconds resolution.
      * 2^22 bits with 10 seconds resoluton is more or less 1.5 years.
@@ -685,7 +704,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
              server.auto_aofrewrite_perc &&
              server.appendonly_current_size > server.auto_aofrewrite_min_size)
          {
-            int base = server.auto_aofrewrite_base_size ?
+            long long base = server.auto_aofrewrite_base_size ?
                             server.auto_aofrewrite_base_size : 1;
             long long growth = (server.appendonly_current_size*100/base) - 100;
             if (growth >= server.auto_aofrewrite_perc) {
@@ -695,6 +714,11 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
          }
     }
 
+
+    /* If we postponed an AOF buffer flush, let's try to do it every time the
+     * cron function is called. */
+    if (server.aof_flush_postponed_start) flushAppendOnlyFile(0);
+
     /* Expire a few keys per cycle, only if this is a master.
      * On slaves we wait for DEL operations synthesized by the master
      * in order to guarantee a strict consistency. */
@@ -733,7 +757,7 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
     }
 
     /* Write the AOF buffer on disk */
-    flushAppendOnlyFile();
+    flushAppendOnlyFile(0);
 }
 
 /* =========================== Server initialization ======================== */
@@ -820,6 +844,7 @@ void initServerConfig() {
     server.lastfsync = time(NULL);
     server.appendfd = -1;
     server.appendseldb = -1; /* Make sure the first time will not match */
+    server.aof_flush_postponed_start = 0;
     server.pidfile = zstrdup("/var/run/redis.pid");
     server.dbfilename = zstrdup("dump.rdb");
     server.appendfilename = zstrdup("appendonly.aof");
@@ -903,7 +928,8 @@ void initServer() {
     if (server.port != 0) {
         server.ipfd = anetTcpServer(server.neterr,server.port,server.bindaddr);
         if (server.ipfd == ANET_ERR) {
-            redisLog(REDIS_WARNING, "Opening port: %s", server.neterr);
+            redisLog(REDIS_WARNING, "Opening port %d: %s",
+                server.port, server.neterr);
             exit(1);
         }
     }
@@ -965,6 +991,7 @@ void initServer() {
     if (server.cluster_enabled) clusterInit();
     scriptingInit();
     slowlogInit();
+    bioInit();
     srand(time(NULL)^getpid());
 }
 
@@ -976,8 +1003,24 @@ void populateCommandTable(void) {
 
     for (j = 0; j < numcommands; j++) {
         struct redisCommand *c = redisCommandTable+j;
+        char *f = c->sflags;
         int retval;
 
+        while(*f != '\0') {
+            switch(*f) {
+            case 'w': c->flags |= REDIS_CMD_WRITE; break;
+            case 'r': c->flags |= REDIS_CMD_READONLY; break;
+            case 'm': c->flags |= REDIS_CMD_DENYOOM; break;
+            case 'a': c->flags |= REDIS_CMD_ADMIN; break;
+            case 'p': c->flags |= REDIS_CMD_PUBSUB; break;
+            case 'f': c->flags |= REDIS_CMD_FORCE_REPLICATION; break;
+            case 's': c->flags |= REDIS_CMD_NOSCRIPT; break;
+            case 'R': c->flags |= REDIS_CMD_RANDOM; break;
+            default: redisPanic("Unsupported command flag"); break;
+            }
+            f++;
+        }
+
         retval = dictAdd(server.commands, sdsnew(c->name), c);
         assert(retval == DICT_OK);
     }
@@ -1022,9 +1065,9 @@ void call(redisClient *c) {
     slowlogPushEntryIfNeeded(c->argv,c->argc,duration);
     c->cmd->calls++;
 
-    if (server.appendonly && dirty)
+    if (server.appendonly && dirty > 0)
         feedAppendOnlyFile(c->cmd,c->db->id,c->argv,c->argc);
-    if ((dirty || c->cmd->flags & REDIS_CMD_FORCE_REPLICATION) &&
+    if ((dirty > 0 || c->cmd->flags & REDIS_CMD_FORCE_REPLICATION) &&
         listLength(server.slaves))
         replicationFeedSlaves(server.slaves,c->db->id,c->argv,c->argc);
     if (listLength(server.monitors))
@@ -1152,19 +1195,29 @@ int processCommand(redisClient *c) {
 /*================================== Shutdown =============================== */
 
 int prepareForShutdown() {
-    redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
+    redisLog(REDIS_WARNING,"User requested shutdown...");
     /* Kill the saving child if there is a background saving in progress.
        We want to avoid race conditions, for instance our saving child may
        overwrite the synchronous saving did by SHUTDOWN. */
     if (server.bgsavechildpid != -1) {
-        redisLog(REDIS_WARNING,"There is a live saving child. Killing it!");
+        redisLog(REDIS_WARNING,"There is a child saving an .rdb. Killing it!");
         kill(server.bgsavechildpid,SIGKILL);
         rdbRemoveTempFile(server.bgsavechildpid);
     }
     if (server.appendonly) {
+        /* Kill the AOF saving child as the AOF we already have may be longer
+         * but contains the full dataset anyway. */
+        if (server.bgrewritechildpid != -1) {
+            redisLog(REDIS_WARNING,
+                "There is a child rewriting the AOF. Killing it!");
+            kill(server.bgrewritechildpid,SIGKILL);
+        }
         /* Append only file: fsync() the AOF and exit */
+        redisLog(REDIS_NOTICE,"Calling fsync() on the AOF file.");
         aof_fsync(server.appendfd);
-    } else if (server.saveparamslen > 0) {
+    }
+    if (server.saveparamslen > 0) {
+        redisLog(REDIS_NOTICE,"Saving the final RDB snapshot before exiting.");
         /* Snapshotting. Perform a SYNC SAVE and exit */
         if (rdbSave(server.dbfilename) != REDIS_OK) {
             /* Ooops.. error saving! The best we can do is to continue
@@ -1172,14 +1225,19 @@ int prepareForShutdown() {
              * in the next cron() Redis will be notified that the background
              * saving aborted, handling special stuff like slaves pending for
              * synchronization... */
-            redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
+            redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit.");
             return REDIS_ERR;
         }
-    } else {
-        redisLog(REDIS_WARNING,"Not saving DB.");
     }
-    if (server.daemonize) unlink(server.pidfile);
-    redisLog(REDIS_WARNING,"Server exit now, bye bye...");
+    if (server.daemonize) {
+        redisLog(REDIS_NOTICE,"Removing the pid file.");
+        unlink(server.pidfile);
+    }
+    /* Close the listening sockets. Apparently this allows faster restarts. */
+    if (server.ipfd != -1) close(server.ipfd);
+    if (server.sofd != -1) close(server.sofd);
+
+    redisLog(REDIS_WARNING,"Redis is now ready to exit, bye bye...");
     return REDIS_OK;
 }
 
@@ -1711,6 +1769,7 @@ void redisAsciiArt(void) {
 int main(int argc, char **argv) {
     long long start;
 
+    zmalloc_enable_thread_safeness();
     initServerConfig();
     if (argc == 2) {
         if (strcmp(argv[1], "-v") == 0 ||
@@ -1758,8 +1817,10 @@ static void *getMcontextEip(ucontext_t *uc) {
 #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
   #if __x86_64__
     return (void*) uc->uc_mcontext->__ss.__rip;
-  #else
+  #elif __i386__
     return (void*) uc->uc_mcontext->__ss.__eip;
+  #else
+    return (void*) uc->uc_mcontext->__ss.__srr0;
   #endif
 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
   #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)