diff options
author | Arno Töll <arno@debian.org> | 2012-11-21 23:03:36 +0100 |
---|---|---|
committer | Arno Töll <arno@debian.org> | 2012-11-21 23:03:36 +0100 |
commit | 0e7d1e864fb7bc92f3bbab4a9a0f154ad00fd76e (patch) | |
tree | e0098274febb4c76579f70e9f6a7bd35ba189a7d /src/mod_fastcgi.c | |
parent | eb45c46b906e492f063f1469486190e93ff340ff (diff) | |
download | lighttpd-0e7d1e864fb7bc92f3bbab4a9a0f154ad00fd76e.tar.gz |
Imported Upstream version 1.4.11upstream/1.4.11
Diffstat (limited to 'src/mod_fastcgi.c')
-rw-r--r-- | src/mod_fastcgi.c | 685 |
1 files changed, 311 insertions, 374 deletions
diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c index da20c76..e64351a 100644 --- a/src/mod_fastcgi.c +++ b/src/mod_fastcgi.c @@ -57,8 +57,10 @@ typedef struct fcgi_proc { size_t id; /* id will be between 1 and max_procs */ - buffer *socket; /* config.socket + "-" + id */ + buffer *unixsocket; /* config.socket + "-" + id */ unsigned port; /* config.port + pno */ + + buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */ pid_t pid; /* PID of the spawned process (0 if not spawned locally) */ @@ -74,12 +76,13 @@ typedef struct fcgi_proc { int is_local; enum { - PROC_STATE_UNSET, /* init-phase */ - PROC_STATE_RUNNING, /* alive */ - PROC_STATE_DIED_WAIT_FOR_PID, - PROC_STATE_KILLED, /* was killed as we don't have the load anymore */ - PROC_STATE_DIED, /* marked as dead, should be restarted */ - PROC_STATE_DISABLED /* proc disabled as it resulted in an error */ + PROC_STATE_UNSET, /* init-phase */ + PROC_STATE_RUNNING, /* alive */ + PROC_STATE_OVERLOADED, /* listen-queue is full, + don't send something to this proc for the next 2 seconds */ + PROC_STATE_DIED_WAIT_FOR_PID, /* */ + PROC_STATE_DIED, /* marked as dead, should be restarted */ + PROC_STATE_KILLED /* was killed as we don't have the load anymore */ } state; } fcgi_proc; @@ -262,6 +265,8 @@ typedef struct { typedef struct { buffer *key; /* like .php */ + int note_is_sent; + fcgi_extension_host **hosts; size_t used; @@ -358,8 +363,6 @@ typedef struct { /* ok, we need a prototype */ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents); -int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc); - data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) { data_integer *di; @@ -406,8 +409,10 @@ int status_counter_set(server *srv, const char *s, size_t len, int val) { int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) { buffer_copy_string(b, "fastcgi.backend."); buffer_append_string_buffer(b, host->id); - buffer_append_string(b, "."); - buffer_append_long(b, proc->id); + if (proc) { + buffer_append_string(b, "."); + buffer_append_long(b, proc->id); + } return 0; } @@ -426,6 +431,15 @@ int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_ #undef CLEAN +#define CLEAN(x) \ + fastcgi_status_copy_procname(b, host, NULL); \ + buffer_append_string(b, x); \ + status_counter_set(srv, CONST_BUF_LEN(b), 0); + + CLEAN(".load"); + +#undef CLEAN + return 0; } @@ -472,7 +486,8 @@ fcgi_proc *fastcgi_process_init() { fcgi_proc *f; f = calloc(1, sizeof(*f)); - f->socket = buffer_init(); + f->unixsocket = buffer_init(); + f->connection_name = buffer_init(); f->prev = NULL; f->next = NULL; @@ -485,7 +500,8 @@ void fastcgi_process_free(fcgi_proc *f) { fastcgi_process_free(f->next); - buffer_free(f->socket); + buffer_free(f->unixsocket); + buffer_free(f->connection_name); free(f); } @@ -669,8 +685,8 @@ FREE_FUNC(mod_fastcgi_free) { if (proc->pid != 0) kill(proc->pid, SIGTERM); if (proc->is_local && - !buffer_is_empty(proc->socket)) { - unlink(proc->socket->ptr); + !buffer_is_empty(proc->unixsocket)) { + unlink(proc->unixsocket->ptr); } } @@ -678,8 +694,8 @@ FREE_FUNC(mod_fastcgi_free) { if (proc->pid != 0) kill(proc->pid, SIGTERM); if (proc->is_local && - !buffer_is_empty(proc->socket)) { - unlink(proc->socket->ptr); + !buffer_is_empty(proc->unixsocket)) { + unlink(proc->unixsocket->ptr); } } } @@ -799,24 +815,28 @@ static int fcgi_spawn_connection(server *srv, if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sdb", - "new proc, socket:", proc->port, proc->socket); + "new proc, socket:", proc->port, proc->unixsocket); } - if (!buffer_is_empty(proc->socket)) { + if (!buffer_is_empty(proc->unixsocket)) { memset(&fcgi_addr, 0, sizeof(fcgi_addr)); #ifdef HAVE_SYS_UN_H fcgi_addr_un.sun_family = AF_UNIX; - strcpy(fcgi_addr_un.sun_path, proc->socket->ptr); + strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr); #ifdef SUN_LEN servlen = SUN_LEN(&fcgi_addr_un); #else /* stevens says: */ - servlen = proc->socket->used - 1 + sizeof(fcgi_addr_un.sun_family); + servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family); #endif socket_type = AF_UNIX; fcgi_addr = (struct sockaddr *) &fcgi_addr_un; + + buffer_copy_string(proc->connection_name, "unix:"); + buffer_append_string_buffer(proc->connection_name, proc->unixsocket); + #else log_error_write(srv, __FILE__, __LINE__, "s", "ERROR: Unix Domain sockets are not supported."); @@ -859,6 +879,11 @@ static int fcgi_spawn_connection(server *srv, socket_type = AF_INET; fcgi_addr = (struct sockaddr *) &fcgi_addr_in; + + buffer_copy_string(proc->connection_name, "tcp:"); + buffer_append_string_buffer(proc->connection_name, host->host); + buffer_append_string(proc->connection_name, ":"); + buffer_append_long(proc->connection_name, proc->port); } if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { @@ -872,8 +897,9 @@ static int fcgi_spawn_connection(server *srv, pid_t child; int val; - if (!buffer_is_empty(proc->socket)) { - unlink(proc->socket->ptr); + if (errno != ENOENT && + !buffer_is_empty(proc->unixsocket)) { + unlink(proc->unixsocket->ptr); } close(fcgi_fd); @@ -894,10 +920,9 @@ static int fcgi_spawn_connection(server *srv, /* create socket */ if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { - log_error_write(srv, __FILE__, __LINE__, "sbds", + log_error_write(srv, __FILE__, __LINE__, "sbs", "bind failed for:", - proc->socket, - proc->port, + proc->connection_name, strerror(errno)); return -1; } @@ -1040,7 +1065,7 @@ static int fcgi_spawn_connection(server *srv, WTERMSIG(status)); if (WTERMSIG(status) == 11) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "s", "to be exact: it seg-fault, crashed, died, ... you get the idea." ); log_error_write(srv, __FILE__, __LINE__, "s", "If this is PHP try to remove the byte-code caches for now and try again."); @@ -1068,7 +1093,7 @@ static int fcgi_spawn_connection(server *srv, if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) socket is already used, won't spawn:", - proc->socket); + proc->connection_name); } } @@ -1240,9 +1265,12 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { if ((!buffer_is_empty(host->host) || host->port) && !buffer_is_empty(host->unixsocket)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "either host+port or socket"); - + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + "either host/port or socket have to be set in:", + da->key, "= (", + da_ext->key, " => (", + da_host->key, " ( ..."); + return HANDLER_ERROR; } @@ -1250,8 +1278,12 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { /* unix domain socket */ if (host->unixsocket->used > UNIX_PATH_MAX - 2) { - log_error_write(srv, __FILE__, __LINE__, "s", - "path of the unixdomain socket is too large"); + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + "unixsocket is too long in:", + da->key, "= (", + da_ext->key, " => (", + da_host->key, " ( ..."); + return HANDLER_ERROR; } } else { @@ -1259,21 +1291,20 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { if (buffer_is_empty(host->host) && buffer_is_empty(host->bin_path)) { - log_error_write(srv, __FILE__, __LINE__, "sbbbs", - "missing key (string):", - da->key, - da_ext->key, - da_host->key, - "host"); + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + "host or binpath have to be set in:", + da->key, "= (", + da_ext->key, " => (", + da_host->key, " ( ..."); return HANDLER_ERROR; } else if (host->port == 0) { - log_error_write(srv, __FILE__, __LINE__, "sbbbs", - "missing key (short):", - da->key, - da_ext->key, - da_host->key, - "port"); + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + "port has to be set in:", + da->key, "= (", + da_ext->key, " => (", + da_host->key, " ( ..."); + return HANDLER_ERROR; } } @@ -1308,9 +1339,9 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { if (buffer_is_empty(host->unixsocket)) { proc->port = host->port + pno; } else { - buffer_copy_string_buffer(proc->socket, host->unixsocket); - buffer_append_string(proc->socket, "-"); - buffer_append_long(proc->socket, pno); + buffer_copy_string_buffer(proc->unixsocket, host->unixsocket); + buffer_append_string(proc->unixsocket, "-"); + buffer_append_long(proc->unixsocket, pno); } if (s->debug) { @@ -1346,7 +1377,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { if (buffer_is_empty(host->unixsocket)) { proc->port = host->port; } else { - buffer_copy_string_buffer(proc->socket, host->unixsocket); + buffer_copy_string_buffer(proc->unixsocket, host->unixsocket); } fastcgi_status_init(srv, p->statuskey, host, proc); @@ -1477,14 +1508,13 @@ void fcgi_connection_close(server *srv, handler_ctx *hctx) { status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load); if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sddb", - "release proc:", - hctx->fd, - hctx->proc->pid, hctx->proc->socket); + log_error_write(srv, __FILE__, __LINE__, "ssdsbsd", + "released proc:", + "pid:", hctx->proc->pid, + "socket:", hctx->proc->connection_name, + "load:", hctx->proc->load); } } - - fcgi_proclist_sort_down(srv, hctx->host, hctx->proc); } @@ -1519,6 +1549,7 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) { fdevent_unregister(srv->ev, hctx->fd); close(hctx->fd); srv->cur_fds--; + hctx->fd = -1; } fcgi_requestid_del(srv, p, hctx->request_id); @@ -1528,16 +1559,20 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) { hctx->request_id = 0; hctx->reconnects++; - if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sddb", - "release proc:", - hctx->fd, - hctx->proc->pid, hctx->proc->socket); + if (p->conf.debug > 2) { + if (hctx->proc) { + log_error_write(srv, __FILE__, __LINE__, "sdb", + "release proc for reconnect:", + hctx->proc->pid, hctx->proc->connection_name); + } else { + log_error_write(srv, __FILE__, __LINE__, "sb", + "release proc for reconnect:", + hctx->host->unixsocket); + } } - if (hctx->proc) { + if (hctx->proc && hctx->got_proc) { hctx->proc->load--; - fcgi_proclist_sort_down(srv, hctx->host, hctx->proc); } /* perhaps another host gives us more luck */ @@ -1637,18 +1672,24 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h memset(&fcgi_addr, 0, sizeof(fcgi_addr)); - if (!buffer_is_empty(proc->socket)) { + if (!buffer_is_empty(proc->unixsocket)) { #ifdef HAVE_SYS_UN_H /* use the unix domain socket */ fcgi_addr_un.sun_family = AF_UNIX; - strcpy(fcgi_addr_un.sun_path, proc->socket->ptr); + strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr); #ifdef SUN_LEN servlen = SUN_LEN(&fcgi_addr_un); #else /* stevens says: */ - servlen = proc->socket->used - 1 + sizeof(fcgi_addr_un.sun_family); + servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family); #endif fcgi_addr = (struct sockaddr *) &fcgi_addr_un; + + if (buffer_is_empty(proc->connection_name)) { + /* on remote spawing we have to set the connection-name now */ + buffer_copy_string(proc->connection_name, "unix:"); + buffer_append_string_buffer(proc->connection_name, proc->unixsocket); + } #else return -1; #endif @@ -1665,32 +1706,40 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h servlen = sizeof(fcgi_addr_in); fcgi_addr = (struct sockaddr *) &fcgi_addr_in; + + if (buffer_is_empty(proc->connection_name)) { + /* on remote spawing we have to set the connection-name now */ + buffer_copy_string(proc->connection_name, "tcp:"); + buffer_append_string_buffer(proc->connection_name, host->host); + buffer_append_string(proc->connection_name, ":"); + buffer_append_long(proc->connection_name, proc->port); + } } if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) { if (errno == EINPROGRESS || errno == EALREADY || errno == EINTR) { - if (hctx->conf.debug) { + if (hctx->conf.debug > 2) { log_error_write(srv, __FILE__, __LINE__, "sb", - "connect delayed, will continue later:", host->host); + "connect delayed, will continue later:", proc->connection_name); } return CONNECTION_DELAYED; } else if (errno == EAGAIN) { if (hctx->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sbsd", "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. " "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections." - "The load for this fastcgi backend is:", proc->load); + "The load for this fastcgi backend", proc->connection_name, "is", proc->load); } return CONNECTION_OVERLOADED; } else { - log_error_write(srv, __FILE__, __LINE__, "ssdb", + log_error_write(srv, __FILE__, __LINE__, "sssb", "connect failed:", - strerror(errno), - proc->port, proc->socket); + strerror(errno), "on", + proc->connection_name); return CONNECTION_DEAD; } @@ -2378,12 +2427,10 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { b->used = r + 1; /* one extra for the fake \0 */ b->ptr[b->used - 1] = '\0'; } else { - log_error_write(srv, __FILE__, __LINE__, "ssdsbsbsd", + log_error_write(srv, __FILE__, __LINE__, "ssdsb", "unexpected end-of-file (perhaps the fastcgi process died):", "pid:", proc->pid, - "socket:", proc->socket, - "host:", host->host, - "port:", proc->port); + "socket:", proc->connection_name); return -1; } @@ -2514,222 +2561,97 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { return fin; } -int fcgi_proclist_sort_up(server *srv, fcgi_extension_host *host, fcgi_proc *proc) { - fcgi_proc *p; - - UNUSED(srv); - - /* we have been the smallest of the current list - * and we want to insert the node sorted as soon - * possible - * - * 1 0 0 0 1 1 1 - * | ^ - * | | - * +------+ - * - */ - - /* nothing to sort, only one element */ - if (host->first == proc && proc->next == NULL) return 0; - - for (p = proc; p->next && p->next->load < proc->load; p = p->next); - - /* no need to move something - * - * 1 2 2 2 3 3 3 - * ^ - * | - * + - * - */ - if (p == proc) return 0; - - if (host->first == proc) { - /* we have been the first elememt */ - - host->first = proc->next; - host->first->prev = NULL; - } - - /* disconnect proc */ - - if (proc->prev) proc->prev->next = proc->next; - if (proc->next) proc->next->prev = proc->prev; - - /* proc should be right of p */ - - proc->next = p->next; - proc->prev = p; - if (p->next) p->next->prev = proc; - p->next = proc; -#if 0 - for(p = host->first; p; p = p->next) { - log_error_write(srv, __FILE__, __LINE__, "dd", - p->pid, p->load); - } -#else - UNUSED(srv); -#endif - - return 0; -} - -int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc) { - fcgi_proc *p; - - UNUSED(srv); - - /* we have been the smallest of the current list - * and we want to insert the node sorted as soon - * possible - * - * 0 0 0 0 1 0 1 - * ^ | - * | | - * +----------+ - * - * - * the basic is idea is: - * - the last active fastcgi process should be still - * in ram and is not swapped out yet - * - processes that are not reused will be killed - * after some time by the trigger-handler - * - remember it as: - * everything > 0 is hot - * all unused procs are colder the more right they are - * ice-cold processes are propably unused since more - * than 'unused-timeout', are swaped out and won't be - * reused in the next seconds anyway. - * - */ - - /* nothing to sort, only one element */ - if (host->first == proc && proc->next == NULL) return 0; - - for (p = host->first; p != proc && p->load < proc->load; p = p->next); - - - /* no need to move something - * - * 1 2 2 2 3 3 3 - * ^ - * | - * + - * - */ - if (p == proc) return 0; - - /* we have to move left. If we are already the first element - * we are done */ - if (host->first == proc) return 0; - - /* release proc */ - if (proc->prev) proc->prev->next = proc->next; - if (proc->next) proc->next->prev = proc->prev; - - /* proc should be left of p */ - proc->next = p; - proc->prev = p->prev; - if (p->prev) p->prev->next = proc; - p->prev = proc; - - if (proc->prev == NULL) host->first = proc; -#if 0 - for(p = host->first; p; p = p->next) { - log_error_write(srv, __FILE__, __LINE__, "dd", - p->pid, p->load); - } -#else - UNUSED(srv); -#endif - - return 0; -} - static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) { fcgi_proc *proc; for (proc = host->first; proc; proc = proc->next) { - if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sbdbdddd", + int status; + + if (p->conf.debug > 2) { + log_error_write(srv, __FILE__, __LINE__, "sbdddd", "proc:", - host->host, proc->port, - proc->socket, + proc->connection_name, proc->state, proc->is_local, proc->load, proc->pid); } - if (!proc->is_local) { - /* - * external servers might get disabled - * - * enable the server again, perhaps it is back again - */ - - if ((proc->state == PROC_STATE_DISABLED) && - (srv->cur_ts > proc->disabled_until)) { - proc->state = PROC_STATE_RUNNING; - host->active_procs++; - - fastcgi_status_copy_procname(p->statuskey, host, proc); - buffer_append_string(p->statuskey, ".disabled"); + /* + * if the remote side is overloaded, we check back after <n> seconds + * + */ + switch (proc->state) { + case PROC_STATE_KILLED: + case PROC_STATE_UNSET: + /* this should never happen as long as adaptive spawing is disabled */ + assert(0); - status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 0); + break; + case PROC_STATE_RUNNING: + break; + case PROC_STATE_OVERLOADED: + if (srv->cur_ts <= proc->disabled_until) break; + + proc->state = PROC_STATE_RUNNING; + host->active_procs++; + + log_error_write(srv, __FILE__, __LINE__, "sbdb", + "fcgi-server re-enabled:", + host->host, host->port, + host->unixsocket); + break; + case PROC_STATE_DIED_WAIT_FOR_PID: + /* non-local procs don't have PIDs to wait for */ + if (!proc->is_local) break; - log_error_write(srv, __FILE__, __LINE__, "sbdb", - "fcgi-server re-enabled:", - host->host, host->port, - host->unixsocket); - } - } else { /* the child should not terminate at all */ - int status; - if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) { - switch(waitpid(proc->pid, &status, WNOHANG)) { - case 0: - /* child is still alive */ - break; - case -1: - break; - default: - if (WIFEXITED(status)) { + switch(waitpid(proc->pid, &status, WNOHANG)) { + case 0: + /* child is still alive */ + break; + case -1: + break; + default: + if (WIFEXITED(status)) { #if 0 - log_error_write(srv, __FILE__, __LINE__, "sdsd", - "child exited, pid:", proc->pid, - "status:", WEXITSTATUS(status)); + log_error_write(srv, __FILE__, __LINE__, "sdsd", + "child exited, pid:", proc->pid, + "status:", WEXITSTATUS(status)); #endif - } else if (WIFSIGNALED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child signaled:", - WTERMSIG(status)); - } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child died somehow:", - status); - } - - proc->state = PROC_STATE_DIED; - break; + } else if (WIFSIGNALED(status)) { + log_error_write(srv, __FILE__, __LINE__, "sd", + "child signaled:", + WTERMSIG(status)); + } else { + log_error_write(srv, __FILE__, __LINE__, "sd", + "child died somehow:", + status); } + + proc->state = PROC_STATE_DIED; + break; } + + /* fall through if we have a dead proc now */ + if (proc->state != PROC_STATE_DIED) break; + + case PROC_STATE_DIED: + /* local proc get restarted by us, + * remote ones hopefully by the admin */ + + if (proc->is_local) { + /* we still have connections bound to this proc, + * let them terminate first */ + if (proc->load != 0) break; - /* - * local servers might died, but we restart them - * - */ - if (proc->state == PROC_STATE_DIED && - proc->load == 0) { /* restart the child */ if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd", + log_error_write(srv, __FILE__, __LINE__, "ssbsdsd", "--- fastcgi spawning", - "\n\tport:", host->port, - "\n\tsocket", host->unixsocket, + "\n\tsocket", proc->connection_name, "\n\tcurrent:", 1, "/", host->min_procs); } @@ -2738,9 +2660,17 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h "ERROR: spawning fcgi failed."); return HANDLER_ERROR; } - - fcgi_proclist_sort_down(srv, host, proc); + } else { + if (srv->cur_ts <= proc->disabled_until) break; + + proc->state = PROC_STATE_RUNNING; + host->active_procs++; + + log_error_write(srv, __FILE__, __LINE__, "sb", + "fcgi-server re-enabled:", + proc->connection_name); } + break; } } @@ -2751,6 +2681,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { plugin_data *p = hctx->plugin_data; fcgi_extension_host *host= hctx->host; connection *con = hctx->remote_conn; + fcgi_proc *proc; int ret; @@ -2763,6 +2694,10 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { host->host->used, host->port, host->unixsocket->used); + + hctx->proc->disabled_until = srv->cur_ts + 10; + hctx->proc->state = PROC_STATE_DIED; + return HANDLER_ERROR; } @@ -2776,18 +2711,29 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { log_error_write(srv, __FILE__, __LINE__, "ss", "getsockopt failed:", strerror(errno)); + hctx->proc->disabled_until = srv->cur_ts + 10; + hctx->proc->state = PROC_STATE_DIED; + return HANDLER_ERROR; } if (socket_error != 0) { if (!hctx->proc->is_local || p->conf.debug) { /* local procs get restarted */ - log_error_write(srv, __FILE__, __LINE__, "sssd", + log_error_write(srv, __FILE__, __LINE__, "sssb", "establishing connection failed:", strerror(socket_error), - "port:", hctx->proc->port); + "socket:", hctx->proc->connection_name); } - hctx->proc->disabled_until = srv->cur_ts + 10; + hctx->proc->disabled_until = srv->cur_ts + 5; + + if (hctx->proc->is_local) { + hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID; + } else { + hctx->proc->state = PROC_STATE_DIED; + } + + hctx->proc->state = PROC_STATE_DIED; fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string(p->statuskey, ".died"); @@ -2807,18 +2753,27 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { break; case FCGI_STATE_INIT: /* do we have a running process for this host (max-procs) ? */ + hctx->proc = NULL; - for (hctx->proc = hctx->host->first; - hctx->proc && hctx->proc->state != PROC_STATE_RUNNING; - hctx->proc = hctx->proc->next); + for (proc = hctx->host->first; + proc && proc->state != PROC_STATE_RUNNING; + proc = proc->next); /* all childs are dead */ - if (hctx->proc == NULL) { + if (proc == NULL) { hctx->fde_ndx = -1; return HANDLER_ERROR; } + hctx->proc = proc; + + /* check the other procs if they have a lower load */ + for (proc = proc->next; proc; proc = proc->next) { + if (proc->state != PROC_STATE_RUNNING) continue; + if (proc->load < hctx->proc->load) hctx->proc = proc; + } + ret = host->unixsocket->used ? AF_UNIX : AF_INET; if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) { @@ -2863,14 +2818,14 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { /* cool down the backend, it is overloaded * -> EAGAIN */ - log_error_write(srv, __FILE__, __LINE__, "ssdsdb", + log_error_write(srv, __FILE__, __LINE__, "ssdsd", "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:", "reconnects:", hctx->reconnects, - "load:", host->load, - host->unixsocket); + "load:", host->load); hctx->proc->disabled_until = srv->cur_ts + 2; + hctx->proc->state = PROC_STATE_OVERLOADED; fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string(p->statuskey, ".overloaded"); @@ -2883,11 +2838,21 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { * - ECONNREFUSED for tcp-ip sockets * - ENOENT for unix-domain-sockets * - * for check if the host is back in 10 seconds + * for check if the host is back in 5 seconds * */ - hctx->proc->disabled_until = srv->cur_ts + 10; - + hctx->proc->disabled_until = srv->cur_ts + 5; + if (hctx->proc->is_local) { + hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID; + } else { + hctx->proc->state = PROC_STATE_DIED; + } + + log_error_write(srv, __FILE__, __LINE__, "ssdsd", + "backend died, we disable it for a 5 seconds and send the request to another backend instead:", + "reconnects:", hctx->reconnects, + "load:", host->load); + fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string(p->statuskey, ".died"); @@ -2919,24 +2884,27 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { status_counter_inc(srv, CONST_BUF_LEN(p->statuskey)); + /* the proc-load */ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string(p->statuskey, ".load"); status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load); + /* the host-load */ + fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL); + buffer_append_string(p->statuskey, ".load"); + + status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load); + if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sddbdd", + log_error_write(srv, __FILE__, __LINE__, "ssdsbsd", "got proc:", - hctx->fd, - hctx->proc->pid, - hctx->proc->socket, - hctx->proc->port, - hctx->proc->load); + "pid:", hctx->proc->pid, + "socket:", hctx->proc->connection_name, + "load:", hctx->proc->load); } /* move the proc-list entry down the list */ - fcgi_proclist_sort_up(srv, hctx->host, hctx->proc); - if (hctx->request_id == 0) { hctx->request_id = fcgi_requestid_new(srv, p); } else { @@ -3098,43 +3066,7 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { if (hctx->state == FCGI_STATE_INIT || hctx->state == FCGI_STATE_CONNECT_DELAYED) { - /* connect() or getsockopt() failed, - * restart the request-handling - */ - if (proc) { - if (proc->is_local) { - - if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sbdb", - "connect() to fastcgi failed, restarting the request-handling:", - host->host, - proc->port, - proc->socket); - } - - /* - * several hctx might reference the same proc - * - * Only one of them should mark the proc as dead all the other - * ones should just take a new one. - * - * If a new proc was started with the old struct this might lead - * the mark a perfect proc as dead otherwise - * - */ - if (proc->state == PROC_STATE_RUNNING && - hctx->pid == proc->pid) { - proc->state = PROC_STATE_DIED_WAIT_FOR_PID; - } - } else { - proc->state = PROC_STATE_DISABLED; - } - host->active_procs--; - fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); - buffer_append_string(p->statuskey, ".disabled"); - - status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 1); - } + if (proc) host->active_procs--; fcgi_restart_dead_procs(srv, p, host); @@ -3247,18 +3179,18 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { } if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd", + log_error_write(srv, __FILE__, __LINE__, "ssbsdsd", "--- fastcgi spawning", - "\n\tport:", host->port, - "\n\tsocket", host->unixsocket, + "\n\tsocket", proc->connection_name, "\n\tcurrent:", 1, "/", host->min_procs); } if (fcgi_spawn_connection(srv, p, host, proc)) { - /* child died */ + /* respawning failed, retry later */ proc->state = PROC_STATE_DIED; - } else { - fcgi_proclist_sort_down(srv, host, proc); + + log_error_write(srv, __FILE__, __LINE__, "s", + "respawning failed, will retry later"); } break; @@ -3272,18 +3204,18 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { hctx->reconnects < 5) { fcgi_reconnect(srv, hctx); - log_error_write(srv, __FILE__, __LINE__, "ssdsd", - "response not received, request not sent, reconnecting.", - "connection-fd:", con->fd, - "fcgi-fd:", hctx->fd); + log_error_write(srv, __FILE__, __LINE__, "ssbsbs", + "response not received, request not sent", + "on socket:", proc->connection_name, + "for", con->uri.path, ", reconnecting"); return HANDLER_WAIT_FOR_FD; } - - log_error_write(srv, __FILE__, __LINE__, "sosdsd", + + log_error_write(srv, __FILE__, __LINE__, "sosbsbs", "response not received, request sent:", hctx->wb->bytes_out, - "connection-fd:", con->fd, - "fcgi-fd:", hctx->fd); + "on socket:", proc->connection_name, + "for", con->uri.path, ", closing connection"); fcgi_connection_close(srv, hctx); @@ -3295,10 +3227,10 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { /* response might have been already started, kill the connection */ fcgi_connection_close(srv, hctx); - log_error_write(srv, __FILE__, __LINE__, "ssdsd", - "response already sent out, termination connection", - "connection-fd:", con->fd, - "fcgi-fd:", hctx->fd); + log_error_write(srv, __FILE__, __LINE__, "ssbsbs", + "response already sent out, but backend returned error", + "on socket:", proc->connection_name, + "for", con->uri.path, ", terminating connection"); connection_set_state(srv, con, CON_STATE_ERROR); } @@ -3351,7 +3283,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", "error: unexpected close of fastcgi connection for", con->uri.path, - "(no fastcgi process on host: ", + "(no fastcgi process on host:", host->host, ", port: ", host->port, @@ -3425,9 +3357,7 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i fn = uri_path_handler ? con->uri.path : con->physical.path; - if (fn->used == 0) { - return HANDLER_ERROR; - } + if (buffer_is_empty(fn)) return HANDLER_GO_ON; s_len = fn->used - 1; @@ -3519,14 +3449,23 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i /* sorry, we don't have a server alive for this ext */ buffer_reset(con->physical.path); con->http_status = 500; - - log_error_write(srv, __FILE__, __LINE__, "sb", - "no fcgi-handler found for:", - fn); + + /* only send the 'no handler' once */ + if (!extension->note_is_sent) { + extension->note_is_sent = 1; + + log_error_write(srv, __FILE__, __LINE__, "sbsbs", + "all handlers for ", con->uri.path, + "on", extension->key, + "are down."); + } return HANDLER_FINISHED; } + /* a note about no handler is not sent yey */ + extension->note_is_sent = 0; + /* * if check-local is disabled, use the uri.path handler * @@ -3708,48 +3647,46 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { host->num_procs < host->max_procs && (sum_load / host->num_procs) > host->max_load_per_proc) { /* overload, spawn new child */ - fcgi_proc *fp = NULL; - if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "overload detected, spawning a new child"); } - for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next); + for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next); - if (fp) { - if (fp == host->unused_procs) host->unused_procs = fp->next; + if (proc) { + if (proc == host->unused_procs) host->unused_procs = proc->next; - if (fp->next) fp->next->prev = NULL; + if (proc->next) proc->next->prev = NULL; host->max_id++; } else { - fp = fastcgi_process_init(); - fp->id = host->max_id++; + proc = fastcgi_process_init(); + proc->id = host->max_id++; } host->num_procs++; if (buffer_is_empty(host->unixsocket)) { - fp->port = host->port + fp->id; + proc->port = host->port + proc->id; } else { - buffer_copy_string_buffer(fp->socket, host->unixsocket); - buffer_append_string(fp->socket, "-"); - buffer_append_long(fp->socket, fp->id); + buffer_copy_string_buffer(proc->unixsocket, host->unixsocket); + buffer_append_string(proc->unixsocket, "-"); + buffer_append_long(proc->unixsocket, proc->id); } - if (fcgi_spawn_connection(srv, p, host, fp)) { + if (fcgi_spawn_connection(srv, p, host, proc)) { log_error_write(srv, __FILE__, __LINE__, "s", "ERROR: spawning fcgi failed."); return HANDLER_ERROR; } - fp->prev = NULL; - fp->next = host->first; + proc->prev = NULL; + proc->next = host->first; if (host->first) { - host->first->prev = fp; + host->first->prev = proc; } - host->first = fp; + host->first = proc; } for (proc = host->first; proc; proc = proc->next) { @@ -3764,7 +3701,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "ssbsd", "idle-timeout reached, terminating child:", - "socket:", proc->socket, + "socket:", proc->connection_name, "pid", proc->pid); } @@ -3786,7 +3723,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { log_error_write(srv, __FILE__, __LINE__, "ssbsd", "killed:", - "socket:", proc->socket, + "socket:", proc->connection_name, "pid", proc->pid); host->num_procs--; @@ -3827,7 +3764,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { if (proc->state != PROC_STATE_KILLED) { log_error_write(srv, __FILE__, __LINE__, "sdb", "child exited:", - WEXITSTATUS(status), proc->socket); + WEXITSTATUS(status), proc->connection_name); } } else if (WIFSIGNALED(status)) { if (WTERMSIG(status) != SIGTERM) { |