diff options
Diffstat (limited to 'src/server.c')
-rw-r--r-- | src/server.c | 348 |
1 files changed, 227 insertions, 121 deletions
diff --git a/src/server.c b/src/server.c index 4784431ba..993260619 100644 --- a/src/server.c +++ b/src/server.c @@ -901,7 +901,7 @@ struct redisCommand redisCommandTable[] = { 0,NULL,0,0,0,0,0,0}, {"hello",helloCommand,-1, - "no-auth no-script fast no-monitor ok-loading ok-stale no-slowlog @connection", + "no-auth no-script fast no-monitor ok-loading ok-stale @connection", 0,NULL,0,0,0,0,0,0}, /* EVAL can modify the dataset, however it is not flagged as a write @@ -1091,7 +1091,7 @@ struct redisCommand redisCommandTable[] = { 0,NULL,0,0,0,0,0,0}, {"acl",aclCommand,-2, - "admin no-script no-slowlog ok-loading ok-stale", + "admin no-script ok-loading ok-stale", 0,NULL,0,0,0,0,0,0}, {"stralgo",stralgoCommand,-2, @@ -1161,12 +1161,10 @@ void serverLogRaw(int level, const char *msg) { /* Like serverLogRaw() but with printf-alike support. This is the function that * is used across the code. The raw version is only used in order to dump * the INFO output on crash. */ -void serverLog(int level, const char *fmt, ...) { +void _serverLog(int level, const char *fmt, ...) { va_list ap; char msg[LOG_MAX_LEN]; - if ((level&0xff) < server.verbosity) return; - va_start(ap, fmt); vsnprintf(msg, sizeof(msg), fmt, ap); va_end(ap); @@ -1332,21 +1330,14 @@ uint64_t dictEncObjHash(const void *key) { if (sdsEncodedObject(o)) { return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr)); - } else { - if (o->encoding == OBJ_ENCODING_INT) { - char buf[32]; - int len; + } else if (o->encoding == OBJ_ENCODING_INT) { + char buf[32]; + int len; - len = ll2string(buf,32,(long)o->ptr); - return dictGenHashFunction((unsigned char*)buf, len); - } else { - uint64_t hash; - - o = getDecodedObject(o); - hash = dictGenHashFunction(o->ptr, sdslen((sds)o->ptr)); - decrRefCount(o); - return hash; - } + len = ll2string(buf,32,(long)o->ptr); + return dictGenHashFunction((unsigned char*)buf, len); + } else { + serverPanic("Unknown string encoding"); } } @@ -1621,6 +1612,7 @@ void resetChildState() { server.child_type = CHILD_TYPE_NONE; server.child_pid = -1; server.stat_current_cow_bytes = 0; + server.stat_current_cow_updated = 0; server.stat_current_save_keys_processed = 0; server.stat_module_progress = 0; server.stat_current_save_keys_total = 0; @@ -1729,33 +1721,17 @@ int clientsCronResizeQueryBuffer(client *c) { * When we want to know what was recently the peak memory usage, we just scan * such few slots searching for the maximum value. */ #define CLIENTS_PEAK_MEM_USAGE_SLOTS 8 -size_t ClientsPeakMemInput[CLIENTS_PEAK_MEM_USAGE_SLOTS]; -size_t ClientsPeakMemOutput[CLIENTS_PEAK_MEM_USAGE_SLOTS]; +size_t ClientsPeakMemInput[CLIENTS_PEAK_MEM_USAGE_SLOTS] = {0}; +size_t ClientsPeakMemOutput[CLIENTS_PEAK_MEM_USAGE_SLOTS] = {0}; -int clientsCronTrackExpansiveClients(client *c) { +int clientsCronTrackExpansiveClients(client *c, int time_idx) { size_t in_usage = sdsZmallocSize(c->querybuf) + c->argv_len_sum + (c->argv ? zmalloc_size(c->argv) : 0); size_t out_usage = getClientOutputBufferMemoryUsage(c); - int i = server.unixtime % CLIENTS_PEAK_MEM_USAGE_SLOTS; - int zeroidx = (i+1) % CLIENTS_PEAK_MEM_USAGE_SLOTS; - - /* Always zero the next sample, so that when we switch to that second, we'll - * only register samples that are greater in that second without considering - * the history of such slot. - * - * Note: our index may jump to any random position if serverCron() is not - * called for some reason with the normal frequency, for instance because - * some slow command is called taking multiple seconds to execute. In that - * case our array may end containing data which is potentially older - * than CLIENTS_PEAK_MEM_USAGE_SLOTS seconds: however this is not a problem - * since here we want just to track if "recently" there were very expansive - * clients from the POV of memory usage. */ - ClientsPeakMemInput[zeroidx] = 0; - ClientsPeakMemOutput[zeroidx] = 0; /* Track the biggest values observed so far in this slot. */ - if (in_usage > ClientsPeakMemInput[i]) ClientsPeakMemInput[i] = in_usage; - if (out_usage > ClientsPeakMemOutput[i]) ClientsPeakMemOutput[i] = out_usage; + if (in_usage > ClientsPeakMemInput[time_idx]) ClientsPeakMemInput[time_idx] = in_usage; + if (out_usage > ClientsPeakMemOutput[time_idx]) ClientsPeakMemOutput[time_idx] = out_usage; return 0; /* This function never terminates the client. */ } @@ -1828,6 +1804,24 @@ void clientsCron(void) { iterations = (numclients < CLIENTS_CRON_MIN_ITERATIONS) ? numclients : CLIENTS_CRON_MIN_ITERATIONS; + + int curr_peak_mem_usage_slot = server.unixtime % CLIENTS_PEAK_MEM_USAGE_SLOTS; + /* Always zero the next sample, so that when we switch to that second, we'll + * only register samples that are greater in that second without considering + * the history of such slot. + * + * Note: our index may jump to any random position if serverCron() is not + * called for some reason with the normal frequency, for instance because + * some slow command is called taking multiple seconds to execute. In that + * case our array may end containing data which is potentially older + * than CLIENTS_PEAK_MEM_USAGE_SLOTS seconds: however this is not a problem + * since here we want just to track if "recently" there were very expansive + * clients from the POV of memory usage. */ + int zeroidx = (curr_peak_mem_usage_slot+1) % CLIENTS_PEAK_MEM_USAGE_SLOTS; + ClientsPeakMemInput[zeroidx] = 0; + ClientsPeakMemOutput[zeroidx] = 0; + + while(listLength(server.clients) && iterations--) { client *c; listNode *head; @@ -1843,7 +1837,7 @@ void clientsCron(void) { * terminated. */ if (clientsCronHandleTimeout(c,now)) continue; if (clientsCronResizeQueryBuffer(c)) continue; - if (clientsCronTrackExpansiveClients(c)) continue; + if (clientsCronTrackExpansiveClients(c, curr_peak_mem_usage_slot)) continue; if (clientsCronTrackClientsMemUsage(c)) continue; } } @@ -1934,11 +1928,11 @@ void updateCachedTime(int update_daylight_info) { } void checkChildrenDone(void) { - int statloc; + int statloc = 0; pid_t pid; - if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) { - int exitcode = WEXITSTATUS(statloc); + if ((pid = waitpid(-1, &statloc, WNOHANG)) != 0) { + int exitcode = WIFEXITED(statloc) ? WEXITSTATUS(statloc) : -1; int bysignal = 0; if (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc); @@ -1946,15 +1940,14 @@ void checkChildrenDone(void) { /* sigKillChildHandler catches the signal and calls exit(), but we * must make sure not to flag lastbgsave_status, etc incorrectly. * We could directly terminate the child process via SIGUSR1 - * without handling it, but in this case Valgrind will log an - * annoying error. */ + * without handling it */ if (exitcode == SERVER_CHILD_NOERROR_RETVAL) { bysignal = SIGUSR1; exitcode = 1; } if (pid == -1) { - serverLog(LL_WARNING,"wait3() returned an error: %s. " + serverLog(LL_WARNING,"waitpid() returned an error: %s. " "child_type: %s, child_pid = %d", strerror(errno), strChildType(server.child_type), @@ -2662,6 +2655,7 @@ void initServerConfig(void) { server.aof_rewrite_scheduled = 0; server.aof_flush_sleep = 0; server.aof_last_fsync = time(NULL); + atomicSet(server.aof_bio_fsync_status,C_OK); server.aof_rewrite_time_last = -1; server.aof_rewrite_time_start = -1; server.aof_lastbgrewrite_status = C_OK; @@ -3058,14 +3052,15 @@ int listenToPort(int port, socketFds *sfd) { sfd->fd[sfd->count] = anetTcpServer(server.neterr,port,addr,server.tcp_backlog); } if (sfd->fd[sfd->count] == ANET_ERR) { + int net_errno = errno; serverLog(LL_WARNING, - "Could not create server TCP listening socket %s:%d: %s", + "Warning: Could not create server TCP listening socket %s:%d: %s", addr, port, server.neterr); - if (errno == EADDRNOTAVAIL && optional) + if (net_errno == EADDRNOTAVAIL && optional) continue; - if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || - errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || - errno == EAFNOSUPPORT) + if (net_errno == ENOPROTOOPT || net_errno == EPROTONOSUPPORT || + net_errno == ESOCKTNOSUPPORT || net_errno == EPFNOSUPPORT || + net_errno == EAFNOSUPPORT) continue; /* Rollback successful listens before exiting */ @@ -3163,6 +3158,7 @@ void initServer(void) { server.clients_pending_write = listCreate(); server.clients_pending_read = listCreate(); server.clients_timeout_table = raxNew(); + server.replication_allowed = 1; server.slaveseldb = -1; /* Force to emit the first SELECT command. */ server.unblocked_clients = listCreate(); server.ready_keys = listCreate(); @@ -3196,11 +3192,15 @@ void initServer(void) { /* Open the TCP listening socket for the user commands. */ if (server.port != 0 && - listenToPort(server.port,&server.ipfd) == C_ERR) + listenToPort(server.port,&server.ipfd) == C_ERR) { + serverLog(LL_WARNING, "Failed listening on port %u (TCP), aborting.", server.port); exit(1); + } if (server.tls_port != 0 && - listenToPort(server.tls_port,&server.tlsfd) == C_ERR) + listenToPort(server.tls_port,&server.tlsfd) == C_ERR) { + serverLog(LL_WARNING, "Failed listening on port %u (TLS), aborting.", server.tls_port); exit(1); + } /* Open the listening Unix domain socket. */ if (server.unixsocket != NULL) { @@ -3266,6 +3266,7 @@ void initServer(void) { server.stat_starttime = time(NULL); server.stat_peak_memory = 0; server.stat_current_cow_bytes = 0; + server.stat_current_cow_updated = 0; server.stat_current_save_keys_processed = 0; server.stat_current_save_keys_total = 0; server.stat_rdb_cow_bytes = 0; @@ -3507,6 +3508,7 @@ void redisOpArrayFree(redisOpArray *oa) { zfree(op->argv); } zfree(oa->ops); + oa->ops = NULL; } /* ====================== Commands lookup and execution ===================== */ @@ -3557,6 +3559,9 @@ struct redisCommand *lookupCommandOrOriginal(sds name) { void propagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, int flags) { + if (!server.replication_allowed) + return; + /* Propagate a MULTI request once we encounter the first command which * is a write command. * This way we'll deliver the MULTI/..../EXEC block as a whole and @@ -3619,6 +3624,12 @@ void preventCommandPropagation(client *c) { c->flags |= CLIENT_PREVENT_PROP; } +/* Avoid logging any information about this client's arguments + * since they contain sensitive information. */ +void preventCommandLogging(client *c) { + c->flags |= CLIENT_PREVENT_LOGGING; +} + /* AOF specific version of preventCommandPropagation(). */ void preventCommandAOF(client *c) { c->flags |= CLIENT_PREVENT_AOF_PROP; @@ -3629,6 +3640,19 @@ void preventCommandReplication(client *c) { c->flags |= CLIENT_PREVENT_REPL_PROP; } +/* Log the last command a client executed into the slowlog. */ +void slowlogPushCurrentCommand(client *c, struct redisCommand *cmd, ustime_t duration) { + /* Some commands may contain sensitive data that should not be available in the slowlog. */ + if ((c->flags & CLIENT_PREVENT_LOGGING) || (cmd->flags & CMD_SKIP_SLOWLOG)) + return; + + /* If command argument vector was rewritten, use the original + * arguments. */ + robj **argv = c->original_argv ? c->original_argv : c->argv; + int argc = c->original_argv ? c->original_argc : c->argc; + slowlogPushEntryIfNeeded(c,argv,argc,duration); +} + /* Call() is the core of Redis execution of a command. * * The following flags can be passed: @@ -3731,27 +3755,31 @@ void call(client *c, int flags) { server.lua_caller->flags |= CLIENT_FORCE_AOF; } - /* Log the command into the Slow log if needed, and populate the - * per-command statistics that we show in INFO commandstats. */ - if (flags & CMD_CALL_SLOWLOG && !(c->cmd->flags & CMD_SKIP_SLOWLOG)) { - char *latency_event = (c->cmd->flags & CMD_FAST) ? - "fast-command" : "command"; + /* Note: the code below uses the real command that was executed + * c->cmd and c->lastcmd may be different, in case of MULTI-EXEC or + * re-written commands such as EXPIRE, GEOADD, etc. */ + + /* Record the latency this command induced on the main thread. + * unless instructed by the caller not to log. (happens when processing + * a MULTI-EXEC from inside an AOF). */ + if (flags & CMD_CALL_SLOWLOG) { + char *latency_event = (real_cmd->flags & CMD_FAST) ? + "fast-command" : "command"; latencyAddSampleIfNeeded(latency_event,duration/1000); - /* If command argument vector was rewritten, use the original - * arguments. */ - robj **argv = c->original_argv ? c->original_argv : c->argv; - int argc = c->original_argv ? c->original_argc : c->argc; - /* If the client is blocked we will handle slowlog when it is unblocked . */ - if (!(c->flags & CLIENT_BLOCKED)) { - slowlogPushEntryIfNeeded(c,argv,argc,duration); - } } - freeClientOriginalArgv(c); + /* Log the command into the Slow log if needed. + * If the client is blocked we will handle slowlog when it is unblocked. */ + if ((flags & CMD_CALL_SLOWLOG) && !(c->flags & CLIENT_BLOCKED)) + slowlogPushCurrentCommand(c, real_cmd, duration); + + /* Clear the original argv. + * If the client is blocked we will handle slowlog when it is unblocked. */ + if (!(c->flags & CLIENT_BLOCKED)) + freeClientOriginalArgv(c); + + /* populate the per-command statistics that we show in INFO commandstats. */ if (flags & CMD_CALL_STATS) { - /* use the real command that was executed (cmd and lastamc) may be - * different, in case of MULTI-EXEC or re-written commands such as - * EXPIRE, GEOADD, etc. */ real_cmd->microseconds += duration; real_cmd->calls++; } @@ -3916,6 +3944,16 @@ static int cmdHasMovableKeys(struct redisCommand *cmd) { * other operations can be performed by the caller. Otherwise * if C_ERR is returned the client was destroyed (i.e. after QUIT). */ int processCommand(client *c) { + if (!server.lua_timedout) { + /* Both EXEC and EVAL call call() directly so there should be + * no way in_exec or in_eval or propagate_in_transaction is 1. + * That is unless lua_timedout, in which case client may run + * some commands. */ + serverAssert(!server.propagate_in_transaction); + serverAssert(!server.in_exec); + serverAssert(!server.in_eval); + } + moduleCallCommandFilters(c); /* The QUIT command is handled separately. Normal command procs will @@ -3974,18 +4012,30 @@ int processCommand(client *c) { /* Check if the user can run this command according to the current * ACLs. */ - int acl_keypos; - int acl_retval = ACLCheckCommandPerm(c,&acl_keypos); + int acl_errpos; + int acl_retval = ACLCheckAllPerm(c,&acl_errpos); if (acl_retval != ACL_OK) { - addACLLogEntry(c,acl_retval,acl_keypos,NULL); - if (acl_retval == ACL_DENIED_CMD) + addACLLogEntry(c,acl_retval,acl_errpos,NULL); + switch (acl_retval) { + case ACL_DENIED_CMD: rejectCommandFormat(c, "-NOPERM this user has no permissions to run " "the '%s' command or its subcommand", c->cmd->name); - else + break; + case ACL_DENIED_KEY: rejectCommandFormat(c, "-NOPERM this user has no permissions to access " "one of the keys used as arguments"); + break; + case ACL_DENIED_CHANNEL: + rejectCommandFormat(c, + "-NOPERM this user has no permissions to access " + "one of the channels used as arguments"); + break; + default: + rejectCommandFormat(c, "no permission"); + break; + } return C_OK; } @@ -4144,6 +4194,7 @@ int processCommand(client *c) { c->cmd->proc != discardCommand && c->cmd->proc != watchCommand && c->cmd->proc != unwatchCommand && + c->cmd->proc != resetCommand && !(c->cmd->proc == shutdownCommand && c->argc == 2 && tolower(((char*)c->argv[1]->ptr)[0]) == 'n') && @@ -4272,7 +4323,10 @@ int prepareForShutdown(int flags) { /* Append only file: flush buffers and fsync() the AOF at exit */ serverLog(LL_NOTICE,"Calling fsync() on the AOF file."); flushAppendOnlyFile(1); - redis_fsync(server.aof_fd); + if (redis_fsync(server.aof_fd) == -1) { + serverLog(LL_WARNING,"Fail to fsync the AOF file: %s.", + strerror(errno)); + } } /* Create a new RDB file before exiting. */ @@ -4335,13 +4389,20 @@ int writeCommandsDeniedByDiskError(void) { server.lastbgsave_status == C_ERR) { return DISK_ERROR_TYPE_RDB; - } else if (server.aof_state != AOF_OFF && - server.aof_last_write_status == C_ERR) - { - return DISK_ERROR_TYPE_AOF; - } else { - return DISK_ERROR_TYPE_NONE; + } else if (server.aof_state != AOF_OFF) { + if (server.aof_last_write_status == C_ERR) { + return DISK_ERROR_TYPE_AOF; + } + /* AOF fsync error. */ + int aof_bio_fsync_status; + atomicGet(server.aof_bio_fsync_status,aof_bio_fsync_status); + if (aof_bio_fsync_status == C_ERR) { + atomicGet(server.aof_bio_fsync_errno,server.aof_last_write_errno); + return DISK_ERROR_TYPE_AOF; + } } + + return DISK_ERROR_TYPE_NONE; } /* The PING command. It works in a different way if the client is in @@ -4801,12 +4862,15 @@ sds genRedisInfoString(const char *section) { } else if (server.stat_current_save_keys_total) { fork_perc = ((double)server.stat_current_save_keys_processed / server.stat_current_save_keys_total) * 100; } - + int aof_bio_fsync_status; + atomicGet(server.aof_bio_fsync_status,aof_bio_fsync_status); + info = sdscatprintf(info, "# Persistence\r\n" "loading:%d\r\n" "current_cow_size:%zu\r\n" - "current_fork_perc:%.2f%%\r\n" + "current_cow_size_age:%lu\r\n" + "current_fork_perc:%.2f\r\n" "current_save_keys_processed:%zu\r\n" "current_save_keys_total:%zu\r\n" "rdb_changes_since_last_save:%lld\r\n" @@ -4828,6 +4892,7 @@ sds genRedisInfoString(const char *section) { "module_fork_last_cow_size:%zu\r\n", (int)server.loading, server.stat_current_cow_bytes, + server.stat_current_cow_updated ? (unsigned long) elapsedMs(server.stat_current_cow_updated) / 1000 : 0, fork_perc, server.stat_current_save_keys_processed, server.stat_current_save_keys_total, @@ -4846,7 +4911,8 @@ sds genRedisInfoString(const char *section) { (intmax_t)((server.child_type != CHILD_TYPE_AOF) ? -1 : time(NULL)-server.aof_rewrite_time_start), (server.aof_lastbgrewrite_status == C_OK) ? "ok" : "err", - (server.aof_last_write_status == C_OK) ? "ok" : "err", + (server.aof_last_write_status == C_OK && + aof_bio_fsync_status == C_OK) ? "ok" : "err", server.stat_aof_cow_bytes, server.child_type == CHILD_TYPE_MODULE, server.stat_module_cow_bytes); @@ -5054,13 +5120,16 @@ sds genRedisInfoString(const char *section) { if (server.repl_state != REPL_STATE_CONNECTED) { info = sdscatprintf(info, "master_link_down_since_seconds:%jd\r\n", - (intmax_t)(server.unixtime-server.repl_down_since)); + server.repl_down_since ? + (intmax_t)(server.unixtime-server.repl_down_since) : -1); } info = sdscatprintf(info, "slave_priority:%d\r\n" - "slave_read_only:%d\r\n", + "slave_read_only:%d\r\n" + "replica_announced:%d\r\n", server.slave_priority, - server.repl_slave_ro); + server.repl_slave_ro, + server.replica_announced); } info = sdscatprintf(info, @@ -5800,6 +5869,7 @@ int redisFork(int purpose) { server.child_pid = childpid; server.child_type = purpose; server.stat_current_cow_bytes = 0; + server.stat_current_cow_updated = 0; server.stat_current_save_keys_processed = 0; server.stat_module_progress = 0; server.stat_current_save_keys_total = dbTotalServerKeyCount(); @@ -6035,36 +6105,78 @@ int iAmMaster(void) { (server.cluster_enabled && nodeIsMaster(server.cluster->myself))); } +#ifdef REDIS_TEST +typedef int redisTestProc(int argc, char **argv, int accurate); +struct redisTest { + char *name; + redisTestProc *proc; + int failed; +} redisTests[] = { + {"ziplist", ziplistTest}, + {"quicklist", quicklistTest}, + {"intset", intsetTest}, + {"zipmap", zipmapTest}, + {"sha1test", sha1Test}, + {"util", utilTest}, + {"endianconv", endianconvTest}, + {"crc64", crc64Test}, + {"zmalloc", zmalloc_test}, + {"sds", sdsTest}, + {"dict", dictTest} +}; +redisTestProc *getTestProcByName(const char *name) { + int numtests = sizeof(redisTests)/sizeof(struct redisTest); + for (int j = 0; j < numtests; j++) { + if (!strcasecmp(name,redisTests[j].name)) { + return redisTests[j].proc; + } + } + return NULL; +} +#endif + int main(int argc, char **argv) { struct timeval tv; int j; char config_from_stdin = 0; #ifdef REDIS_TEST - if (argc == 3 && !strcasecmp(argv[1], "test")) { - if (!strcasecmp(argv[2], "ziplist")) { - return ziplistTest(argc, argv); - } else if (!strcasecmp(argv[2], "quicklist")) { - quicklistTest(argc, argv); - } else if (!strcasecmp(argv[2], "intset")) { - return intsetTest(argc, argv); - } else if (!strcasecmp(argv[2], "zipmap")) { - return zipmapTest(argc, argv); - } else if (!strcasecmp(argv[2], "sha1test")) { - return sha1Test(argc, argv); - } else if (!strcasecmp(argv[2], "util")) { - return utilTest(argc, argv); - } else if (!strcasecmp(argv[2], "endianconv")) { - return endianconvTest(argc, argv); - } else if (!strcasecmp(argv[2], "crc64")) { - return crc64Test(argc, argv); - } else if (!strcasecmp(argv[2], "zmalloc")) { - return zmalloc_test(argc, argv); - } else if (!strcasecmp(argv[2], "sds")) { - return sdsTest(argc, argv); + if (argc >= 3 && !strcasecmp(argv[1], "test")) { + int accurate = 0; + for (j = 3; j < argc; j++) { + if (!strcasecmp(argv[j], "--accurate")) { + accurate = 1; + } } - return -1; /* test not found */ + if (!strcasecmp(argv[2], "all")) { + int numtests = sizeof(redisTests)/sizeof(struct redisTest); + for (j = 0; j < numtests; j++) { + redisTests[j].failed = (redisTests[j].proc(argc,argv,accurate) != 0); + } + + /* Report tests result */ + int failed_num = 0; + for (j = 0; j < numtests; j++) { + if (redisTests[j].failed) { + failed_num++; + printf("[failed] Test - %s\n", redisTests[j].name); + } else { + printf("[ok] Test - %s\n", redisTests[j].name); + } + } + + printf("%d tests, %d passed, %d failed\n", numtests, + numtests-failed_num, failed_num); + + return failed_num == 0 ? 0 : 1; + } else { + redisTestProc *proc = getTestProcByName(argv[2]); + if (!proc) return -1; /* test not found */ + return proc(argc,argv,accurate); + } + + return 0; } #endif @@ -6150,7 +6262,6 @@ int main(int argc, char **argv) { server.exec_argv[1] = zstrdup(server.configfile); j = 2; // Skip this arg when parsing options } - while(j < argc) { /* Either first or last argument - Should we read config from stdin? */ if (argv[j][0] == '-' && argv[j][1] == '\0' && (j == 1 || j == argc-1)) { @@ -6173,16 +6284,11 @@ int main(int argc, char **argv) { j++; } - if (server.sentinel_mode && ! server.configfile) { - serverLog(LL_WARNING, - "Sentinel needs config file on disk to save state. Exiting..."); - exit(1); - } loadServerConfig(server.configfile, config_from_stdin, options); if (server.sentinel_mode) loadSentinelConfigFromQueue(); sdsfree(options); } - + if (server.sentinel_mode) sentinelCheckConfigFile(); server.supervised = redisIsSupervised(server.supervised_mode); int background = server.daemonize && !server.supervised; if (background) daemonize(); @@ -6197,7 +6303,7 @@ int main(int argc, char **argv) { (int)getpid()); if (argc == 1) { - serverLog(LL_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"); + serverLog(LL_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/redis.conf", argv[0]); } else { serverLog(LL_WARNING, "Configuration loaded"); } @@ -6251,10 +6357,10 @@ int main(int argc, char **argv) { if (server.supervised_mode == SUPERVISED_SYSTEMD) { if (!server.masterhost) { redisCommunicateSystemd("STATUS=Ready to accept connections\n"); - redisCommunicateSystemd("READY=1\n"); } else { - redisCommunicateSystemd("STATUS=Waiting for MASTER <-> REPLICA sync\n"); + redisCommunicateSystemd("STATUS=Ready to accept connections in read-only mode. Waiting for MASTER <-> REPLICA sync\n"); } + redisCommunicateSystemd("READY=1\n"); } } else { ACLLoadUsersAtStartup(); |