X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/3a32897856ec77c77be5dd8e69623dd3624035fc..5117c20ab5558e5d68b1a3c7751610cd6c4279db:/src/redis.c diff --git a/src/redis.c b/src/redis.c index fa0603cb..f2c5e2c7 100644 --- a/src/redis.c +++ b/src/redis.c @@ -106,6 +106,10 @@ struct redisCommand *commandTable; * results. For instance SPOP and RANDOMKEY are two random commands. * S: Sort command output array if called from script, so that the output * is deterministic. + * l: Allow command while loading the database. + * t: Allow command while a slave has stale data but is not allowed to + * server this data. Normally no command is accepted in this condition + * but just a few. */ struct redisCommand redisCommandTable[] = { {"get",getCommand,2,"r",0,NULL,1,1,1,0,0}, @@ -219,19 +223,19 @@ struct redisCommand redisCommandTable[] = { {"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,"wmS",0,NULL,1,1,1,0,0}, - {"info",infoCommand,-1,"r",0,NULL,0,0,0,0,0}, + {"info",infoCommand,-1,"rlt",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}, {"pttl",pttlCommand,2,"r",0,NULL,1,1,1,0,0}, {"persist",persistCommand,2,"w",0,NULL,1,1,1,0,0}, - {"slaveof",slaveofCommand,3,"as",0,NULL,0,0,0,0,0}, + {"slaveof",slaveofCommand,3,"ast",0,NULL,0,0,0,0,0}, {"debug",debugCommand,-2,"as",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,"pf",0,NULL,0,0,0,0,0}, + {"subscribe",subscribeCommand,-2,"rpslt",0,NULL,0,0,0,0,0}, + {"unsubscribe",unsubscribeCommand,-1,"rpslt",0,NULL,0,0,0,0,0}, + {"psubscribe",psubscribeCommand,-2,"rpslt",0,NULL,0,0,0,0,0}, + {"punsubscribe",punsubscribeCommand,-1,"rpslt",0,NULL,0,0,0,0,0}, + {"publish",publishCommand,3,"pflt",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}, @@ -817,13 +821,8 @@ void clientsCron(void) { * a macro is used: run_with_period(milliseconds) { .... } */ -/* Using the following macro you can run code inside serverCron() with the - * specified period, specified in milliseconds. - * The actual resolution depends on REDIS_HZ. */ -#define run_with_period(_ms_) if (!(loops % ((_ms_)/(1000/REDIS_HZ)))) - int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { - int j, loops = server.cronloops; + int j; REDIS_NOTUSED(eventLoop); REDIS_NOTUSED(id); REDIS_NOTUSED(clientData); @@ -892,11 +891,14 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { } /* Show information about connected clients */ - run_with_period(5000) { - redisLog(REDIS_VERBOSE,"%d clients connected (%d slaves), %zu bytes in use", - listLength(server.clients)-listLength(server.slaves), - listLength(server.slaves), - zmalloc_used_memory()); + if (!server.sentinel_mode) { + run_with_period(5000) { + redisLog(REDIS_VERBOSE, + "%d clients connected (%d slaves), %zu bytes in use", + listLength(server.clients)-listLength(server.slaves), + listLength(server.slaves), + zmalloc_used_memory()); + } } /* We need to do a few operations on clients asynchronously. */ @@ -981,6 +983,11 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { if (server.cluster_enabled) clusterCron(); } + /* Run the sentinel timer if we are in sentinel mode. */ + run_with_period(100) { + if (server.sentinel_mode) sentinelTimer(); + } + server.cronloops++; return 1000/REDIS_HZ; } @@ -1114,6 +1121,7 @@ void initServerConfig() { server.aof_last_fsync = time(NULL); server.aof_rewrite_time_last = -1; server.aof_rewrite_time_start = -1; + server.aof_lastbgrewrite_status = REDIS_OK; server.aof_delayed_fsync = 0; server.aof_fd = -1; server.aof_selected_db = -1; /* Make sure the first time will not match */ @@ -1381,6 +1389,8 @@ void populateCommandTable(void) { case 's': c->flags |= REDIS_CMD_NOSCRIPT; break; case 'R': c->flags |= REDIS_CMD_RANDOM; break; case 'S': c->flags |= REDIS_CMD_SORT_FOR_SCRIPT; break; + case 'l': c->flags |= REDIS_CMD_LOADING; break; + case 't': c->flags |= REDIS_CMD_STALE; break; default: redisPanic("Unsupported command flag"); break; } f++; @@ -1622,7 +1632,7 @@ int processCommand(redisClient *c) { return REDIS_OK; } - /* Don't accept wirte commands if this is a read only slave. But + /* Don't accept write commands if this is a read only slave. But * accept write commands if this is our master. */ if (server.masterhost && server.repl_slave_ro && !(c->flags & REDIS_MASTER) && @@ -1647,19 +1657,20 @@ int processCommand(redisClient *c) { * we are a slave with a broken link with master. */ if (server.masterhost && server.repl_state != REDIS_REPL_CONNECTED && server.repl_serve_stale_data == 0 && - c->cmd->proc != infoCommand && c->cmd->proc != slaveofCommand) + !(c->cmd->flags & REDIS_CMD_STALE)) { addReply(c, shared.masterdownerr); return REDIS_OK; } - /* Loading DB? Return an error if the command is not INFO */ - if (server.loading && c->cmd->proc != infoCommand) { + /* Loading DB? Return an error if the command has not the + * REDIS_CMD_LOADING flag. */ + if (server.loading && !(c->cmd->flags & REDIS_CMD_LOADING)) { addReply(c, shared.loadingerr); return REDIS_OK; } - /* Lua script too slow? Only allow SHUTDOWN NOSAVE and SCRIPT KILL. */ + /* Lua script too slow? Only allow commands with REDIS_CMD_STALE flag. */ if (server.lua_timedout && !(c->cmd->proc == shutdownCommand && c->argc == 2 && @@ -1957,12 +1968,13 @@ sds genRedisInfoString(char *section) { "aof_rewrite_in_progress:%d\r\n" "aof_rewrite_scheduled:%d\r\n" "aof_last_rewrite_time_sec:%ld\r\n" - "aof_current_rewrite_time_sec:%ld\r\n", + "aof_current_rewrite_time_sec:%ld\r\n" + "aof_last_bgrewrite_status:%s\r\n", server.loading, server.dirty, server.rdb_child_pid != -1, server.lastsave, - server.lastbgsave_status == REDIS_OK ? "ok" : "err", + (server.lastbgsave_status == REDIS_OK) ? "ok" : "err", server.rdb_save_time_last, (server.rdb_child_pid == -1) ? -1 : time(NULL)-server.rdb_save_time_start, @@ -1971,7 +1983,8 @@ sds genRedisInfoString(char *section) { server.aof_rewrite_scheduled, server.aof_rewrite_time_last, (server.aof_child_pid == -1) ? - -1 : time(NULL)-server.aof_rewrite_time_start); + -1 : time(NULL)-server.aof_rewrite_time_start, + (server.aof_lastbgrewrite_status == REDIS_OK) ? "ok" : "err"); if (server.aof_state != REDIS_AOF_OFF) { info = sdscatprintf(info, @@ -2437,21 +2450,26 @@ void usage() { fprintf(stderr," ./redis-server /etc/redis/6379.conf\n"); fprintf(stderr," ./redis-server --port 7777\n"); fprintf(stderr," ./redis-server --port 7777 --slaveof 127.0.0.1 8888\n"); - fprintf(stderr," ./redis-server /etc/myredis.conf --loglevel verbose\n"); + fprintf(stderr," ./redis-server /etc/myredis.conf --loglevel verbose\n\n"); + fprintf(stderr,"Sentinel mode:\n"); + fprintf(stderr," ./redis-server /etc/sentinel.conf --sentinel\n"); exit(1); } void redisAsciiArt(void) { #include "asciilogo.h" char *buf = zmalloc(1024*16); + char *mode = "stand alone"; + + if (server.cluster_enabled) mode = "cluster"; + else if (server.sentinel_mode) mode = "sentinel"; snprintf(buf,1024*16,ascii_logo, REDIS_VERSION, redisGitSHA1(), strtol(redisGitDirty(),NULL,10) > 0, (sizeof(long) == 8) ? "64" : "32", - server.cluster_enabled ? "cluster" : "stand alone", - server.port, + mode, server.port, (long) getpid() ); redisLogRaw(REDIS_NOTICE|REDIS_LOG_RAW,buf); @@ -2489,8 +2507,35 @@ void setupSignalHandlers(void) { void memtest(size_t megabytes, int passes); +/* Returns 1 if there is --sentinel among the arguments or if + * argv[0] is exactly "redis-sentinel". */ +int checkForSentinelMode(int argc, char **argv) { + int j; + + if (strstr(argv[0],"redis-sentinel") != NULL) return 1; + for (j = 1; j < argc; j++) + if (!strcmp(argv[j],"--sentinel")) return 1; + return 0; +} + +/* Function called at startup to load RDB or AOF file in memory. */ +void loadDataFromDisk(void) { + long long start = ustime(); + if (server.aof_state == REDIS_AOF_ON) { + if (loadAppendOnlyFile(server.aof_filename) == REDIS_OK) + redisLog(REDIS_NOTICE,"DB loaded from append only file: %.3f seconds",(float)(ustime()-start)/1000000); + } else { + if (rdbLoad(server.rdb_filename) == REDIS_OK) { + redisLog(REDIS_NOTICE,"DB loaded from disk: %.3f seconds", + (float)(ustime()-start)/1000000); + } else if (errno != ENOENT) { + redisLog(REDIS_WARNING,"Fatal error loading the DB. Exiting."); + exit(1); + } + } +} + int main(int argc, char **argv) { - long long start; struct timeval tv; /* We need to initialize our libraries, and the server configuration. */ @@ -2498,8 +2543,17 @@ int main(int argc, char **argv) { srand(time(NULL)^getpid()); gettimeofday(&tv,NULL); dictSetHashFunctionSeed(tv.tv_sec^tv.tv_usec^getpid()); + server.sentinel_mode = checkForSentinelMode(argc,argv); initServerConfig(); + /* We need to init sentinel right now as parsing the configuration file + * in sentinel mode will have the effect of populating the sentinel + * data structures with master nodes to monitor. */ + if (server.sentinel_mode) { + initSentinelConfig(); + initSentinel(); + } + if (argc >= 2) { int j = 1; /* First option to parse in argv[] */ sds options = sdsempty(); @@ -2545,33 +2599,26 @@ int main(int argc, char **argv) { loadServerConfig(configfile,options); sdsfree(options); } else { - redisLog(REDIS_WARNING,"Warning: no config file specified, using the default config. In order to specify a config file use 'redis-server /path/to/redis.conf'"); + redisLog(REDIS_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/%s.conf", argv[0], server.sentinel_mode ? "sentinel" : "redis"); } if (server.daemonize) daemonize(); initServer(); if (server.daemonize) createPidFile(); redisAsciiArt(); - redisLog(REDIS_WARNING,"Server started, Redis version " REDIS_VERSION); -#ifdef __linux__ - linuxOvercommitMemoryWarning(); -#endif - start = ustime(); - if (server.aof_state == REDIS_AOF_ON) { - if (loadAppendOnlyFile(server.aof_filename) == REDIS_OK) - redisLog(REDIS_NOTICE,"DB loaded from append only file: %.3f seconds",(float)(ustime()-start)/1000000); - } else { - if (rdbLoad(server.rdb_filename) == REDIS_OK) { - redisLog(REDIS_NOTICE,"DB loaded from disk: %.3f seconds", - (float)(ustime()-start)/1000000); - } else if (errno != ENOENT) { - redisLog(REDIS_WARNING,"Fatal error loading the DB. Exiting."); - exit(1); - } + + if (!server.sentinel_mode) { + /* Things only needed when not runnign in Sentinel mode. */ + redisLog(REDIS_WARNING,"Server started, Redis version " REDIS_VERSION); + #ifdef __linux__ + linuxOvercommitMemoryWarning(); + #endif + loadDataFromDisk(); + if (server.ipfd > 0) + redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port); + if (server.sofd > 0) + redisLog(REDIS_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket); } - if (server.ipfd > 0) - redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port); - if (server.sofd > 0) - redisLog(REDIS_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket); + aeSetBeforeSleepProc(server.el,beforeSleep); aeMain(server.el); aeDeleteEventLoop(server.el);