提交 73427462 编写于 作者: A antirez

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.
上级 c372a595
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册