summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2015-10-13 10:58:08 +0200
committerantirez <antirez@gmail.com>2015-10-13 11:02:35 +0200
commit73427462ed8fc089a0fd6cecf0ae73f1339f68f6 (patch)
treeb2cb800699f78accc2d815ffc130870e050961e7 /src
parentc372a595201451721ddc76bc627e169c9b465c20 (diff)
downloadredis-73427462ed8fc089a0fd6cecf0ae73f1339f68f6.tar.gz
Server: restartServer() API.
This new function is able to restart the server "in place". The current Redis process executes the same executable it was executed with, using the same arguments and configuration file.
Diffstat (limited to 'src')
-rw-r--r--src/server.c70
-rw-r--r--src/server.h7
2 files changed, 73 insertions, 4 deletions
diff --git a/src/server.c b/src/server.c
index 267e585ec..96cd28d4f 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1436,6 +1436,7 @@ void initServerConfig(void) {
getRandomHexChars(server.runid,CONFIG_RUN_ID_SIZE);
server.configfile = NULL;
+ server.executable = NULL;
server.hz = CONFIG_DEFAULT_HZ;
server.runid[CONFIG_RUN_ID_SIZE] = '\0';
server.arch_bits = (sizeof(long) == 8) ? 64 : 32;
@@ -1595,6 +1596,50 @@ void initServerConfig(void) {
server.watchdog_period = 0;
}
+extern char **environ;
+
+/* Restart the server, executing the same executable that started this
+ * instance, with the same arguments and configuration file.
+ *
+ * The list of flags, that may be bitwise ORed together, alter the
+ * behavior of this function:
+ *
+ * RESTART_SERVER_NONE No flags.
+ * RESTART_SERVER_GRACEFULLY Do a proper shutdown before restarting.
+ * RESTART_SERVER_CONFIG_REWRITE Rewrite the config file before restarting.
+ *
+ * On success the function does not return, because the process turns into
+ * a different process. On error C_ERR is returned. */
+int restartServer(int flags, mstime_t delay) {
+ int j;
+
+ /* Check if we still have accesses to the executable that started this
+ * server instance. */
+ if (access(server.executable,X_OK) == -1) return C_ERR;
+
+ /* Config rewriting. */
+ if (flags & RESTART_SERVER_CONFIG_REWRITE &&
+ server.configfile &&
+ rewriteConfig(server.configfile) == -1) return C_ERR;
+
+ /* Perform a proper shutdown. */
+ if (flags & RESTART_SERVER_GRACEFULLY &&
+ prepareForShutdown(SHUTDOWN_NOFLAGS) != C_OK) return C_ERR;
+
+ /* Close all file descriptors, with the exception of stdin, stdout, strerr
+ * which are useful if we restart a Redis server which is not daemonized. */
+ for (j = 3; j < (int)server.maxclients + 1024; j++) close(j);
+
+ /* Execute the server with the original command line. */
+ if (delay) usleep(delay*1000);
+ execve(server.executable,server.exec_argv,environ);
+
+ /* If an error occurred here, there is nothing we can do, but exit. */
+ _exit(1);
+
+ return C_ERR; /* Never reached. */
+}
+
/* This function will try to raise the max number of open files accordingly to
* the configured max number of clients. It also reserves a number of file
* descriptors (CONFIG_MIN_RESERVED_FDS) for extra operations of
@@ -2730,6 +2775,7 @@ sds genRedisInfoString(char *section) {
"uptime_in_days:%jd\r\n"
"hz:%d\r\n"
"lru_clock:%ld\r\n"
+ "executable:%s\r\n"
"config_file:%s\r\n",
REDIS_VERSION,
redisGitSHA1(),
@@ -2751,6 +2797,7 @@ sds genRedisInfoString(char *section) {
(intmax_t)(uptime/(3600*24)),
server.hz,
(unsigned long) server.lruclock,
+ server.executable ? server.executable : "",
server.configfile ? server.configfile : "");
}
@@ -3793,6 +3840,7 @@ int redisIsSupervised(int mode) {
int main(int argc, char **argv) {
struct timeval tv;
+ int j;
#ifdef REDIS_TEST
if (argc == 3 && !strcasecmp(argv[1], "test")) {
@@ -3833,6 +3881,13 @@ int main(int argc, char **argv) {
server.sentinel_mode = checkForSentinelMode(argc,argv);
initServerConfig();
+ /* Store the executable path and arguments in a safe place in order
+ * to be able to restart the server later. */
+ server.executable = getAbsolutePath(argv[0]);
+ server.exec_argv = zmalloc(sizeof(char*)*(argc+1));
+ server.exec_argv[argc] = NULL;
+ for (j = 0; j < argc; j++) server.exec_argv[j] = zstrdup(argv[j]);
+
/* 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. */
@@ -3848,7 +3903,7 @@ int main(int argc, char **argv) {
exit(redis_check_rdb_main(argv,argc));
if (argc >= 2) {
- int j = 1; /* First option to parse in argv[] */
+ j = 1; /* First option to parse in argv[] */
sds options = sdsempty();
char *configfile = NULL;
@@ -3869,8 +3924,16 @@ int main(int argc, char **argv) {
}
/* First argument is the config file name? */
- if (argv[j][0] != '-' || argv[j][1] != '-')
- configfile = argv[j++];
+ if (argv[j][0] != '-' || argv[j][1] != '-') {
+ configfile = argv[j];
+ server.configfile = getAbsolutePath(configfile);
+ /* Replace the config file in server.exec_argv with
+ * its absoulte path. */
+ zfree(server.exec_argv[j]);
+ server.exec_argv[j] = zstrdup(server.configfile);
+ j++;
+ }
+
/* All the other options are parsed and conceptually appended to the
* configuration file. For instance --port 6380 will generate the
* string "port 6380\n" to be parsed after the actual file name
@@ -3900,7 +3963,6 @@ int main(int argc, char **argv) {
"Sentinel needs config file on disk to save state. Exiting...");
exit(1);
}
- if (configfile) server.configfile = getAbsolutePath(configfile);
resetServerSaveParams();
loadServerConfig(configfile,options);
sdsfree(options);
diff --git a/src/server.h b/src/server.h
index 9f3e9b0d2..6d9e70028 100644
--- a/src/server.h
+++ b/src/server.h
@@ -694,6 +694,8 @@ struct redisServer {
/* General */
pid_t pid; /* Main process pid. */
char *configfile; /* Absolute config file path, or NULL */
+ char *executable; /* Absolute executable file path. */
+ char **exec_argv; /* Executable argv vector (copy). */
int hz; /* serverCron() calls frequency in hertz */
redisDb *db;
dict *commands; /* Command table */
@@ -1321,6 +1323,11 @@ void resetServerStats(void);
unsigned int getLRUClock(void);
const char *maxmemoryToString(void);
+#define RESTART_SERVER_NONE 0
+#define RESTART_SERVER_GRACEFULLY (1<<0) /* Do proper shutdown. */
+#define RESTART_SERVER_CONFIG_REWRITE (1<<1) /* CONFIG REWRITE before restart.*/
+int restartServer(int flags, mstime_t delay);
+
/* Set data type */
robj *setTypeCreate(sds value);
int setTypeAdd(robj *subject, sds value);