diff options
author | Oran Agra <oran@redislabs.com> | 2023-05-15 13:08:15 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-15 13:08:15 +0300 |
commit | a51eb05b1895babb17c37c36b963e2bcbd5496d5 (patch) | |
tree | 7be24b09e0a5621a03e9f9ffe9ef27fcb44d8345 /src/server.c | |
parent | e26a769d9627ebecb8607375580970a740348956 (diff) | |
parent | 986dbf716e0cb904c80bb444635cea3242859cc1 (diff) | |
download | redis-7.2.tar.gz |
Diffstat (limited to 'src/server.c')
-rw-r--r-- | src/server.c | 310 |
1 files changed, 175 insertions, 135 deletions
diff --git a/src/server.c b/src/server.c index 4e77d2f6d..9389e707f 100644 --- a/src/server.c +++ b/src/server.c @@ -36,6 +36,7 @@ #include "atomicvar.h" #include "mt19937-64.h" #include "functions.h" +#include "hdr_histogram.h" #include "syscheck.h" #include <time.h> @@ -655,11 +656,11 @@ const char *strChildType(int type) { /* Return true if there are active children processes doing RDB saving, * AOF rewriting, or some side process spawned by a loaded module. */ -int hasActiveChildProcess() { +int hasActiveChildProcess(void) { return server.child_pid != -1; } -void resetChildState() { +void resetChildState(void) { server.child_type = CHILD_TYPE_NONE; server.child_pid = -1; server.stat_current_cow_peak = 0; @@ -681,7 +682,7 @@ int isMutuallyExclusiveChildType(int type) { } /* Returns true when we're inside a long command that yielded to the event loop. */ -int isInsideYieldingLongCommand() { +int isInsideYieldingLongCommand(void) { return scriptIsTimedout() || server.busy_module_yield_flags; } @@ -693,22 +694,24 @@ int allPersistenceDisabled(void) { /* ======================= Cron: called every 100 ms ======================== */ -/* Add a sample to the operations per second array of samples. */ -void trackInstantaneousMetric(int metric, long long current_reading) { - long long now = mstime(); - long long t = now - server.inst_metric[metric].last_sample_time; - long long ops = current_reading - - server.inst_metric[metric].last_sample_count; - long long ops_sec; - - ops_sec = t > 0 ? (ops*1000/t) : 0; - - server.inst_metric[metric].samples[server.inst_metric[metric].idx] = - ops_sec; - server.inst_metric[metric].idx++; - server.inst_metric[metric].idx %= STATS_METRIC_SAMPLES; - server.inst_metric[metric].last_sample_time = now; - server.inst_metric[metric].last_sample_count = current_reading; +/* Add a sample to the instantaneous metric. This function computes the quotient + * of the increment of value and base, which is useful to record operation count + * per second, or the average time consumption of an operation. + * + * current_value - The dividend + * current_base - The divisor + * */ +void trackInstantaneousMetric(int metric, long long current_value, long long current_base, long long factor) { + if (server.inst_metric[metric].last_sample_base > 0) { + long long base = current_base - server.inst_metric[metric].last_sample_base; + long long value = current_value - server.inst_metric[metric].last_sample_value; + long long avg = base > 0 ? (value * factor / base) : 0; + server.inst_metric[metric].samples[server.inst_metric[metric].idx] = avg; + server.inst_metric[metric].idx++; + server.inst_metric[metric].idx %= STATS_METRIC_SAMPLES; + } + server.inst_metric[metric].last_sample_base = current_base; + server.inst_metric[metric].last_sample_value = current_value; } /* Return the mean of all the samples. */ @@ -744,7 +747,7 @@ int clientsCronResizeQueryBuffer(client *c) { * sure not to resize to less than the bulk length. */ size_t resize = sdslen(c->querybuf); if (resize < c->querybuf_peak) resize = c->querybuf_peak; - if (c->bulklen != -1 && resize < (size_t)c->bulklen) resize = c->bulklen; + if (c->bulklen != -1 && resize < (size_t)c->bulklen + 2) resize = c->bulklen + 2; c->querybuf = sdsResize(c->querybuf, resize, 1); } } @@ -754,8 +757,7 @@ int clientsCronResizeQueryBuffer(client *c) { c->querybuf_peak = sdslen(c->querybuf); /* We reset to either the current used, or currently processed bulk size, * which ever is bigger. */ - if (c->bulklen != -1 && (size_t)c->bulklen > c->querybuf_peak) - c->querybuf_peak = c->bulklen; + if (c->bulklen != -1 && (size_t)c->bulklen + 2 > c->querybuf_peak) c->querybuf_peak = c->bulklen + 2; return 0; } @@ -1015,12 +1017,11 @@ void clientsCron(void) { client *c; listNode *head; - /* Rotate the list, take the current head, process. - * This way if the client must be removed from the list it's the - * first element and we don't incur into O(N) computation. */ - listRotateTailToHead(server.clients); + /* Take the current head, process, and then rotate the head to tail. + * This way we can fairly iterate all clients step by step. */ head = listFirst(server.clients); c = listNodeValue(head); + listRotateHeadToTail(server.clients); /* The following functions do different service checks on the client. * The protocol is that they return non-zero if the client was * terminated. */ @@ -1149,7 +1150,7 @@ void enterExecutionUnit(int update_cached_time, long long us) { } } -void exitExecutionUnit() { +void exitExecutionUnit(void) { --server.execution_nesting; } @@ -1205,7 +1206,7 @@ void checkChildrenDone(void) { } /* Called from serverCron and cronUpdateMemoryStats to update cached memory metrics. */ -void cronUpdateMemoryStats() { +void cronUpdateMemoryStats(void) { /* Record the max memory used since the server was started. */ if (zmalloc_used_memory() > server.stat_peak_memory) server.stat_peak_memory = zmalloc_used_memory(); @@ -1286,6 +1287,8 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { /* for debug purposes: skip actual cron work if pause_cron is on */ if (server.pause_cron) return 1000/server.hz; + monotime cron_start = getMonotonicUs(); + run_with_period(100) { long long stat_net_input_bytes, stat_net_output_bytes; long long stat_net_repl_input_bytes, stat_net_repl_output_bytes; @@ -1293,16 +1296,21 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { atomicGet(server.stat_net_output_bytes, stat_net_output_bytes); atomicGet(server.stat_net_repl_input_bytes, stat_net_repl_input_bytes); atomicGet(server.stat_net_repl_output_bytes, stat_net_repl_output_bytes); - - trackInstantaneousMetric(STATS_METRIC_COMMAND,server.stat_numcommands); - trackInstantaneousMetric(STATS_METRIC_NET_INPUT, - stat_net_input_bytes + stat_net_repl_input_bytes); - trackInstantaneousMetric(STATS_METRIC_NET_OUTPUT, - stat_net_output_bytes + stat_net_repl_output_bytes); - trackInstantaneousMetric(STATS_METRIC_NET_INPUT_REPLICATION, - stat_net_repl_input_bytes); - trackInstantaneousMetric(STATS_METRIC_NET_OUTPUT_REPLICATION, - stat_net_repl_output_bytes); + monotime current_time = getMonotonicUs(); + long long factor = 1000000; // us + trackInstantaneousMetric(STATS_METRIC_COMMAND, server.stat_numcommands, current_time, factor); + trackInstantaneousMetric(STATS_METRIC_NET_INPUT, stat_net_input_bytes + stat_net_repl_input_bytes, + current_time, factor); + trackInstantaneousMetric(STATS_METRIC_NET_OUTPUT, stat_net_output_bytes + stat_net_repl_output_bytes, + current_time, factor); + trackInstantaneousMetric(STATS_METRIC_NET_INPUT_REPLICATION, stat_net_repl_input_bytes, current_time, + factor); + trackInstantaneousMetric(STATS_METRIC_NET_OUTPUT_REPLICATION, stat_net_repl_output_bytes, + current_time, factor); + trackInstantaneousMetric(STATS_METRIC_EL_CYCLE, server.duration_stats[EL_DURATION_TYPE_EL].cnt, + current_time, factor); + trackInstantaneousMetric(STATS_METRIC_EL_DURATION, server.duration_stats[EL_DURATION_TYPE_EL].sum, + server.duration_stats[EL_DURATION_TYPE_EL].cnt, 1); } /* We have just LRU_BITS bits per object for LRU information. @@ -1515,18 +1523,21 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { &ei); server.cronloops++; + + server.el_cron_duration = getMonotonicUs() - cron_start; + return 1000/server.hz; } -void blockingOperationStarts() { +void blockingOperationStarts(void) { if(!server.blocking_op_nesting++){ updateCachedTime(0); server.blocked_last_cron = server.mstime; } } -void blockingOperationEnds() { +void blockingOperationEnds(void) { if(!(--server.blocking_op_nesting)){ server.blocked_last_cron = 0; } @@ -1537,7 +1548,7 @@ void blockingOperationEnds() { * It attempts to do its duties at a similar rate as the configured server.hz, * and updates cronloops variable so that similarly to serverCron, the * run_with_period can be used. */ -void whileBlockedCron() { +void whileBlockedCron(void) { /* Here we may want to perform some cron jobs (normally done server.hz times * per second). */ @@ -1650,6 +1661,11 @@ void beforeSleep(struct aeEventLoop *eventLoop) { /* If any connection type(typical TLS) still has pending unread data don't sleep at all. */ aeSetDontWait(server.el, connTypeHasPendingData()); + /* Record cron time in beforeSleep, which is the sum of active-expire, active-defrag and all other + * tasks done by cron and beforeSleep, but excluding read, write and AOF, that are counted by other + * sets of metrics. */ + monotime cron_start_time_before_aof = getMonotonicUs(); + /* Call the Redis Cluster before sleep function. Note that this function * may change the state of Redis Cluster (from ok to fail or vice versa), * so it's a good idea to call it before serving the unblocked clients @@ -1658,7 +1674,7 @@ void beforeSleep(struct aeEventLoop *eventLoop) { /* Run a fast expire cycle (the called function will return * ASAP if a fast cycle is not needed). */ - if (server.active_expire_enabled && server.masterhost == NULL) + if (server.active_expire_enabled && iAmMaster()) activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST); /* Unblock all the clients blocked for synchronous replication @@ -1716,12 +1732,20 @@ void beforeSleep(struct aeEventLoop *eventLoop) { * since the unblocked clients may write data. */ handleClientsBlockedOnKeys(); + /* Record time consumption of AOF writing. */ + monotime aof_start_time = getMonotonicUs(); + /* Record cron time in beforeSleep. This does not include the time consumed by AOF writing and IO writing below. */ + monotime duration_before_aof = aof_start_time - cron_start_time_before_aof; + /* Write the AOF buffer on disk, * must be done before handleClientsWithPendingWritesUsingThreads, * in case of appendfsync=always. */ if (server.aof_state == AOF_ON || server.aof_state == AOF_WAIT_REWRITE) flushAppendOnlyFile(0); + /* Record time consumption of AOF writing. */ + durationAddSample(EL_DURATION_TYPE_AOF, getMonotonicUs() - aof_start_time); + /* Update the fsynced replica offset. * If an initial rewrite is in progress then not all data is guaranteed to have actually been * persisted to disk yet, so we cannot update the field. We will wait for the rewrite to complete. */ @@ -1734,6 +1758,9 @@ void beforeSleep(struct aeEventLoop *eventLoop) { /* Handle writes with pending output buffers. */ handleClientsWithPendingWritesUsingThreads(); + /* Record cron time in beforeSleep. This does not include the time consumed by AOF writing and IO writing above. */ + monotime cron_start_time_after_write = getMonotonicUs(); + /* Close clients that need to be closed asynchronous */ freeClientsInAsyncFreeQueue(); @@ -1745,6 +1772,25 @@ void beforeSleep(struct aeEventLoop *eventLoop) { /* Disconnect some clients if they are consuming too much memory. */ evictClients(); + /* Record cron time in beforeSleep. */ + monotime duration_after_write = getMonotonicUs() - cron_start_time_after_write; + + /* Record eventloop latency. */ + if (server.el_start > 0) { + monotime el_duration = getMonotonicUs() - server.el_start; + durationAddSample(EL_DURATION_TYPE_EL, el_duration); + } + server.el_cron_duration += duration_before_aof + duration_after_write; + durationAddSample(EL_DURATION_TYPE_CRON, server.el_cron_duration); + server.el_cron_duration = 0; + /* Record max command count per cycle. */ + if (server.stat_numcommands > server.el_cmd_cnt_start) { + long long el_command_cnt = server.stat_numcommands - server.el_cmd_cnt_start; + if (el_command_cnt > server.el_cmd_cnt_max) { + server.el_cmd_cnt_max = el_command_cnt; + } + } + /* Before we are going to sleep, let the threads access the dataset by * releasing the GIL. Redis main thread will not touch anything at this * time. */ @@ -1775,6 +1821,10 @@ void afterSleep(struct aeEventLoop *eventLoop) { latencyEndMonitor(latency); latencyAddSampleIfNeeded("module-acquire-GIL",latency); } + /* Set the eventloop start time. */ + server.el_start = getMonotonicUs(); + /* Set the eventloop command count at start. */ + server.el_cmd_cnt_start = server.stat_numcommands; } /* Update the time cache. */ @@ -1955,7 +2005,7 @@ void createSharedObjects(void) { shared.maxstring = sdsnew("maxstring"); } -void initServerClientMemUsageBuckets() { +void initServerClientMemUsageBuckets(void) { if (server.client_mem_usage_buckets) return; server.client_mem_usage_buckets = zmalloc(sizeof(clientMemUsageBucket)*CLIENT_MEM_USAGE_BUCKETS); @@ -1965,7 +2015,7 @@ void initServerClientMemUsageBuckets() { } } -void freeServerClientMemUsageBuckets() { +void freeServerClientMemUsageBuckets(void) { if (!server.client_mem_usage_buckets) return; for (int j = 0; j < CLIENT_MEM_USAGE_BUCKETS; j++) @@ -2018,6 +2068,7 @@ void initServerConfig(void) { server.aof_selected_db = -1; /* Make sure the first time will not match */ server.aof_flush_postponed_start = 0; server.aof_last_incr_size = 0; + server.aof_last_incr_fsync_offset = 0; server.active_defrag_running = 0; server.notify_keyspace_events = 0; server.blocked_clients = 0; @@ -2494,8 +2545,8 @@ void resetServerStats(void) { atomicSet(server.stat_total_writes_processed, 0); for (j = 0; j < STATS_METRIC_COUNT; j++) { server.inst_metric[j].idx = 0; - server.inst_metric[j].last_sample_time = mstime(); - server.inst_metric[j].last_sample_count = 0; + server.inst_metric[j].last_sample_base = 0; + server.inst_metric[j].last_sample_value = 0; memset(server.inst_metric[j].samples,0, sizeof(server.inst_metric[j].samples)); } @@ -2512,6 +2563,8 @@ void resetServerStats(void) { server.aof_delayed_fsync = 0; server.stat_reply_buffer_shrinks = 0; server.stat_reply_buffer_expands = 0; + memset(server.duration_stats, 0, sizeof(durationStats) * EL_DURATION_TYPE_NUM); + server.el_cmd_cnt_max = 0; lazyfreeResetStats(); } @@ -2717,7 +2770,7 @@ void initServer(void) { initServerClientMemUsageBuckets(); } -void initListeners() { +void initListeners(void) { /* Setup listeners from server config for TCP/TLS/Unix */ int conn_index; connListener *listener; @@ -2794,7 +2847,7 @@ void initListeners() { * Specifically, creation of threads due to a race bug in ld.so, in which * Thread Local Storage initialization collides with dlopen call. * see: https://sourceware.org/bugzilla/show_bug.cgi?id=19329 */ -void InitServerLast() { +void InitServerLast(void) { bioInit(); initThreadedIO(); set_jemalloc_bg_thread(server.jemalloc_bg_thread); @@ -2942,21 +2995,6 @@ void setImplicitACLCategories(struct redisCommand *c) { c->acl_categories |= ACL_CATEGORY_SLOW; } -/* Recursively populate the args structure (setting num_args to the number of - * subargs) and return the number of args. */ -int populateArgsStructure(struct redisCommandArg *args) { - if (!args) - return 0; - int count = 0; - while (args->name) { - serverAssert(count < INT_MAX); - args->num_args = populateArgsStructure(args->subargs); - count++; - args++; - } - return count; -} - /* Recursively populate the command structure. * * On success, the function return C_OK. Otherwise C_ERR is returned and we won't @@ -2974,28 +3012,10 @@ int populateCommandStructure(struct redisCommand *c) { * set of flags. */ setImplicitACLCategories(c); - /* Redis commands don't need more args than STATIC_KEY_SPECS_NUM (Number of keys - * specs can be greater than STATIC_KEY_SPECS_NUM only for module commands) */ - c->key_specs = c->key_specs_static; - c->key_specs_max = STATIC_KEY_SPECS_NUM; - /* We start with an unallocated histogram and only allocate memory when a command * has been issued for the first time */ c->latency_histogram = NULL; - for (int i = 0; i < STATIC_KEY_SPECS_NUM; i++) { - if (c->key_specs[i].begin_search_type == KSPEC_BS_INVALID) - break; - c->key_specs_num++; - } - - /* Count things so we don't have to use deferred reply in COMMAND reply. */ - while (c->history && c->history[c->num_history].since) - c->num_history++; - while (c->tips && c->tips[c->num_tips]) - c->num_tips++; - c->num_args = populateArgsStructure(c->args); - /* Handle the legacy range spec and the "movablekeys" flag (must be done after populating all key specs). */ populateCommandLegacyRangeSpec(c); @@ -3155,12 +3175,13 @@ struct redisCommand *lookupCommandBySdsLogic(dict *commands, sds s) { sds *strings = sdssplitlen(s,sdslen(s),"|",1,&argc); if (strings == NULL) return NULL; - if (argc > 2) { + if (argc < 1 || argc > 2) { /* Currently we support just one level of subcommands */ sdsfreesplitres(strings,argc); return NULL; } + serverAssert(argc > 0); /* Avoid warning `-Wmaybe-uninitialized` in lookupCommandLogic() */ robj objects[argc]; robj *argv[argc]; for (j = 0; j < argc; j++) { @@ -3336,7 +3357,7 @@ void updateCommandLatencyHistogram(struct hdr_histogram **latency_histogram, int /* Handle the alsoPropagate() API to handle commands that want to propagate * multiple separated commands. Note that alsoPropagate() is not affected * by CLIENT_PREVENT_PROP flag. */ -static void propagatePendingCommands() { +static void propagatePendingCommands(void) { if (server.also_propagate.numops == 0) return; @@ -3392,7 +3413,7 @@ static void propagatePendingCommands() { * currently with respect to replication and post jobs, but in the future there might * be other considerations. So we basically want the `postUnitOperations` to trigger * after the entire chain finished. */ -void postExecutionUnitOperations() { +void postExecutionUnitOperations(void) { if (server.execution_nesting) return; @@ -3563,6 +3584,8 @@ void call(client *c, int flags) { char *latency_event = (real_cmd->flags & CMD_FAST) ? "fast-command" : "command"; latencyAddSampleIfNeeded(latency_event,duration/1000); + if (server.execution_nesting == 0) + durationAddSample(EL_DURATION_TYPE_CMD, duration); } /* Log the command into the Slow log if needed. @@ -3595,6 +3618,12 @@ void call(client *c, int flags) { updateCommandLatencyHistogram(&(real_cmd->latency_histogram), c->duration*1000); } + /* The duration needs to be reset after each call except for a blocked command, + * which is expected to record and reset the duration after unblocking. */ + if (!(c->flags & CLIENT_BLOCKED)) { + c->duration = 0; + } + /* Propagate the command into the AOF and replication link. * We never propagate EXEC explicitly, it will be implicitly * propagated if needed (see propagatePendingCommands). @@ -4356,6 +4385,8 @@ int finishShutdown(void) { serverLog(LL_WARNING, "Writing initial AOF. Exit anyway."); } else { serverLog(LL_WARNING, "Writing initial AOF, can't exit."); + if (server.supervised_mode == SUPERVISED_SYSTEMD) + redisCommunicateSystemd("STATUS=Writing initial AOF, can't exit.\n"); goto error; } } @@ -4853,28 +4884,6 @@ void addReplyCommandSubCommands(client *c, struct redisCommand *cmd, void (*repl dictReleaseIterator(di); } -/* Must match redisCommandGroup */ -const char *COMMAND_GROUP_STR[] = { - "generic", - "string", - "list", - "set", - "sorted-set", - "hash", - "pubsub", - "transactions", - "connection", - "server", - "scripting", - "hyperloglog", - "cluster", - "sentinel", - "geo", - "stream", - "bitmap", - "module" -}; - /* Output the representation of a Redis command. Used by the COMMAND command and COMMAND INFO. */ void addReplyCommandInfo(client *c, struct redisCommand *cmd) { if (!cmd) { @@ -4933,7 +4942,7 @@ void addReplyCommandDocs(client *c, struct redisCommand *cmd) { /* Always have the group, for module commands the group is always "module". */ addReplyBulkCString(c, "group"); - addReplyBulkCString(c, COMMAND_GROUP_STR[cmd->group]); + addReplyBulkCString(c, commandGroupStr(cmd->group)); if (cmd->complexity) { addReplyBulkCString(c, "complexity"); @@ -5933,7 +5942,12 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) { "io_threaded_reads_processed:%lld\r\n" "io_threaded_writes_processed:%lld\r\n" "reply_buffer_shrinks:%lld\r\n" - "reply_buffer_expands:%lld\r\n", + "reply_buffer_expands:%lld\r\n" + "eventloop_cycles:%llu\r\n" + "eventloop_duration_sum:%llu\r\n" + "eventloop_duration_cmd_sum:%llu\r\n" + "instantaneous_eventloop_cycles_per_sec:%llu\r\n" + "instantaneous_eventloop_duration_usec:%llu\r\n", server.stat_numconnections, server.stat_numcommands, getInstantaneousMetric(STATS_METRIC_COMMAND), @@ -5983,7 +5997,12 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) { server.stat_io_reads_processed, server.stat_io_writes_processed, server.stat_reply_buffer_shrinks, - server.stat_reply_buffer_expands); + server.stat_reply_buffer_expands, + server.duration_stats[EL_DURATION_TYPE_EL].cnt, + server.duration_stats[EL_DURATION_TYPE_EL].sum, + server.duration_stats[EL_DURATION_TYPE_CMD].sum, + getInstantaneousMetric(STATS_METRIC_EL_CYCLE), + getInstantaneousMetric(STATS_METRIC_EL_DURATION)); info = genRedisInfoStringACLStats(info); } @@ -6233,6 +6252,21 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) { 0, /* not a crash report */ sections); } + + if (dictFind(section_dict, "debug") != NULL) { + if (sections++) info = sdscat(info,"\r\n"); + info = sdscatprintf(info, + "# Debug\r\n" + "eventloop_duration_aof_sum:%llu\r\n" + "eventloop_duration_cron_sum:%llu\r\n" + "eventloop_duration_max:%llu\r\n" + "eventloop_cmd_per_cycle_max:%lld\r\n", + server.duration_stats[EL_DURATION_TYPE_AOF].sum, + server.duration_stats[EL_DURATION_TYPE_CRON].sum, + server.duration_stats[EL_DURATION_TYPE_EL].max, + server.el_cmd_cnt_max); + } + return info; } @@ -6551,7 +6585,7 @@ void setupChildSignalHandlers(void) { * of the parent process, e.g. fd(socket or flock) etc. * should close the resources not used by the child process, so that if the * parent restarts it can bind/lock despite the child possibly still running. */ -void closeChildUnusedResourceAfterFork() { +void closeChildUnusedResourceAfterFork(void) { closeListeningSockets(0); if (server.cluster_enabled && server.cluster_config_file_lock_fd != -1) close(server.cluster_config_file_lock_fd); /* don't care if this fails */ @@ -6746,6 +6780,7 @@ void loadDataFromDisk(void) { serverLog(LL_NOTICE, "DB loaded from append only file: %.3f seconds", (float)(ustime()-start)/1000000); } else { rdbSaveInfo rsi = RDB_SAVE_INFO_INIT; + int rsi_is_valid = 0; errno = 0; /* Prevent a stale value from affecting error checking */ int rdb_flags = RDBFLAGS_NONE; if (iAmMaster()) { @@ -6767,6 +6802,7 @@ void loadDataFromDisk(void) { * information in function rdbPopulateSaveInfo. */ rsi.repl_stream_db != -1) { + rsi_is_valid = 1; if (!iAmMaster()) { memcpy(server.replid,rsi.repl_id,sizeof(server.replid)); server.master_repl_offset = rsi.repl_offset; @@ -6800,7 +6836,7 @@ void loadDataFromDisk(void) { * if RDB doesn't have replication info or there is no rdb, it is not * possible to support partial resynchronization, to avoid extra memory * of replication backlog, we drop it. */ - if (server.master_repl_offset == 0 && server.repl_backlog) + if (!rsi_is_valid && server.repl_backlog) freeReplicationBacklog(); } } @@ -7224,6 +7260,34 @@ int main(int argc, char **argv) { sdsfree(options); } if (server.sentinel_mode) sentinelCheckConfigFile(); + + /* Do system checks */ +#ifdef __linux__ + linuxMemoryWarnings(); + sds err_msg = NULL; + if (checkXenClocksource(&err_msg) < 0) { + serverLog(LL_WARNING, "WARNING %s", err_msg); + sdsfree(err_msg); + } +#if defined (__arm64__) + int ret; + if ((ret = checkLinuxMadvFreeForkBug(&err_msg)) <= 0) { + if (ret < 0) { + serverLog(LL_WARNING, "WARNING %s", err_msg); + sdsfree(err_msg); + } else + serverLog(LL_WARNING, "Failed to test the kernel for a bug that could lead to data corruption during background save. " + "Your system could be affected, please report this error."); + if (!checkIgnoreWarning("ARM64-COW-BUG")) { + serverLog(LL_WARNING,"Redis will now exit to prevent data corruption. " + "Note that it is possible to suppress this warning by setting the following config: ignore-warnings ARM64-COW-BUG"); + exit(1); + } + } +#endif /* __arm64__ */ +#endif /* __linux__ */ + + /* Daemonize if needed */ server.supervised = redisIsSupervised(server.supervised_mode); int background = server.daemonize && !server.supervised; if (background) daemonize(); @@ -7265,30 +7329,6 @@ int main(int argc, char **argv) { if (!server.sentinel_mode) { /* Things not needed when running in Sentinel mode. */ serverLog(LL_NOTICE,"Server initialized"); - #ifdef __linux__ - linuxMemoryWarnings(); - sds err_msg = NULL; - if (checkXenClocksource(&err_msg) < 0) { - serverLog(LL_WARNING, "WARNING %s", err_msg); - sdsfree(err_msg); - } - #if defined (__arm64__) - int ret; - if ((ret = checkLinuxMadvFreeForkBug(&err_msg)) <= 0) { - if (ret < 0) { - serverLog(LL_WARNING, "WARNING %s", err_msg); - sdsfree(err_msg); - } else - serverLog(LL_WARNING, "Failed to test the kernel for a bug that could lead to data corruption during background save. " - "Your system could be affected, please report this error."); - if (!checkIgnoreWarning("ARM64-COW-BUG")) { - serverLog(LL_WARNING,"Redis will now exit to prevent data corruption. " - "Note that it is possible to suppress this warning by setting the following config: ignore-warnings ARM64-COW-BUG"); - exit(1); - } - } - #endif /* __arm64__ */ - #endif /* __linux__ */ aofLoadManifestFromDisk(); loadDataFromDisk(); aofOpenIfNeededOnServerStart(); |