mirror of
https://github.com/apache/httpd.git
synced 2026-01-06 09:01:14 +03:00
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
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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() */
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user