From d66cbe9577ac092163babe6b816205fd14f1bc5a Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Sun, 16 Jul 2017 00:13:37 -0400 Subject: [PATCH] [core] adaptive spawning for socket backend procs (fixes #1162) *experimental* enable adaptive spawning for socket backend processes new feature will allow "min-procs" => "0" and will spawn a backend upon receipt of a request, if no backends are currently running. This may be useful on resource-limited systems where there is a seldom-used resource-intensive backend, such as home router configuration web pages. The first request may be slower as the backend is starting up, but then subsequent requests within "idle-timeout" will hit the (temporarily) persistent backend for faster responses. x-ref: "Adaptive spawning with min-procs=>0" https://redmine.lighttpd.net/issues/1162 --- src/gw_backend.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/gw_backend.c b/src/gw_backend.c index c74841e7..7b67f9a5 100644 --- a/src/gw_backend.c +++ b/src/gw_backend.c @@ -228,6 +228,7 @@ static int gw_extension_insert(gw_exts *ext, buffer *key, gw_host *fh) { static void gw_proc_connect_success(server *srv, gw_host *host, gw_proc *proc, int debug) { gw_proc_tag_inc(srv, host, proc, CONST_STR_LEN(".connected")); + proc->last_used = srv->cur_ts; if (debug) { log_error_write(srv, __FILE__, __LINE__, "ssdsbsd", @@ -912,6 +913,16 @@ static gw_host * gw_host_get(server *srv, connection *con, gw_extension *extensi } return host; + } else if (0 == srv->srvconf.max_worker) { + /* special-case adaptive spawning and 0 == host->min_procs */ + for (k = 0; k < extension->used; ++k) { + host = extension->hosts[k]; + if (0 == host->min_procs && 0 == host->num_procs + && !buffer_string_is_empty(host->bin_path)) { + gw_proc_spawn(srv, host, debug); + if (host->num_procs) return host; + } + } } /* all hosts are down */ @@ -1214,7 +1225,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, data_unset *du, size { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */ { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */ - { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */ + { "min-procs", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 */ { "max-procs", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */ { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */ { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */ @@ -1402,11 +1413,15 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, data_unset *du, size host->args.ptr[3] = NULL; } - /* HACK: just to make sure the adaptive spawing is disabled */ - host->min_procs = host->max_procs; - if (host->min_procs > host->max_procs) - host->max_procs = host->min_procs; + host->min_procs = host->max_procs; + if (host->min_procs!= host->max_procs + && 0 != srv->srvconf.max_worker) { + host->min_procs = host->max_procs; + log_error_write(srv, __FILE__, __LINE__, "s", + "adaptive backend spawning disabled " + "(server.max_worker is non-zero)"); + } if (host->max_load_per_proc < 1) host->max_load_per_proc = 0; @@ -1420,7 +1435,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, data_unset *du, size "\n\tmax-procs:", host->max_procs); } - for (size_t pno = 0; pno < host->max_procs; ++pno) { + for (size_t pno = 0; pno < host->min_procs; ++pno) { gw_proc *proc = gw_proc_init(); proc->id = host->num_procs++; host->max_id++; @@ -1975,6 +1990,7 @@ static handler_t gw_recv_response(server *srv, gw_handler_ctx *hctx) { physpath = con->physical.path; } + proc->last_used = srv->cur_ts; gw_backend_close(srv, hctx); handler_ctx_clear(hctx); @@ -2358,7 +2374,7 @@ static void gw_handle_trigger_host(server *srv, gw_host *host, int debug) { gw_proc *proc; time_t idle_timestamp; - unsigned long sum_load = 0; + int overload = 1; for (proc = host->first; proc; proc = proc->next) { gw_proc_waitpid(srv, host, proc); @@ -2366,14 +2382,18 @@ static void gw_handle_trigger_host(server *srv, gw_host *host, int debug) { gw_restart_dead_procs(srv, host, debug); + /* check if adaptive spawning enabled */ + if (host->min_procs == host->max_procs) return; if (buffer_string_is_empty(host->bin_path)) return; for (proc = host->first; proc; proc = proc->next) { - sum_load += proc->load; + if (proc->load <= host->max_load_per_proc) { + overload = 0; + break; + } } - if (host->num_procs && host->num_procs < host->max_procs - && (sum_load / host->num_procs) > host->max_load_per_proc) { + if (overload && host->num_procs && host->num_procs < host->max_procs) { /* overload, spawn new child */ if (debug) { log_error_write(srv, __FILE__, __LINE__, "s",