From e951eba96cddcda5b7c3ae09b40be8b0e2fe8cd1 Mon Sep 17 00:00:00 2001 From: Unbit Date: Fri, 22 Mar 2013 14:56:49 +0100 Subject: [PATCH] improved emperor on demand mode --- core/emperor.c | 19 +++++++++++++++++-- core/socket.c | 15 +++++++++++++++ core/stats.c | 39 +++++++++++++++++++++++++++++++++++++++ core/uwsgi.c | 3 +++ uwsgi.h | 5 +++++ 5 files changed, 79 insertions(+), 2 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 3e28e933..1a177bd1 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -509,6 +509,10 @@ void emperor_del(struct uwsgi_instance *c_ui) { uwsgi.emperor_broodlord_count--; } + if (c_ui->socket_name) { + free(c_ui->socket_name); + } + free(c_ui); } @@ -648,6 +652,9 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha n_ui->first_run = uwsgi_now(); n_ui->last_run = n_ui->first_run; n_ui->on_demand_fd = -1; + if (socket_name) { + n_ui->socket_name = uwsgi_str(socket_name); + } n_ui->pid = -1; @@ -669,6 +676,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha uwsgi_error("emperor_add()/bind()"); free(n_ui); c_ui->ui_next = NULL; + return; } event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->on_demand_fd); @@ -1104,6 +1112,8 @@ void emperor_loop() { char notification_message[64]; struct rlimit rl; + uwsgi.disable_nuclear_blast = 1; + uwsgi.emperor_stats_fd = -1; if (uwsgi.emperor_pidfile) { @@ -1216,6 +1226,7 @@ void emperor_loop() { else if (byte == 30 && uwsgi.emperor_broodlord > 0 && uwsgi.emperor_broodlord_count < uwsgi.emperor_broodlord) { uwsgi_log("[emperor] going in broodlord mode: launching zergs for %s\n", ui_current->name); char *zerg_name = uwsgi_concat3(ui_current->name, ":", "zerg"); + // here we discard socket name as broodlord/zerg cannot be on demand emperor_add(ui_current->scanner, zerg_name, uwsgi_now(), NULL, 0, ui_current->uid, ui_current->gid, NULL); free(zerg_name); } @@ -1312,7 +1323,7 @@ void emperor_loop() { } else { // UNSAFE - emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid, NULL); + emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid, ui_current->socket_name); emperor_del(ui_current); } break; @@ -1406,7 +1417,7 @@ void emperor_send_stats(int fd) { if (uwsgi_stats_keyval_comma(us, "id", c_ui->name)) goto end0; - if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) c_ui->pid)) + if (uwsgi_stats_keyslong_comma(us, "pid", (long long) c_ui->pid)) goto end0; if (uwsgi_stats_keylong_comma(us, "born", (unsigned long long) c_ui->born)) goto end0; @@ -1425,6 +1436,9 @@ void emperor_send_stats(int fd) { if (uwsgi_stats_keylong_comma(us, "zerg", (unsigned long long) c_ui->zerg)) goto end0; + if (uwsgi_stats_keyval_comma(us, "on_demand", c_ui->socket_name ? c_ui->socket_name : "")) + goto end0; + if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) c_ui->uid)) goto end0; if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) c_ui->gid)) @@ -1543,6 +1557,7 @@ void uwsgi_emperor_start() { else { uwsgi.emperor_pid = uwsgi_fork("uWSGI Emperor"); } + if (uwsgi.emperor_pid < 0) { uwsgi_error("pid()"); exit(1); diff --git a/core/socket.c b/core/socket.c index d6ea8692..0376539c 100644 --- a/core/socket.c +++ b/core/socket.c @@ -66,6 +66,7 @@ int bind_to_unix_dgram(char *socket_name) { if (serverfd < 0) { uwsgi_error("socket()"); uwsgi_nuclear_blast(); + return -1; } if (unlink(socket_name) != 0 && errno != ENOENT) { @@ -85,6 +86,7 @@ int bind_to_unix_dgram(char *socket_name) { #endif uwsgi_error("bind()"); uwsgi_nuclear_blast(); + return -1; } return serverfd; @@ -100,6 +102,7 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst if (strlen(socket_name) > 102) { uwsgi_log("invalid socket name\n"); uwsgi_nuclear_blast(); + return -1; } if (socket_name[0] == '@') { @@ -113,6 +116,7 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst if (uws_addr == NULL) { uwsgi_error("malloc()"); uwsgi_nuclear_blast(); + return -1; } memset(uws_addr, 0, sizeof(struct sockaddr_un)); @@ -120,6 +124,7 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst if (serverfd < 0) { uwsgi_error("socket()"); uwsgi_nuclear_blast(); + return -1; } if (abstract_socket == 0) { if (unlink(socket_name) != 0 && errno != ENOENT) { @@ -157,12 +162,14 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst #endif uwsgi_error("bind()"); uwsgi_nuclear_blast(); + return -1; } if (listen(serverfd, listen_queue) != 0) { uwsgi_error("listen()"); uwsgi_nuclear_blast(); + return -1; } // chmod unix socket for lazy users @@ -578,11 +585,13 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) { if (serverfd < 0) { uwsgi_error("socket()"); uwsgi_nuclear_blast(); + return -1; } if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) { uwsgi_error("SO_REUSEADDR setsockopt()"); uwsgi_nuclear_blast(); + return -1; } #ifdef __linux__ @@ -593,6 +602,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) { if (setsockopt(serverfd, SOL_IP, IP_FREEBIND, (const void *) &uwsgi.freebind, sizeof(int)) < 0) { uwsgi_error("IP_FREEBIND setsockopt()"); uwsgi_nuclear_blast(); + return -1; } } #endif @@ -602,6 +612,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) { if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEPORT, (const void *) &uwsgi.reuse_port, sizeof(int)) < 0) { uwsgi_error("SO_REUSEPORT setsockopt()"); uwsgi_nuclear_blast(); + return -1; } #else uwsgi_log("!!! your system does not support SO_REUSEPORT !!!\n"); @@ -628,6 +639,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) { if (setsockopt(serverfd, SOL_SOCKET, SO_SNDTIMEO, (const void *) &tv, sizeof(struct timeval)) < 0) { uwsgi_error("SO_SNDTIMEO setsockopt()"); uwsgi_nuclear_blast(); + return -1; } } @@ -662,6 +674,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) { } uwsgi_error("bind()"); uwsgi_nuclear_blast(); + return -1; } #ifdef __linux__ @@ -669,12 +682,14 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) { if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) { uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn); uwsgi_nuclear_blast(); + return -1; } #endif if (listen(serverfd, listen_queue) != 0) { uwsgi_error("listen()"); uwsgi_nuclear_blast(); + return -1; } diff --git a/core/stats.c b/core/stats.c index 97acce39..22c9e32c 100644 --- a/core/stats.c +++ b/core/stats.c @@ -315,6 +315,45 @@ int uwsgi_stats_keylong_comma(struct uwsgi_stats *us, char *key, unsigned long l return uwsgi_stats_comma(us); } +int uwsgi_stats_keyslong(struct uwsgi_stats *us, char *key, long long num) { + + if (uwsgi_stats_apply_tabs(us)) + return -1; + + char *ptr = us->base + us->pos; + char *watermark = us->base + us->size; + size_t available = watermark - ptr; + + int ret = snprintf(ptr, available, "\"%s\":%lld", key, num); + if (ret < 0) + return -1; + while (ret >= (int) available) { + char *new_base = realloc(us->base, us->size + us->chunk); + if (!new_base) + return -1; + us->base = new_base; + us->size += us->chunk; + ptr = us->base + us->pos; + watermark = us->base + us->size; + available = watermark - ptr; + ret = snprintf(ptr, available, "\"%s\":%lld", key, num); + if (ret < 0) + return -1; + } + + us->pos += ret; + return 0; +} + + +int uwsgi_stats_keyslong_comma(struct uwsgi_stats *us, char *key, long long num) { + int ret = uwsgi_stats_keyslong(us, key, num); + if (ret) + return -1; + return uwsgi_stats_comma(us); +} + + void uwsgi_send_stats(int fd, struct uwsgi_stats *(*func) (void)) { struct sockaddr_un client_src; diff --git a/core/uwsgi.c b/core/uwsgi.c index f3ec3657..b3770754 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -1041,6 +1041,9 @@ void grace_them_all(int signum) { void uwsgi_nuclear_blast() { + // the Emperor (as an example) cannot nuke itself + if (uwsgi.disable_nuclear_blast) return; + if (!uwsgi.workers) { reap_them_all(0); } diff --git a/uwsgi.h b/uwsgi.h index 9b49c4d3..03d79f11 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -1626,6 +1626,8 @@ struct uwsgi_server { // run a shell script passing the vassal as the only argument, the stdout is used as the socket char *emperor_on_demand_exec; + int disable_nuclear_blast; + time_t next_heartbeat; int heartbeat; struct uwsgi_string_list *emperor; @@ -3404,6 +3406,8 @@ int uwsgi_stats_keyvaln_comma(struct uwsgi_stats *, char *, char *, int); int uwsgi_stats_key(struct uwsgi_stats *, char *); int uwsgi_stats_keylong(struct uwsgi_stats *, char *, unsigned long long); int uwsgi_stats_keylong_comma(struct uwsgi_stats *, char *, unsigned long long); +int uwsgi_stats_keyslong(struct uwsgi_stats *, char *, long long); +int uwsgi_stats_keyslong_comma(struct uwsgi_stats *, char *, long long); int uwsgi_stats_str(struct uwsgi_stats *, char *); char *uwsgi_substitute(char *, char *, char *); @@ -3517,6 +3521,7 @@ struct uwsgi_instance { gid_t gid; int on_demand_fd; + char *socket_name; }; struct uwsgi_instance *emperor_get_by_fd(int);