/* * Copyright (c) 2009-2016, Redis Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Redis nor the names of its contributors may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "server.h" #include "monotonic.h" #include "cluster.h" #include "cluster_slot_stats.h" #include "slowlog.h" #include "bio.h" #include "latency.h" #include "mt19937-64.h" #include "functions.h" #include "hdr_histogram.h" #include "syscheck.h" #include "threads_mngr.h" #include "fmtargs.h" #include "io_threads.h" #include "sds.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __linux__ #include #endif #if defined(HAVE_SYSCTL_KIPC_SOMAXCONN) || defined(HAVE_SYSCTL_KERN_SOMAXCONN) #include #endif #ifdef __GNUC__ #define GNUC_VERSION_STR STRINGIFY(__GNUC__) "." STRINGIFY(__GNUC_MINOR__) "." STRINGIFY(__GNUC_PATCHLEVEL__) #else #define GNUC_VERSION_STR "0.0.0" #endif /* Our shared "common" objects */ struct sharedObjectsStruct shared; /* 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. */ double R_Zero, R_PosInf, R_NegInf, R_Nan; /*================================= Globals ================================= */ /* Global vars */ struct valkeyServer server; /* Server global state */ /*============================ Internal prototypes ========================== */ static inline int isShutdownInitiated(void); int isReadyToShutdown(void); int finishShutdown(void); const char *replstateToString(int replstate); /*============================ Utility functions ============================ */ /* This macro tells if we are in the context of loading an AOF. */ #define isAOFLoadingContext() ((server.current_client && server.current_client->id == CLIENT_ID_AOF) ? 1 : 0) /* We use a private localtime implementation which is fork-safe. The logging * function of the server may be called from other threads. */ void nolocks_localtime(struct tm *tmp, time_t t, time_t tz, int dst); /* Low level logging. To use only for very big messages, otherwise * serverLog() is to prefer. */ void serverLogRaw(int level, const char *msg) { const int syslogLevelMap[] = {LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING}; const char *c = ".-*#"; FILE *fp; char buf[64]; int rawmode = (level & LL_RAW); int log_to_stdout = server.logfile[0] == '\0'; level &= 0xff; /* clear flags */ if (level < server.verbosity) return; /* We open and close the log file in every call to support log rotation. * This allows external processes to move or truncate the log file without * disrupting logging. */ fp = log_to_stdout ? stdout : fopen(server.logfile, "a"); if (!fp) return; if (rawmode) { fprintf(fp, "%s", msg); } else { int off; struct timeval tv; int role_char; pid_t pid = getpid(); int daylight_active = atomic_load_explicit(&server.daylight_active, memory_order_relaxed); gettimeofday(&tv, NULL); struct tm tm; nolocks_localtime(&tm, tv.tv_sec, server.timezone, daylight_active); off = strftime(buf, sizeof(buf), "%d %b %Y %H:%M:%S.", &tm); snprintf(buf + off, sizeof(buf) - off, "%03d", (int)tv.tv_usec / 1000); if (server.sentinel_mode) { role_char = 'X'; /* Sentinel. */ } else if (pid != server.pid) { role_char = 'C'; /* RDB / AOF writing child. */ } else { role_char = (server.primary_host ? 'S' : 'M'); /* replica or Primary. */ } fprintf(fp, "%d:%c %s %c %s\n", (int)getpid(), role_char, buf, c[level], msg); } fflush(fp); if (!log_to_stdout) fclose(fp); if (server.syslog_enabled) syslog(syslogLevelMap[level], "%s", 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, ...) { va_list ap; char msg[LOG_MAX_LEN]; va_start(ap, fmt); vsnprintf(msg, sizeof(msg), fmt, ap); va_end(ap); serverLogRaw(level, msg); } /* Low level logging from signal handler. Should be used with pre-formatted strings. See serverLogFromHandler. */ void serverLogRawFromHandler(int level, const char *msg) { int fd; int log_to_stdout = server.logfile[0] == '\0'; char buf[64]; if ((level & 0xff) < server.verbosity || (log_to_stdout && server.daemonize)) return; fd = log_to_stdout ? STDOUT_FILENO : open(server.logfile, O_APPEND | O_CREAT | O_WRONLY, 0644); if (fd == -1) return; if (level & LL_RAW) { if (write(fd, msg, strlen(msg)) == -1) goto err; } else { ll2string(buf, sizeof(buf), getpid()); if (write(fd, buf, strlen(buf)) == -1) goto err; if (write(fd, ":signal-handler (", 17) == -1) goto err; ll2string(buf, sizeof(buf), time(NULL)); if (write(fd, buf, strlen(buf)) == -1) goto err; if (write(fd, ") ", 2) == -1) goto err; if (write(fd, msg, strlen(msg)) == -1) goto err; if (write(fd, "\n", 1) == -1) goto err; } err: if (!log_to_stdout) close(fd); } /* An async-signal-safe version of serverLog. if LL_RAW is not included in level flags, * The message format is: :signal-handler (