From 4669bc745bc82de3022d7370eca72091c83e205f Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Thu, 20 Nov 2014 16:26:04 +0000 Subject: [PATCH] mpm_event(opt), mpm_worker, mpm_prefork: follow up to r1635521, r1640161. Retain num_buckets and max_buckets accross restarts so that we can determine whether new buckets were allocated and set their idle_spawn_rate at the same level as the existing ones (max). Also, adjust ap_daemons_limit and ap_daemons_to_start lower bounds at mpm_run() time, once num_buckets is available for the current generation (previously done at check_config time, hence before num_buckets is computed, and then with the previous generation's value). git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1640763 13f79535-47bb-0310-9956-ffa450edef68 --- server/mpm/event/event.c | 104 +++++++++++++++++---------------- server/mpm/eventopt/eventopt.c | 100 ++++++++++++++++--------------- server/mpm/prefork/prefork.c | 30 ++++------ server/mpm/worker/worker.c | 101 +++++++++++++++++--------------- 4 files changed, 172 insertions(+), 163 deletions(-) diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index a5e312491b..4635a2e524 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -350,15 +350,20 @@ typedef struct event_retained_data { /* * idle_spawn_rate is the number of children that will be spawned on the * next maintenance cycle if there aren't enough idle servers. It is - * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by - * without the need to spawn. + * maintained per listeners bucket, doubled up to MAX_SPAWN_RATE, and + * reset only when a cycle goes by without the need to spawn. */ - int *idle_spawn_rate, - idle_spawn_rate_len; + int *idle_spawn_rate; #ifndef MAX_SPAWN_RATE #define MAX_SPAWN_RATE (32) #endif int hold_off_on_exponential_spawning; + /* + * Current number of listeners buckets and maximum reached accross + * restarts (to size retained data according to dynamic num_buckets, + * eg. idle_spawn_rate). + */ + int num_buckets, max_buckets; } event_retained_data; static event_retained_data *retained; @@ -366,7 +371,6 @@ typedef struct event_child_bucket { ap_pod_t *pod; ap_listen_rec *listeners; } event_child_bucket; -static int num_buckets; /* Number of listeners buckets */ static event_child_bucket *all_buckets, /* All listeners buckets */ *my_bucket; /* Current child bucket */ @@ -2425,7 +2429,7 @@ static void child_main(int child_num_arg, int child_bucket) apr_pool_create(&pchild, pconf); /* close unused listeners and pods */ - for (i = 0; i < num_buckets; i++) { + for (i = 0; i < retained->num_buckets; i++) { if (i != child_bucket) { ap_close_listeners_ex(all_buckets[i].listeners); ap_mpm_podx_close(all_buckets[i].pod); @@ -2664,14 +2668,14 @@ static void startup_children(int number_to_start) if (ap_scoreboard_image->parent[i].pid != 0) { continue; } - if (make_child(ap_server_conf, i, i % num_buckets) < 0) { + if (make_child(ap_server_conf, i, i % retained->num_buckets) < 0) { break; } --number_to_start; } } -static void perform_idle_server_maintenance(int child_bucket) +static void perform_idle_server_maintenance(int child_bucket, int num_buckets) { int i, j; int idle_thread_count; @@ -2845,8 +2849,8 @@ static void perform_idle_server_maintenance(int child_bucket) if (retained->hold_off_on_exponential_spawning) { --retained->hold_off_on_exponential_spawning; } - else if (retained->idle_spawn_rate[child_bucket] < - MAX_SPAWN_RATE / num_buckets) { + else if (retained->idle_spawn_rate[child_bucket] + < MAX_SPAWN_RATE / num_buckets) { retained->idle_spawn_rate[child_bucket] *= 2; } } @@ -2856,7 +2860,7 @@ static void perform_idle_server_maintenance(int child_bucket) } } -static void server_main_loop(int remaining_children_to_start) +static void server_main_loop(int remaining_children_to_start, int num_buckets) { ap_generation_t old_gen; int child_slot; @@ -2972,15 +2976,15 @@ static void server_main_loop(int remaining_children_to_start) } for (i = 0; i < num_buckets; i++) { - perform_idle_server_maintenance(i); + perform_idle_server_maintenance(i, num_buckets); } } } static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) { + int num_buckets = retained->num_buckets; int remaining_children_to_start; - int i; ap_log_pid(pconf, ap_pid_fname); @@ -2999,7 +3003,13 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) restart_pending = shutdown_pending = 0; set_signals(); - /* Don't thrash... */ + /* Don't thrash since num_buckets depends on the + * system and the number of online CPU cores... + */ + if (ap_daemons_limit < num_buckets) + ap_daemons_limit = num_buckets; + if (ap_daemons_to_start < num_buckets) + ap_daemons_to_start = num_buckets; if (min_spare_threads < threads_per_child * num_buckets) min_spare_threads = threads_per_child * num_buckets; if (max_spare_threads < min_spare_threads + threads_per_child * num_buckets) @@ -3038,7 +3048,7 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) mpm_state = AP_MPMQ_RUNNING; - server_main_loop(remaining_children_to_start); + server_main_loop(remaining_children_to_start, num_buckets); mpm_state = AP_MPMQ_STOPPING; if (shutdown_pending && !retained->is_graceful) { @@ -3178,6 +3188,7 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog, { int startup = 0; int level_flags = 0; + int num_buckets = 0; ap_listen_rec **listen_buckets; apr_status_t rv; int i; @@ -3200,9 +3211,9 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog, if (one_process) { num_buckets = 1; } - else if (!retained->is_graceful) { /* Preserve the number of buckets - on graceful restarts. */ - num_buckets = 0; + else if (retained->is_graceful) { + /* Preserve the number of buckets on graceful restarts. */ + num_buckets = retained->num_buckets; } if ((rv = ap_duplicate_listeners(pconf, ap_server_conf, &listen_buckets, &num_buckets))) { @@ -3211,8 +3222,8 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog, "could not duplicate listeners"); return DONE; } - all_buckets = apr_pcalloc(pconf, num_buckets * - sizeof(event_child_bucket)); + + all_buckets = apr_pcalloc(pconf, num_buckets * sizeof(*all_buckets)); for (i = 0; i < num_buckets; i++) { if (!one_process && /* no POD in one_process mode */ (rv = ap_mpm_podx_open(pconf, &all_buckets[i].pod))) { @@ -3224,21 +3235,34 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog, all_buckets[i].listeners = listen_buckets[i]; } - if (retained->idle_spawn_rate_len < num_buckets) { - int *new_ptr, new_len; - new_len = retained->idle_spawn_rate_len * 2; - if (new_len < num_buckets) { - new_len = num_buckets; + if (retained->max_buckets < num_buckets) { + int new_max, *new_ptr; + new_max = retained->max_buckets * 2; + if (new_max < num_buckets) { + new_max = num_buckets; } - new_ptr = (int *)apr_palloc(ap_pglobal, new_len * sizeof(int)); + new_ptr = (int *)apr_palloc(ap_pglobal, new_max * sizeof(int)); memcpy(new_ptr, retained->idle_spawn_rate, - retained->idle_spawn_rate_len * sizeof(int)); - for (i = retained->idle_spawn_rate_len; i < new_len; i++) { - new_ptr[i] = 1; - } - retained->idle_spawn_rate_len = new_len; + retained->num_buckets * sizeof(int)); retained->idle_spawn_rate = new_ptr; + retained->max_buckets = new_max; + } + if (retained->num_buckets < num_buckets) { + int rate_max = 1; + /* If new buckets are added, set their idle spawn rate to + * the highest so far, so that they get filled as quickly + * as the existing ones. + */ + for (i = 0; i < retained->num_buckets; i++) { + if (rate_max < retained->idle_spawn_rate[i]) { + rate_max = retained->idle_spawn_rate[i]; + } + } + for (/* up to date i */; i < num_buckets; i++) { + retained->idle_spawn_rate[i] = rate_max; + } } + retained->num_buckets = num_buckets; /* for skiplist */ srand((unsigned int)apr_time_now()); @@ -3522,12 +3546,6 @@ static int event_check_config(apr_pool_t *p, apr_pool_t *plog, } ap_daemons_limit = server_limit; } - else if (ap_daemons_limit < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - ap_daemons_limit = num_buckets; - } /* ap_daemons_to_start > ap_daemons_limit checked in ap_mpm_run() */ if (ap_daemons_to_start < 1) { @@ -3542,12 +3560,6 @@ static int event_check_config(apr_pool_t *p, apr_pool_t *plog, } ap_daemons_to_start = 1; } - if (ap_daemons_to_start < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - ap_daemons_to_start = num_buckets; - } if (min_spare_threads < 1) { if (startup) { @@ -3565,12 +3577,6 @@ static int event_check_config(apr_pool_t *p, apr_pool_t *plog, } min_spare_threads = 1; } - if (min_spare_threads < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - min_spare_threads = num_buckets; - } /* max_spare_threads < min_spare_threads + threads_per_child * checked in ap_mpm_run() diff --git a/server/mpm/eventopt/eventopt.c b/server/mpm/eventopt/eventopt.c index dd002ac831..a5d1c7881d 100644 --- a/server/mpm/eventopt/eventopt.c +++ b/server/mpm/eventopt/eventopt.c @@ -335,15 +335,20 @@ typedef struct event_retained_data { /* * idle_spawn_rate is the number of children that will be spawned on the * next maintenance cycle if there aren't enough idle servers. It is - * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by - * without the need to spawn. + * maintained per listeners bucket, doubled up to MAX_SPAWN_RATE, and + * reset only when a cycle goes by without the need to spawn. */ - int *idle_spawn_rate, - idle_spawn_rate_len; + int *idle_spawn_rate; #ifndef MAX_SPAWN_RATE #define MAX_SPAWN_RATE (32) #endif int hold_off_on_exponential_spawning; + /* + * Current number of listeners buckets and maximum reached accross + * restarts (to size retained data according to dynamic num_buckets, + * eg. idle_spawn_rate). + */ + int num_buckets, max_buckets; } event_retained_data; static event_retained_data *retained; @@ -351,7 +356,6 @@ typedef struct event_child_bucket { ap_pod_t *pod; ap_listen_rec *listeners; } event_child_bucket; -static int num_buckets; /* Number of listeners buckets */ static event_child_bucket *all_buckets, /* All listeners buckets */ *my_bucket; /* Current child bucket */ @@ -2245,7 +2249,7 @@ static void child_main(int child_num_arg, int child_bucket) apr_pool_create(&pchild, pconf); /* close unused listeners and pods */ - for (i = 0; i < num_buckets; i++) { + for (i = 0; i < retained->num_buckets; i++) { if (i != child_bucket) { ap_close_listeners_ex(all_buckets[i].listeners); ap_mpm_podx_close(all_buckets[i].pod); @@ -2484,14 +2488,14 @@ static void startup_children(int number_to_start) if (ap_scoreboard_image->parent[i].pid != 0) { continue; } - if (make_child(ap_server_conf, i, i % num_buckets) < 0) { + if (make_child(ap_server_conf, i, i % retained->num_buckets) < 0) { break; } --number_to_start; } } -static void perform_idle_server_maintenance(int child_bucket) +static void perform_idle_server_maintenance(int child_bucket, int num_buckets) { int i, j; int idle_thread_count; @@ -2675,7 +2679,7 @@ static void perform_idle_server_maintenance(int child_bucket) } } -static void server_main_loop(int remaining_children_to_start) +static void server_main_loop(int remaining_children_to_start, int num_buckets) { ap_generation_t old_gen; int child_slot; @@ -2791,15 +2795,15 @@ static void server_main_loop(int remaining_children_to_start) } for (i = 0; i < num_buckets; i++) { - perform_idle_server_maintenance(i); + perform_idle_server_maintenance(i, num_buckets); } } } static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) { + int num_buckets = retained->num_buckets; int remaining_children_to_start; - int i; ap_log_pid(pconf, ap_pid_fname); @@ -2818,7 +2822,13 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) restart_pending = shutdown_pending = 0; set_signals(); - /* Don't thrash... */ + /* Don't thrash since num_buckets depends on the + * system and the number of online CPU cores... + */ + if (ap_daemons_limit < num_buckets) + ap_daemons_limit = num_buckets; + if (ap_daemons_to_start < num_buckets) + ap_daemons_to_start = num_buckets; if (min_spare_threads < threads_per_child * num_buckets) min_spare_threads = threads_per_child * num_buckets; if (max_spare_threads < min_spare_threads + threads_per_child * num_buckets) @@ -2857,7 +2867,7 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) mpm_state = AP_MPMQ_RUNNING; - server_main_loop(remaining_children_to_start); + server_main_loop(remaining_children_to_start, num_buckets); mpm_state = AP_MPMQ_STOPPING; if (shutdown_pending && !retained->is_graceful) { @@ -2997,6 +3007,7 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog, { int startup = 0; int level_flags = 0; + int num_buckets = 0; ap_listen_rec **listen_buckets; apr_status_t rv; int i; @@ -3019,9 +3030,9 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog, if (one_process) { num_buckets = 1; } - else if (!retained->is_graceful) { /* Preserve the number of buckets - on graceful restarts. */ - num_buckets = 0; + else if (retained->is_graceful) { + /* Preserve the number of buckets on graceful restarts. */ + num_buckets = retained->num_buckets; } if ((rv = ap_duplicate_listeners(pconf, ap_server_conf, &listen_buckets, &num_buckets))) { @@ -3030,8 +3041,8 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog, "could not duplicate listeners"); return DONE; } - all_buckets = apr_pcalloc(pconf, num_buckets * - sizeof(event_child_bucket)); + + all_buckets = apr_pcalloc(pconf, num_buckets * sizeof(*all_buckets)); for (i = 0; i < num_buckets; i++) { if (!one_process && /* no POD in one_process mode */ (rv = ap_mpm_podx_open(pconf, &all_buckets[i].pod))) { @@ -3043,21 +3054,34 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog, all_buckets[i].listeners = listen_buckets[i]; } - if (retained->idle_spawn_rate_len < num_buckets) { - int *new_ptr, new_len; - new_len = retained->idle_spawn_rate_len * 2; - if (new_len < num_buckets) { - new_len = num_buckets; + if (retained->max_buckets < num_buckets) { + int new_max, *new_ptr; + new_max = retained->max_buckets * 2; + if (new_max < num_buckets) { + new_max = num_buckets; } - new_ptr = (int *)apr_palloc(ap_pglobal, new_len * sizeof(int)); + new_ptr = (int *)apr_palloc(ap_pglobal, new_max * sizeof(int)); memcpy(new_ptr, retained->idle_spawn_rate, - retained->idle_spawn_rate_len * sizeof(int)); - for (i = retained->idle_spawn_rate_len; i < new_len; i++) { - new_ptr[i] = 1; - } - retained->idle_spawn_rate_len = new_len; + retained->num_buckets * sizeof(int)); retained->idle_spawn_rate = new_ptr; + retained->max_buckets = new_max; + } + if (retained->num_buckets < num_buckets) { + int rate_max = 1; + /* If new buckets are added, set their idle spawn rate to + * the highest so far, so that they get filled as quickly + * as the existing ones. + */ + for (i = 0; i < retained->num_buckets; i++) { + if (rate_max < retained->idle_spawn_rate[i]) { + rate_max = retained->idle_spawn_rate[i]; + } + } + for (/* up to date i */; i < num_buckets; i++) { + retained->idle_spawn_rate[i] = rate_max; + } } + retained->num_buckets = num_buckets; /* for skiplist */ srand((unsigned int)apr_time_now()); @@ -3339,12 +3363,6 @@ static int event_check_config(apr_pool_t *p, apr_pool_t *plog, } ap_daemons_limit = server_limit; } - else if (ap_daemons_limit < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - ap_daemons_limit = num_buckets; - } /* ap_daemons_to_start > ap_daemons_limit checked in ap_mpm_run() */ if (ap_daemons_to_start < 1) { @@ -3359,12 +3377,6 @@ static int event_check_config(apr_pool_t *p, apr_pool_t *plog, } ap_daemons_to_start = 1; } - if (ap_daemons_to_start < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - ap_daemons_to_start = num_buckets; - } if (min_spare_threads < 1) { if (startup) { @@ -3382,12 +3394,6 @@ static int event_check_config(apr_pool_t *p, apr_pool_t *plog, } min_spare_threads = 1; } - if (min_spare_threads < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - min_spare_threads = num_buckets; - } /* max_spare_threads < min_spare_threads + threads_per_child * checked in ap_mpm_run() diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index c8c8266583..260e37666c 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -993,7 +993,15 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) return !OK; } - /* Don't thrash... */ + /* Don't thrash since num_buckets depends on the + * system and the number of online CPU cores... + */ + if (ap_daemons_limit < num_buckets) + ap_daemons_limit = num_buckets; + if (ap_daemons_to_start < num_buckets) + ap_daemons_to_start = num_buckets; + if (ap_daemons_min_free < num_buckets) + ap_daemons_min_free = num_buckets; if (ap_daemons_max_free < ap_daemons_min_free + num_buckets) ap_daemons_max_free = ap_daemons_min_free + num_buckets; @@ -1324,7 +1332,7 @@ static int prefork_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, "could not open pipe-of-death"); return DONE; } - /* Initialize cross-process accept lock (safe accept is needed only) */ + /* Initialize cross-process accept lock (safe accept needed only) */ if ((rv = SAFE_ACCEPT((apr_snprintf(id, sizeof id, "%i", i), ap_proc_mutex_create(&all_buckets[i].mutex, NULL, AP_ACCEPT_MUTEX_TYPE, @@ -1483,12 +1491,6 @@ static int prefork_check_config(apr_pool_t *p, apr_pool_t *plog, } ap_daemons_limit = 1; } - if (ap_daemons_limit < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - ap_daemons_limit = num_buckets; - } /* ap_daemons_to_start > ap_daemons_limit checked in prefork_run() */ if (ap_daemons_to_start < 1) { @@ -1503,12 +1505,6 @@ static int prefork_check_config(apr_pool_t *p, apr_pool_t *plog, } ap_daemons_to_start = 1; } - if (ap_daemons_to_start < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - ap_daemons_to_start = num_buckets; - } if (ap_daemons_min_free < 1) { if (startup) { @@ -1526,12 +1522,6 @@ static int prefork_check_config(apr_pool_t *p, apr_pool_t *plog, } ap_daemons_min_free = 1; } - if (ap_daemons_min_free < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - ap_daemons_min_free = num_buckets; - } /* ap_daemons_max_free < ap_daemons_min_free + 1 checked in prefork_run() */ diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index 0351c066d2..190bc5ba93 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -160,15 +160,20 @@ typedef struct worker_retained_data { /* * idle_spawn_rate is the number of children that will be spawned on the * next maintenance cycle if there aren't enough idle servers. It is - * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by - * without the need to spawn. + * maintained per listeners bucket, doubled up to MAX_SPAWN_RATE, and + * reset only when a cycle goes by without the need to spawn. */ - int *idle_spawn_rate, - idle_spawn_rate_len; + int *idle_spawn_rate; #ifndef MAX_SPAWN_RATE #define MAX_SPAWN_RATE (32) #endif int hold_off_on_exponential_spawning; + /* + * Current number of listeners buckets and maximum reached accross + * restarts (to size retained data according to dynamic num_buckets, + * eg. idle_spawn_rate). + */ + int num_buckets, max_buckets; } worker_retained_data; static worker_retained_data *retained; @@ -177,7 +182,6 @@ typedef struct worker_child_bucket { ap_listen_rec *listeners; apr_proc_mutex_t *mutex; } worker_child_bucket; -static int num_buckets; /* Number of listeners buckets */ static worker_child_bucket *all_buckets, /* All listeners buckets */ *my_bucket; /* Current child bucket */ @@ -1236,7 +1240,7 @@ static void child_main(int child_num_arg, int child_bucket) apr_pool_create(&pchild, pconf); /* close unused listeners and pods */ - for (i = 0; i < num_buckets; i++) { + for (i = 0; i < retained->num_buckets; i++) { if (i != child_bucket) { ap_close_listeners_ex(all_buckets[i].listeners); ap_mpm_podx_close(all_buckets[i].pod); @@ -1476,14 +1480,14 @@ static void startup_children(int number_to_start) if (ap_scoreboard_image->parent[i].pid != 0) { continue; } - if (make_child(ap_server_conf, i, i % num_buckets) < 0) { + if (make_child(ap_server_conf, i, i % retained->num_buckets) < 0) { break; } --number_to_start; } } -static void perform_idle_server_maintenance(int child_bucket) +static void perform_idle_server_maintenance(int child_bucket, int num_buckets) { int i, j; int idle_thread_count; @@ -1680,7 +1684,7 @@ static void perform_idle_server_maintenance(int child_bucket) } } -static void server_main_loop(int remaining_children_to_start) +static void server_main_loop(int remaining_children_to_start, int num_buckets) { ap_generation_t old_gen; int child_slot; @@ -1794,13 +1798,14 @@ static void server_main_loop(int remaining_children_to_start) } for (i = 0; i < num_buckets; i++) { - perform_idle_server_maintenance(i); + perform_idle_server_maintenance(i, num_buckets); } } } static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) { + int num_buckets = retained->num_buckets; int remaining_children_to_start; int i; @@ -1820,7 +1825,13 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) restart_pending = shutdown_pending = 0; set_signals(); - /* Don't thrash... */ + /* Don't thrash since num_buckets depends on the + * system and the number of online CPU cores... + */ + if (ap_daemons_limit < num_buckets) + ap_daemons_limit = num_buckets; + if (ap_daemons_to_start < num_buckets) + ap_daemons_to_start = num_buckets; if (min_spare_threads < threads_per_child * num_buckets) min_spare_threads = threads_per_child * num_buckets; if (max_spare_threads < min_spare_threads + threads_per_child * num_buckets) @@ -1862,7 +1873,7 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) apr_proc_mutex_defname()); mpm_state = AP_MPMQ_RUNNING; - server_main_loop(remaining_children_to_start); + server_main_loop(remaining_children_to_start, num_buckets); mpm_state = AP_MPMQ_STOPPING; if (shutdown_pending && !retained->is_graceful) { @@ -2001,6 +2012,7 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, { int startup = 0; int level_flags = 0; + int num_buckets = 0; ap_listen_rec **listen_buckets; apr_status_t rv; char id[16]; @@ -2024,9 +2036,9 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, if (one_process) { num_buckets = 1; } - else if (!retained->is_graceful) { /* Preserve the number of buckets - on graceful restarts. */ - num_buckets = 0; + else if (retained->is_graceful) { + /* Preserve the number of buckets on graceful restarts. */ + num_buckets = retained->num_buckets; } if ((rv = ap_duplicate_listeners(pconf, ap_server_conf, &listen_buckets, &num_buckets))) { @@ -2035,8 +2047,8 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, "could not duplicate listeners"); return DONE; } - all_buckets = apr_pcalloc(pconf, num_buckets * - sizeof(worker_child_bucket)); + + all_buckets = apr_pcalloc(pconf, num_buckets * sizeof(*all_buckets)); for (i = 0; i < num_buckets; i++) { if (!one_process && /* no POD in one_process mode */ (rv = ap_mpm_podx_open(pconf, &all_buckets[i].pod))) { @@ -2045,7 +2057,7 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, "could not open pipe-of-death"); return DONE; } - /* Initialize cross-process accept lock (safe accept is needed only) */ + /* Initialize cross-process accept lock (safe accept needed only) */ if ((rv = SAFE_ACCEPT((apr_snprintf(id, sizeof id, "%i", i), ap_proc_mutex_create(&all_buckets[i].mutex, NULL, AP_ACCEPT_MUTEX_TYPE, @@ -2058,21 +2070,34 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, all_buckets[i].listeners = listen_buckets[i]; } - if (retained->idle_spawn_rate_len < num_buckets) { - int *new_ptr, new_len; - new_len = retained->idle_spawn_rate_len * 2; - if (new_len < num_buckets) { - new_len = num_buckets; + if (retained->max_buckets < num_buckets) { + int new_max, *new_ptr; + new_max = retained->max_buckets * 2; + if (new_max < num_buckets) { + new_max = num_buckets; } - new_ptr = (int *)apr_palloc(ap_pglobal, new_len * sizeof(int)); + new_ptr = (int *)apr_palloc(ap_pglobal, new_max * sizeof(int)); memcpy(new_ptr, retained->idle_spawn_rate, - retained->idle_spawn_rate_len * sizeof(int)); - for (i = retained->idle_spawn_rate_len; i < new_len; i++) { - new_ptr[i] = 1; - } - retained->idle_spawn_rate_len = new_len; + retained->num_buckets * sizeof(int)); retained->idle_spawn_rate = new_ptr; + retained->max_buckets = new_max; } + if (retained->num_buckets < num_buckets) { + int rate_max = 1; + /* If new buckets are added, set their idle spawn rate to + * the highest so far, so that they get filled as quickly + * as the existing ones. + */ + for (i = 0; i < retained->num_buckets; i++) { + if (rate_max < retained->idle_spawn_rate[i]) { + rate_max = retained->idle_spawn_rate[i]; + } + } + for (/* up to date i */; i < num_buckets; i++) { + retained->idle_spawn_rate[i] = rate_max; + } + } + retained->num_buckets = num_buckets; return OK; } @@ -2334,12 +2359,6 @@ static int worker_check_config(apr_pool_t *p, apr_pool_t *plog, } ap_daemons_limit = server_limit; } - else if (ap_daemons_limit < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - ap_daemons_limit = num_buckets; - } /* ap_daemons_to_start > ap_daemons_limit checked in worker_run() */ if (ap_daemons_to_start < 1) { @@ -2354,12 +2373,6 @@ static int worker_check_config(apr_pool_t *p, apr_pool_t *plog, } ap_daemons_to_start = 1; } - if (ap_daemons_to_start < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - ap_daemons_to_start = num_buckets; - } if (min_spare_threads < 1) { if (startup) { @@ -2377,12 +2390,6 @@ static int worker_check_config(apr_pool_t *p, apr_pool_t *plog, } min_spare_threads = 1; } - if (min_spare_threads < num_buckets) { - /* Don't thrash since num_buckets depends on - * the system and the number of CPU cores. - */ - min_spare_threads = num_buckets; - } /* max_spare_threads < min_spare_threads + threads_per_child * checked in worker_run() -- 2.40.0