-1 in concept.
The server is not architected to handle dynamically changing runtime parameters. I
have
worked on network servers with dynamic runtime configuration (more than one) and it is
a
support nightmare. This will add a lot of complexity and non intuitive bahaviour to the
server for relatively little benefit. If lots of Apache users come out in support for
function like this, I'll reconsider.
Bill
>
> Attached is a patch that adds more dynamic configuration.
> It places some of the MPM variables such as 'ap_max_daemons_limit',
> 'ap_daemons_limit', 'ap_daemons_min_free' and 'ap_daemons_max_free'
> in the scoreboard. This enables management modules to do
> dynamic (runtime) configuration without requiring a restart of the
> Apache HTTP server.
>
>
> How is it done:
> 1) The patch adds a hook after the creation of the scoreboard
> which is used by the MPM to transfer the variables in
> the scoreboard and allows a management modules to change
> those.
> 2) The MPM during its server maintenance (or spawning of extra
> processes)
> use the variables that are now in the scoreboard.
> The children are not influenced in performance from this
> for the variables: 'ap_max_daemons_limit',
> 'ap_daemons_limit', 'ap_daemons_min_free' and 'ap_daemons_max_free'.
> 3) The a child uses now the 'max_requests_per_child' from the
> scoreboard.
> Which is has little or no impact on the request processing.
>
> This patch works only for the PREFORK MPM. If it is seen as usefull,
> we can do the same with the other MPMs and, for instance, add
> 'ap_threads_min_spare' in the scoreboard as well to allow dynamic
> configuration.
>
> Let me know what you think of it.
>
> Harrie
> --
> address: Covalent Technologies, 645 Howard St, San Francisco, CA - 94105
> phone: +1-415-536-5221 fax:+1-415-536-5210
> personal website: http://www.lisanza.net/
--------------------------------------------------------------------------------
> diff -ru ../httpd-2.0/include/ap_mpm.h ./include/ap_mpm.h
> --- ../httpd-2.0/include/ap_mpm.h Wed Jun 27 10:43:28 2001
> +++ ./include/ap_mpm.h Tue Jul 3 14:18:43 2001
> @@ -169,6 +169,7 @@
> #define AP_MPMQ_MAX_SPARE_DAEMONS 9 /* Max # of spare daemons */
> #define AP_MPMQ_MAX_SPARE_THREADS 10 /* Max # of spare threads */
> #define AP_MPMQ_MAX_REQUESTS_DEAMON 11 /* Max # of requests per daemon */
> +#define AP_MPMQ_DAEMONS_USED 12 /* Used # of scoreboard slots */
>
>
> /**
> diff -ru ../httpd-2.0/include/scoreboard.h ./include/scoreboard.h
> --- ../httpd-2.0/include/scoreboard.h Sat Jun 9 17:37:59 2001
> +++ ./include/scoreboard.h Thu Jul 5 09:09:19 2001
> @@ -73,6 +73,8 @@
> #include "apr_thread_proc.h"
> #include "apr_portable.h"
>
> +AP_DECLARE_HOOK(void,setup_shared_info,(apr_pool_t *pconf,apr_pool_t
>*plog,server_rec
*s));
> +
> /* Scoreboard info on a process is, for now, kept very brief ---
> * just status value and pid (the latter so that the caretaker process
> * can properly update the scoreboard when a process dies). We may want
> @@ -169,6 +171,11 @@
> ap_scoreboard_e sb_type;
> ap_generation_t running_generation; /* the generation of children which
> * should still be serving requests. */
> + int ap_max_daemons_limit; /* used # of scoreboard slots */
> + int ap_daemons_limit; /* max # of clients */
> + int ap_daemons_max_free; /* max # of spare servers */
> + int ap_daemons_min_free; /* min # of spare servers */
> + int ap_max_requests_per_child; /* max # of requests per child */
> } global_score;
>
> /* stuff which the parent generally writes and the children rarely read */
> diff -ru ../httpd-2.0/server/mpm/prefork/mpm.h ./server/mpm/prefork/mpm.h
> --- ../httpd-2.0/server/mpm/prefork/mpm.h Wed Jun 6 17:09:16 2001
> +++ ./server/mpm/prefork/mpm.h Tue Jul 3 13:56:27 2001
> @@ -75,7 +75,6 @@
> #define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
>
> extern int ap_threads_per_child;
> -extern int ap_max_daemons_limit;
> extern server_rec *ap_server_conf;
> extern char ap_coredump_dir[MAX_STRING_LEN];
> #endif /* APACHE_MPM_PREFORK_H */
> diff -ru ../httpd-2.0/server/mpm/prefork/prefork.c ./server/mpm/prefork/prefork.c
> --- ../httpd-2.0/server/mpm/prefork/prefork.c Wed Jun 27 10:43:39 2001
> +++ ./server/mpm/prefork/prefork.c Thu Jul 5 11:37:25 2001
> @@ -151,7 +151,6 @@
> * to deal with MaxClients changes across SIGWINCH restarts. We use this
> * value to optimize routines that have to scan the entire scoreboard.
> */
> -int ap_max_daemons_limit = -1;
> server_rec *ap_server_conf;
>
> char ap_coredump_dir[MAX_STRING_LEN];
> @@ -316,7 +315,10 @@
> {
> switch(query_code){
> case AP_MPMQ_MAX_DAEMONS:
> - *result = ap_daemons_limit;
> + *result = ap_scoreboard_image->global.ap_daemons_limit;
> + return APR_SUCCESS;
> + case AP_MPMQ_DAEMONS_USED:
> + *result = ap_scoreboard_image->global.ap_max_daemons_limit;
> return APR_SUCCESS;
> case AP_MPMQ_IS_THREADED:
> *result = AP_MPMQ_NOT_SUPPORTED;
> @@ -334,19 +336,19 @@
> *result = 0;
> return APR_SUCCESS;
> case AP_MPMQ_MIN_SPARE_DEAMONS:
> - *result = ap_daemons_min_free;
> + *result = ap_scoreboard_image->global.ap_daemons_min_free;
> return APR_SUCCESS;
> case AP_MPMQ_MIN_SPARE_THREADS:
> *result = 0;
> return APR_SUCCESS;
> case AP_MPMQ_MAX_SPARE_DAEMONS:
> - *result = ap_daemons_max_free;
> + *result = ap_scoreboard_image->global.ap_daemons_max_free;
> return APR_SUCCESS;
> case AP_MPMQ_MAX_SPARE_THREADS:
> *result = 0;
> return APR_SUCCESS;
> case AP_MPMQ_MAX_REQUESTS_DEAMON:
> - *result = ap_max_requests_per_child;
> + *result = ap_scoreboard_image->global.ap_max_requests_per_child;
> return APR_SUCCESS;
> }
> return APR_ENOTIMPL;
> @@ -361,7 +363,7 @@
> {
> int n, pid;
>
> - for (n = 0; n < ap_max_daemons_limit; ++n) {
> + for (n = 0; n < ap_scoreboard_image->global.ap_max_daemons_limit; ++n) {
> ap_sync_scoreboard_image();
> if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD &&
> kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) {
> @@ -598,8 +600,8 @@
>
> apr_pool_clear(ptrans);
>
> - if ((ap_max_requests_per_child > 0
> - && requests_this_child++ >= ap_max_requests_per_child)) {
> + if ((ap_scoreboard_image->global.ap_max_requests_per_child > 0
> + && requests_this_child++ >=
ap_scoreboard_image->global.ap_max_requests_per_child)) {
> clean_child_exit(0);
> }
>
> @@ -836,8 +838,8 @@
> {
> int pid;
>
> - if (slot + 1 > ap_max_daemons_limit) {
> - ap_max_daemons_limit = slot + 1;
> + if (slot + 1 > ap_scoreboard_image->global.ap_max_daemons_limit) {
> + ap_scoreboard_image->global.ap_max_daemons_limit = slot + 1;
> }
>
> if (one_process) {
> @@ -920,7 +922,7 @@
> {
> int i;
>
> - for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
> + for (i = 0; number_to_start && i < ap_scoreboard_image->global.ap_daemons_limit;
++i) {
> if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
> continue;
> }
> @@ -964,10 +966,10 @@
> total_non_dead = 0;
>
> ap_sync_scoreboard_image();
> - for (i = 0; i < ap_daemons_limit; ++i) {
> + for (i = 0; i < ap_scoreboard_image->global.ap_daemons_limit; ++i) {
> int status;
>
> - if (i >= ap_max_daemons_limit && free_length == idle_spawn_rate)
> + if (i >= ap_scoreboard_image->global.ap_max_daemons_limit && free_length ==
idle_spawn_rate)
> break;
> ws = &ap_scoreboard_image->servers[i][0];
> status = ws->status;
> @@ -1000,8 +1002,8 @@
> last_non_dead = i;
> }
> }
> - ap_max_daemons_limit = last_non_dead + 1;
> - if (idle_count > ap_daemons_max_free) {
> + ap_scoreboard_image->global.ap_max_daemons_limit = last_non_dead + 1;
> + if (idle_count > ap_scoreboard_image->global.ap_daemons_max_free) {
> /* kill off one child... we use the pod because that'll cause it to
> * shut down gracefully, in case it happened to pick up a request
> * while we were counting
> @@ -1009,7 +1011,7 @@
> ap_mpm_pod_signal(pod);
> idle_spawn_rate = 1;
> }
> - else if (idle_count < ap_daemons_min_free) {
> + else if (idle_count < ap_scoreboard_image->global.ap_daemons_min_free) {
> /* terminate the free list */
> if (free_length == 0) {
> /* only report this condition once */
> @@ -1110,9 +1112,13 @@
> return 1;
> }
>
> + if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */
> + ap_daemons_max_free = ap_daemons_min_free + 1;
> +
> SAFE_ACCEPT(accept_mutex_init(pconf));
> if (!is_graceful) {
> ap_create_scoreboard(pconf, SB_SHARED);
> + ap_run_setup_shared_info(pconf, plog, s);
> }
> #ifdef SCOREBOARD_FILE
> else {
> @@ -1123,9 +1129,6 @@
>
> set_signals();
>
> - if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */
> - ap_daemons_max_free = ap_daemons_min_free + 1;
> -
> /* If we're doing a graceful_restart then we're going to see a lot
> * of children exiting immediately when we get into the main loop
> * below (because we just sent them SIGWINCH). This happens pretty
> @@ -1135,8 +1138,8 @@
> * supposed to start up without the 1 second penalty between each fork.
> */
> remaining_children_to_start = ap_daemons_to_start;
> - if (remaining_children_to_start > ap_daemons_limit) {
> - remaining_children_to_start = ap_daemons_limit;
> + if (remaining_children_to_start > ap_scoreboard_image->global.ap_daemons_limit)
>{
> + remaining_children_to_start = ap_scoreboard_image->global.ap_daemons_limit;
> }
> if (!is_graceful) {
> startup_children(remaining_children_to_start);
> @@ -1176,7 +1179,7 @@
> (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(child_slot), SERVER_DEAD,
> (request_rec *) NULL);
> if (remaining_children_to_start
> - && child_slot < ap_daemons_limit) {
> + && child_slot < ap_scoreboard_image->global.ap_daemons_limit) {
> /* we're still doing a 1-for-1 replacement of dead
> * children with new children
> */
> @@ -1267,7 +1270,7 @@
> ap_scoreboard_image->global.running_generation = ap_my_generation;
> update_scoreboard_global();
>
> - for (index = 0; index < ap_daemons_limit; ++index) {
> + for (index = 0; index < ap_scoreboard_image->global.ap_daemons_limit; ++index) {
> ap_scoreboard_image->parent[index].process_status = SB_IDLE_DIE;
> }
>
> @@ -1276,7 +1279,7 @@
> "Graceful restart requested, doing restart");
>
> /* kill off the idle ones */
> - ap_mpm_pod_killpg(pod, ap_daemons_limit);
> + ap_mpm_pod_killpg(pod, ap_scoreboard_image->global.ap_daemons_limit);
>
> #ifndef SCOREBOARD_FILE
> /* This is mostly for debugging... so that we know what is still
> @@ -1285,7 +1288,7 @@
> * corruption too easily.
> */
> ap_sync_scoreboard_image();
> - for (index = 0; index < ap_daemons_limit; ++index) {
> + for (index = 0; index < ap_scoreboard_image->global.ap_daemons_limit; ++index) {
> if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) {
> ap_scoreboard_image->servers[index][0].status = SERVER_GRACEFUL;
> }
> @@ -1339,6 +1342,15 @@
> apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
> }
>
> +static void prefork_init_shared(apr_pool_t *pconf, apr_pool_t *plog, server_rec *s)
> +{
> + ap_scoreboard_image->global.ap_max_daemons_limit = -1;
> + ap_scoreboard_image->global.ap_daemons_limit = ap_daemons_limit;
> + ap_scoreboard_image->global.ap_daemons_max_free = ap_daemons_max_free;
> + ap_scoreboard_image->global.ap_daemons_min_free = ap_daemons_min_free;
> + ap_scoreboard_image->global.ap_max_requests_per_child =
>ap_max_requests_per_child;
> +}
> +
> static void prefork_hooks(apr_pool_t *p)
> {
> #ifdef AUX3
> @@ -1346,6 +1358,7 @@
> #endif
>
> ap_hook_pre_config(prefork_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
> + ap_hook_setup_shared_info(prefork_init_shared, NULL, NULL, APR_HOOK_MIDDLE);
> }
>
> static const char *set_pidfile(cmd_parms *cmd, void *dummy, const char *arg)
> diff -ru ../httpd-2.0/server/scoreboard.c ./server/scoreboard.c
> --- ../httpd-2.0/server/scoreboard.c Mon May 21 18:31:12 2001
> +++ ./server/scoreboard.c Tue Jul 3 13:30:35 2001
> @@ -84,6 +84,14 @@
> AP_DECLARE_DATA int ap_extended_status = 0;
> AP_DECLARE_DATA apr_time_t ap_restart_time = 0;
>
> +APR_HOOK_STRUCT(
> + APR_HOOK_LINK(setup_shared_info)
> +)
> +
> +AP_IMPLEMENT_HOOK_VOID(setup_shared_info,
> + (apr_pool_t *pconf, apr_pool_t *plog, server_rec *s),
> + (pconf,plog,s))
> +
> #if APR_HAS_SHARED_MEMORY
> #include "apr_shmem.h"
> static apr_shmem_t *scoreboard_shm = NULL;
>
>