Merge branch 'unstable' of github.com:/antirez/redis into unstable

This commit is contained in:
antirez 2015-01-12 15:56:46 +01:00
commit 10007cb78c
5 changed files with 129 additions and 28 deletions

View File

@ -36,6 +36,17 @@
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized. # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize no daemonize no
# If you run Redis from upstart or systemd, Redis can interact with your
# supervision tree. Options:
# supervised no - no supervision interaction
# supervised upstart - signal upstart by putting Redis into SIGSTOP mode
# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
# supervised auto - detect upstart or systemd method based on
# UPSTART_JOB or NOTIFY_SOCKET environment variables
# Note: these supervision methods only signal "process is ready."
# They do not enable continuous liveness pings back to your supervisor.
supervised no
# When running daemonized, Redis writes a pid file in /var/run/redis.pid by # When running daemonized, Redis writes a pid file in /var/run/redis.pid by
# default. You can specify a custom pid file location here. # default. You can specify a custom pid file location here.
pidfile /var/run/redis.pid pidfile /var/run/redis.pid

View File

@ -60,6 +60,8 @@ clientBufferLimitsConfig clientBufferLimitsDefaults[REDIS_CLIENT_TYPE_COUNT] = {
* Config file parsing * Config file parsing
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
int supervisedToMode(const char *str);
int yesnotoi(char *s) { int yesnotoi(char *s) {
if (!strcasecmp(s,"yes")) return 1; if (!strcasecmp(s,"yes")) return 1;
else if (!strcasecmp(s,"no")) return 0; else if (!strcasecmp(s,"no")) return 0;
@ -533,6 +535,15 @@ void loadServerConfigFromString(char *config) {
goto loaderr; goto loaderr;
} }
server.notify_keyspace_events = flags; server.notify_keyspace_events = flags;
} else if (!strcasecmp(argv[0],"supervised") && argc == 2) {
int mode = supervisedToMode(argv[1]);
if (mode == -1) {
err = "Invalid option for 'supervised'. "
"Allowed values: 'upstart', 'systemd', 'auto', or 'no'";
goto loaderr;
}
server.supervised_mode = mode;
} else if (!strcasecmp(argv[0],"sentinel")) { } else if (!strcasecmp(argv[0],"sentinel")) {
/* argc == 1 is handled by main() as we need to enter the sentinel /* argc == 1 is handled by main() as we need to enter the sentinel
* mode ASAP. */ * mode ASAP. */
@ -1022,6 +1033,33 @@ char *maxmemoryToString() {
return s; return s;
} }
int supervisedToMode(const char *str) {
int mode;
if (!strcasecmp(str,"upstart")) {
mode = REDIS_SUPERVISED_UPSTART;
} else if (!strcasecmp(str,"systemd")) {
mode = REDIS_SUPERVISED_SYSTEMD;
} else if (!strcasecmp(str,"auto")) {
mode = REDIS_SUPERVISED_AUTODETECT;
} else if (!strcasecmp(str,"no")) {
mode = REDIS_SUPERVISED_NONE;
} else {
mode = -1;
}
return mode;
}
char *supervisedToString(void) {
char *s;
switch(server.supervised_mode) {
case REDIS_SUPERVISED_UPSTART: s = "upstart"; break;
case REDIS_SUPERVISED_SYSTEMD: s = "systemd"; break;
case REDIS_SUPERVISED_AUTODETECT: s = "auto"; break;
case REDIS_SUPERVISED_NONE: s = "no"; break;
default: s = "no"; break;
}
return s;
}
void configGetCommand(redisClient *c) { void configGetCommand(redisClient *c) {
robj *o = c->argv[2]; robj *o = c->argv[2];
void *replylen = addDeferredMultiBulkLength(c); void *replylen = addDeferredMultiBulkLength(c);
@ -1177,6 +1215,11 @@ void configGetCommand(redisClient *c) {
addReplyBulkCString(c,s); addReplyBulkCString(c,s);
matches++; matches++;
} }
if (stringmatch(pattern,"supervised",0)) {
addReplyBulkCString(c,"supervised");
addReplyBulkCString(c,supervisedToString());
matches++;
}
if (stringmatch(pattern,"client-output-buffer-limit",0)) { if (stringmatch(pattern,"client-output-buffer-limit",0)) {
sds buf = sdsempty(); sds buf = sdsempty();
int j; int j;
@ -1872,6 +1915,12 @@ int rewriteConfig(char *path) {
rewriteConfigNumericalOption(state,"hz",server.hz,REDIS_DEFAULT_HZ); rewriteConfigNumericalOption(state,"hz",server.hz,REDIS_DEFAULT_HZ);
rewriteConfigYesNoOption(state,"aof-rewrite-incremental-fsync",server.aof_rewrite_incremental_fsync,REDIS_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC); rewriteConfigYesNoOption(state,"aof-rewrite-incremental-fsync",server.aof_rewrite_incremental_fsync,REDIS_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC);
rewriteConfigYesNoOption(state,"aof-load-truncated",server.aof_load_truncated,REDIS_DEFAULT_AOF_LOAD_TRUNCATED); rewriteConfigYesNoOption(state,"aof-load-truncated",server.aof_load_truncated,REDIS_DEFAULT_AOF_LOAD_TRUNCATED);
rewriteConfigEnumOption(state,"supervised",server.supervised_mode,
"upstart", REDIS_SUPERVISED_UPSTART,
"systemd", REDIS_SUPERVISED_SYSTEMD,
"auto", REDIS_SUPERVISED_AUTODETECT,
"no", REDIS_SUPERVISED_NONE,
NULL, REDIS_SUPERVISED_NONE);
if (server.sentinel_mode) rewriteConfigSentinelOption(state); if (server.sentinel_mode) rewriteConfigSentinelOption(state);
/* Step 3: remove all the orphaned lines in the old file, that is, lines /* Step 3: remove all the orphaned lines in the old file, that is, lines

View File

@ -1324,8 +1324,8 @@ int rdbLoad(char *filename) {
auxkey->ptr); auxkey->ptr);
} }
zfree(auxkey); decrRefCount(auxkey);
zfree(auxval); decrRefCount(auxval);
continue; /* Read type again. */ continue; /* Read type again. */
} }

View File

@ -1416,6 +1416,7 @@ void initServerConfig(void) {
server.syslog_facility = LOG_LOCAL0; server.syslog_facility = LOG_LOCAL0;
server.daemonize = REDIS_DEFAULT_DAEMONIZE; server.daemonize = REDIS_DEFAULT_DAEMONIZE;
server.supervised = 0; server.supervised = 0;
server.supervised_mode = REDIS_SUPERVISED_NONE;
server.aof_state = REDIS_AOF_OFF; server.aof_state = REDIS_AOF_OFF;
server.aof_fsync = REDIS_DEFAULT_AOF_FSYNC; server.aof_fsync = REDIS_DEFAULT_AOF_FSYNC;
server.aof_no_fsync_on_rewrite = REDIS_DEFAULT_AOF_NO_FSYNC_ON_REWRITE; server.aof_no_fsync_on_rewrite = REDIS_DEFAULT_AOF_NO_FSYNC_ON_REWRITE;
@ -1433,7 +1434,7 @@ void initServerConfig(void) {
server.aof_flush_postponed_start = 0; server.aof_flush_postponed_start = 0;
server.aof_rewrite_incremental_fsync = REDIS_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC; server.aof_rewrite_incremental_fsync = REDIS_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC;
server.aof_load_truncated = REDIS_DEFAULT_AOF_LOAD_TRUNCATED; server.aof_load_truncated = REDIS_DEFAULT_AOF_LOAD_TRUNCATED;
server.pidfile = zstrdup(REDIS_DEFAULT_PID_FILE); server.pidfile = NULL;
server.rdb_filename = zstrdup(REDIS_DEFAULT_RDB_FILENAME); server.rdb_filename = zstrdup(REDIS_DEFAULT_RDB_FILENAME);
server.aof_filename = zstrdup(REDIS_DEFAULT_AOF_FILENAME); server.aof_filename = zstrdup(REDIS_DEFAULT_AOF_FILENAME);
server.requirepass = NULL; server.requirepass = NULL;
@ -2374,7 +2375,7 @@ int prepareForShutdown(int flags) {
return REDIS_ERR; return REDIS_ERR;
} }
} }
if (server.daemonize) { if (server.daemonize || server.pidfile) {
redisLog(REDIS_NOTICE,"Removing the pid file."); redisLog(REDIS_NOTICE,"Removing the pid file.");
unlink(server.pidfile); unlink(server.pidfile);
} }
@ -3393,6 +3394,10 @@ void linuxMemoryWarnings(void) {
#endif /* __linux__ */ #endif /* __linux__ */
void createPidFile(void) { void createPidFile(void) {
/* If pidfile requested, but no pidfile defined, use
* default pidfile path */
if (!server.pidfile) server.pidfile = zstrdup(REDIS_DEFAULT_PID_FILE);
/* Try to write the pid file in a best-effort way. */ /* Try to write the pid file in a best-effort way. */
FILE *fp = fopen(server.pidfile,"w"); FILE *fp = fopen(server.pidfile,"w");
if (fp) { if (fp) {
@ -3587,8 +3592,23 @@ void redisSetProcTitle(char *title) {
/* /*
* Check whether systemd or upstart have been used to start redis. * Check whether systemd or upstart have been used to start redis.
*/ */
int redisIsSupervised(void) {
int redisSupervisedUpstart(void) {
const char *upstart_job = getenv("UPSTART_JOB"); const char *upstart_job = getenv("UPSTART_JOB");
if (!upstart_job) {
redisLog(REDIS_WARNING,
"upstart supervision requested, but UPSTART_JOB not found");
return 0;
}
redisLog(REDIS_NOTICE, "supervised by upstart, will stop to signal readyness");
raise(SIGSTOP);
unsetenv("UPSTART_JOB");
return 1;
}
int redisSupervisedSystemd(void) {
const char *notify_socket = getenv("NOTIFY_SOCKET"); const char *notify_socket = getenv("NOTIFY_SOCKET");
int fd = 1; int fd = 1;
struct sockaddr_un su; struct sockaddr_un su;
@ -3596,31 +3616,24 @@ int redisIsSupervised(void) {
struct msghdr hdr; struct msghdr hdr;
int sendto_flags = 0; int sendto_flags = 0;
if (upstart_job == NULL && notify_socket == NULL) if (!notify_socket) {
redisLog(REDIS_WARNING,
"systemd supervision requested, but NOTIFY_SOCKET not found");
return 0; return 0;
if (upstart_job != NULL) {
redisLog(REDIS_NOTICE, "supervised by upstart, will stop to signal readyness");
raise(SIGSTOP);
unsetenv("UPSTART_JOB");
return 1;
} }
/* if ((strchr("@/", notify_socket[0])) == NULL || strlen(notify_socket) < 2) {
* If we got here, we're supervised by systemd.
*/
if ((strchr("@/", notify_socket[0])) == NULL ||
strlen(notify_socket) < 2)
return 0; return 0;
}
redisLog(REDIS_NOTICE, "supervised by systemd, will signal readyness"); redisLog(REDIS_NOTICE, "supervised by systemd, will signal readyness");
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
redisLog(REDIS_WARNING, "cannot contact systemd socket %s", notify_socket); redisLog(REDIS_WARNING,
"Can't connect to systemd socket %s", notify_socket);
return 0; return 0;
} }
bzero(&su, sizeof(su)); memset(&su, 0, sizeof(su));
su.sun_family = AF_UNIX; su.sun_family = AF_UNIX;
strncpy (su.sun_path, notify_socket, sizeof(su.sun_path) -1); strncpy (su.sun_path, notify_socket, sizeof(su.sun_path) -1);
su.sun_path[sizeof(su.sun_path) - 1] = '\0'; su.sun_path[sizeof(su.sun_path) - 1] = '\0';
@ -3628,11 +3641,11 @@ int redisIsSupervised(void) {
if (notify_socket[0] == '@') if (notify_socket[0] == '@')
su.sun_path[0] = '\0'; su.sun_path[0] = '\0';
bzero(&iov, sizeof(iov)); memset(&iov, 0, sizeof(iov));
iov.iov_base = "READY=1"; iov.iov_base = "READY=1";
iov.iov_len = strlen("READY=1"); iov.iov_len = strlen("READY=1");
bzero(&hdr, sizeof(hdr)); memset(&hdr, 0, sizeof(hdr));
hdr.msg_name = &su; hdr.msg_name = &su;
hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
strlen(notify_socket); strlen(notify_socket);
@ -3644,7 +3657,7 @@ int redisIsSupervised(void) {
sendto_flags |= MSG_NOSIGNAL; sendto_flags |= MSG_NOSIGNAL;
#endif #endif
if (sendmsg(fd, &hdr, sendto_flags) < 0) { if (sendmsg(fd, &hdr, sendto_flags) < 0) {
redisLog(REDIS_WARNING, "Cannot send notification to systemd"); redisLog(REDIS_WARNING, "Can't send notification to systemd");
close(fd); close(fd);
return 0; return 0;
} }
@ -3652,6 +3665,26 @@ int redisIsSupervised(void) {
return 1; return 1;
} }
int redisIsSupervised(int mode) {
if (mode == REDIS_SUPERVISED_AUTODETECT) {
const char *upstart_job = getenv("UPSTART_JOB");
const char *notify_socket = getenv("NOTIFY_SOCKET");
if (upstart_job) {
redisSupervisedUpstart();
} else if (notify_socket) {
redisSupervisedSystemd();
}
} else if (mode == REDIS_SUPERVISED_UPSTART) {
return redisSupervisedUpstart();
} else if (mode == REDIS_SUPERVISED_SYSTEMD) {
return redisSupervisedSystemd();
}
return 0;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
struct timeval tv; struct timeval tv;
@ -3758,10 +3791,11 @@ int main(int argc, char **argv) {
redisLog(REDIS_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"); redisLog(REDIS_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");
} }
server.supervised = redisIsSupervised(); server.supervised = redisIsSupervised(server.supervised_mode);
if (server.daemonize && server.supervised == 0) daemonize(); int background = server.daemonize && !server.supervised;
if (background) daemonize();
initServer(); initServer();
if (server.daemonize && server.supervised == 0) createPidFile(); if (background || server.pidfile) createPidFile();
redisSetProcTitle(argv[0]); redisSetProcTitle(argv[0]);
redisAsciiArt(); redisAsciiArt();

View File

@ -313,6 +313,12 @@ typedef long long mstime_t; /* millisecond time type. */
#define REDIS_LOG_RAW (1<<10) /* Modifier to log without timestamp */ #define REDIS_LOG_RAW (1<<10) /* Modifier to log without timestamp */
#define REDIS_DEFAULT_VERBOSITY REDIS_NOTICE #define REDIS_DEFAULT_VERBOSITY REDIS_NOTICE
/* Supervision options */
#define REDIS_SUPERVISED_NONE 0
#define REDIS_SUPERVISED_AUTODETECT 1
#define REDIS_SUPERVISED_SYSTEMD 2
#define REDIS_SUPERVISED_UPSTART 3
/* Anti-warning macro... */ /* Anti-warning macro... */
#define REDIS_NOTUSED(V) ((void) V) #define REDIS_NOTUSED(V) ((void) V)
@ -740,7 +746,8 @@ struct redisServer {
int active_expire_enabled; /* Can be disabled for testing purposes. */ int active_expire_enabled; /* Can be disabled for testing purposes. */
size_t client_max_querybuf_len; /* Limit for client query buffer length */ size_t client_max_querybuf_len; /* Limit for client query buffer length */
int dbnum; /* Total number of configured DBs */ int dbnum; /* Total number of configured DBs */
int supervised; /* True if supervised by upstart or systemd */ int supervised; /* 1 if supervised, 0 otherwise. */
int supervised_mode; /* See REDIS_SUPERVISED_* */
int daemonize; /* True if running as a daemon */ int daemonize; /* True if running as a daemon */
clientBufferLimitsConfig client_obuf_limits[REDIS_CLIENT_TYPE_COUNT]; clientBufferLimitsConfig client_obuf_limits[REDIS_CLIENT_TYPE_COUNT];
/* AOF persistence */ /* AOF persistence */