Hi all,
I spent some time working on the missing apache_like feature in FPM.
The attached patch is the first version and is for testing.
Changes:
1- rename apache_like to dynamic (in conf file and in source file)
2- add the dynamic spawning algorithm
The algorithm is based on the mod_worker from apache httpd
Algorihtm:
check start_servers, min_spare_servers, max_spare_servers
if start_server is not set, set it to (min_spare + (max_spare - min_spare) / 2)
for each pool, set a variable spawn_rate to 1
set a 1s timer event to perform idle server maintenance
each second
for each pool {
calculate nb_idle, number of idle process (based on
child->time_accepted which is set when a child accept() call returns
and reset when it call accept())
if idle > max_spare {
kill the oldest idle child
set spawn_rate to 1
continue to next pool
}
if idle < min_spare {
set nb_children to MIN(spawn_rate, (min_spare - nb_idle))
create nb_children
if (spawn_rate < 32) {
spawn_rate * 2
}
continue to next next pool
}
// nothing has been done (no fork and no kill)
reset spawn_rate to 1
continue to next pool
}
spawn_rate is used to increase the number of child to create when
there is a lot of children to create at once. The first iteration it
will create 1, then 2, then 4, then 8, then 16.
I didn't do anything about handling the gracefull restart. I'll check
that later.
You can test it and make me returns.
Hope it helps
++ Jerome
Index: sapi/fpm/fpm/fpm_request.h
===================================================================
--- sapi/fpm/fpm/fpm_request.h (révision 292067)
+++ sapi/fpm/fpm/fpm_request.h (copie de travail)
@@ -15,6 +15,7 @@
struct timeval;
void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval
*tv, int terminate_timeout, int slowlog_timeout);
+int fpm_request_is_idle(struct fpm_child_s *child);
enum fpm_request_stage_e {
FPM_REQUEST_ACCEPTING = 1,
Index: sapi/fpm/fpm/fpm_children.h
===================================================================
--- sapi/fpm/fpm/fpm_children.h (révision 292067)
+++ sapi/fpm/fpm/fpm_children.h (copie de travail)
@@ -15,6 +15,7 @@
int fpm_children_free(struct fpm_child_s *child);
void fpm_children_bury();
int fpm_children_init_main();
+int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int
nb_to_spawn);
struct fpm_child_s;
@@ -27,6 +28,7 @@
int fd_stdout, fd_stderr;
void (*tracer)(struct fpm_child_s *);
struct timeval slow_logged;
+ int idle_kill;
pid_t pid;
};
Index: sapi/fpm/fpm/fpm_config.h
===================================================================
--- sapi/fpm/fpm/fpm_config.h (révision 292067)
+++ sapi/fpm/fpm/fpm_config.h (copie de travail)
@@ -32,6 +32,10 @@
} while (0)
#endif
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
#if defined(HAVE_PTRACE) || defined(PROC_MEM_FILE) ||
defined(HAVE_MACH_VM_READ)
#define HAVE_FPM_TRACE 1
#else
Index: sapi/fpm/fpm/fpm_process_ctl.c
===================================================================
--- sapi/fpm/fpm/fpm_process_ctl.c (révision 292067)
+++ sapi/fpm/fpm/fpm_process_ctl.c (copie de travail)
@@ -307,10 +307,95 @@
}
}
}
-
}
/* }}} */
+static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now) /*
{{{ */
+{
+ struct fpm_worker_pool_s *wp;
+ struct fpm_child_s *last_idle_child = NULL;
+ int i;
+
+ for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
+ int terminate_timeout = wp->config->request_terminate_timeout;
+ int slowlog_timeout = wp->config->request_slowlog_timeout;
+ struct fpm_child_s *child;
+ int idle = 0;
+ int active = 0;
+ struct timeval tv;
+
+ if (wp->config == NULL) continue;
+ if (wp->config->pm->style != PM_STYLE_DYNAMIC) continue;
+
+ for (child = wp->children; child; child = child->next) {
+ int ret = fpm_request_is_idle(child);
+ if (ret == 1) {
+ if (last_idle_child == NULL) {
+ last_idle_child = child;
+ } else {
+ if (child->started.tv_sec <
last_idle_child->started.tv_sec) {
+ last_idle_child = child;
+ }
+ }
+ idle++;
+ } else if (ret == 0) {
+ active++;
+ }
+ }
+
+ zlog(ZLOG_STUFF, ZLOG_DEBUG, "[%s] rate=%d idle=%d active=%d
total=%d", wp->config->name, wp->idle_spawn_rate, idle, active,
wp->running_children);
+
+ if ((active + idle) != wp->running_children) {
+ zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s] unable to retrieve
spawning informations", wp->config->name);
+ continue;
+ }
+
+ if (idle > wp->config->pm->dynamic.max_spare_servers &&
last_idle_child) {
+ last_idle_child->idle_kill = 1;
+ fpm_pctl_kill(last_idle_child->pid, FPM_PCTL_TERM);
+ wp->idle_spawn_rate = 1;
+ continue;
+ }
+
+ if (idle < wp->config->pm->dynamic.min_spare_servers) {
+ if (wp->running_children >=
wp->config->pm->max_children) {
+ if (!wp->warn_max_children) {
+ zlog(ZLOG_STUFF, ZLOG_WARNING, "pool
%s: server reached max_children setting, consider raising it",
+ wp->config->name);
+ wp->warn_max_children = 1;
+ }
+ wp->idle_spawn_rate = 1;
+ continue;
+ }
+ wp->warn_max_children = 0;
+
+ if (wp->idle_spawn_rate >= 8) {
+ zlog(ZLOG_STUFF, ZLOG_WARNING, "pool %s seems
busy (you may need to increase start_servers, or min/max_spare_servers),
spawning %d children, there are %d idle, and %d total children",
wp->config->name, wp->idle_spawn_rate, idle, wp->running_children);
+ }
+
+ i = MIN(wp->idle_spawn_rate,
wp->config->pm->dynamic.min_spare_servers - idle);
+ fpm_children_make(wp, 1, i);
+
+ /* if it's a child, stop here without creating the next
event
+ * this event is reserved to the master process
+ */
+ if (fpm_globals.is_child) {
+ return;
+ }
+
+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "pool %s: %d child(ren)
have been created because of not enough spare children", wp->config->name, i);
+
+ /* Double the spawn rate for the next iteration */
+ if (wp->idle_spawn_rate < FPM_MAX_SPAWN_RATE) {
+ wp->idle_spawn_rate *= 2;
+ }
+ continue;
+ }
+ wp->idle_spawn_rate = 1;
+ }
+}
+/* }}} */
+
void fpm_pctl_heartbeat(int fd, short which, void *arg) /* {{{ */
{
static struct event heartbeat;
@@ -328,3 +413,29 @@
}
/* }}} */
+void fpm_pctl_perform_idle_server_maintenance_heartbeat(int fd, short which,
void *arg) /* {{{ */
+{
+ static struct event heartbeat;
+ struct timeval tv = { .tv_sec = 0, .tv_usec =
FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT };
+ struct timeval now;
+
+ if (which == EV_TIMEOUT) {
+ evtimer_del(&heartbeat);
+ fpm_clock_get(&now);
+ if (fpm_pctl_can_spawn_children()) {
+ fpm_pctl_perform_idle_server_maintenance(&now);
+
+ /* if it's a child, stop here without creating the next
event
+ * this event is reserved to the master process
+ */
+ if (fpm_globals.is_child) {
+ return;
+ }
+ }
+ }
+
+ evtimer_set(&heartbeat,
&fpm_pctl_perform_idle_server_maintenance_heartbeat, 0);
+ evtimer_add(&heartbeat, &tv);
+}
+/* }}} */
+
Index: sapi/fpm/fpm/fpm_conf.c
===================================================================
--- sapi/fpm/fpm/fpm_conf.c (révision 292067)
+++ sapi/fpm/fpm/fpm_conf.c (copie de travail)
@@ -82,8 +82,8 @@
if (!strcmp(value, "static")) {
c->style = PM_STYLE_STATIC;
- } else if (!strcmp(value, "apache-like")) {
- c->style = PM_STYLE_APACHE_LIKE;
+ } else if (!strcmp(value, "dynamic")) {
+ c->style = PM_STYLE_DYNAMIC;
} else {
return "invalid value for 'style'";
}
@@ -139,19 +139,19 @@
}
/* }}} */
-static struct xml_conf_section fpm_conf_set_apache_like_subsection_conf = {
- .path = "apache_like somewhere", /* fixme */
+static struct xml_conf_section fpm_conf_set_dynamic_subsection_conf = {
+ .path = "dynamic somewhere", /* fixme */
.parsers = (struct xml_value_parser []) {
- { XML_CONF_SCALAR, "StartServers",
&xml_conf_set_slot_integer, offsetof(struct fpm_pm_s,
options_apache_like.StartServers) },
- { XML_CONF_SCALAR, "MinSpareServers",
&xml_conf_set_slot_integer, offsetof(struct fpm_pm_s,
options_apache_like.MinSpareServers) },
- { XML_CONF_SCALAR, "MaxSpareServers",
&xml_conf_set_slot_integer, offsetof(struct fpm_pm_s,
options_apache_like.MaxSpareServers) },
+ { XML_CONF_SCALAR, "start_servers",
&xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, dynamic.start_servers) },
+ { XML_CONF_SCALAR, "min_spare_servers",
&xml_conf_set_slot_integer, offsetof(struct fpm_pm_s,
dynamic.min_spare_servers) },
+ { XML_CONF_SCALAR, "max_spare_servers",
&xml_conf_set_slot_integer, offsetof(struct fpm_pm_s,
dynamic.max_spare_servers) },
{ 0, 0, 0, 0 }
}
};
-static char *fpm_conf_set_apache_like_subsection(void **conf, char *name, void
*xml_node, intptr_t offset) /* {{{ */
+static char *fpm_conf_set_dynamic_subsection(void **conf, char *name, void
*xml_node, intptr_t offset) /* {{{ */
{
- return xml_conf_parse_section(conf,
&fpm_conf_set_apache_like_subsection_conf, xml_node);
+ return xml_conf_parse_section(conf,
&fpm_conf_set_dynamic_subsection_conf, xml_node);
}
/* }}} */
@@ -191,7 +191,7 @@
.parsers = (struct xml_value_parser []) {
{ XML_CONF_SCALAR, "style",
&fpm_conf_set_pm_style, 0 },
{ XML_CONF_SCALAR, "max_children",
&xml_conf_set_slot_integer, offsetof(struct
fpm_pm_s, max_children) },
- { XML_CONF_SUBSECTION, "apache_like",
&fpm_conf_set_apache_like_subsection, offsetof(struct fpm_pm_s,
options_apache_like) },
+ { XML_CONF_SUBSECTION, "dynamic",
&fpm_conf_set_dynamic_subsection, offsetof(struct fpm_pm_s,
dynamic) },
{ 0, 0, 0, 0 }
}
};
@@ -392,6 +392,46 @@
wp->is_template = 1;
}
+ if (wp->config->pm == NULL) {
+ zlog(ZLOG_STUFF, ZLOG_ALERT, "pool %s: the process
manager is missing (static or dynamic)", wp->config->name);
+ return(-1);
+ }
+
+ if (wp->config->pm->style == PM_STYLE_DYNAMIC) {
+ struct fpm_pm_s *pm = wp->config->pm;
+
+ if (pm->dynamic.min_spare_servers <= 0) {
+ zlog(ZLOG_STUFF, ZLOG_ALERT, "pool %s:
min_spare_servers must be a positive value", wp->config->name);
+ return(-1);
+ }
+
+ if (pm->dynamic.max_spare_servers <= 0) {
+ zlog(ZLOG_STUFF, ZLOG_ALERT, "pool %s:
max_spare_servers must be a positive value", wp->config->name);
+ return(-1);
+ }
+
+ if (pm->dynamic.min_spare_servers > pm->max_children ||
+ pm->dynamic.max_spare_servers > pm->max_children) {
+ zlog(ZLOG_STUFF, ZLOG_ALERT, "pool %s:
min_spare_servers(%d) and max_spare_servers(%d) can't be greater than
max_children(%d)",
+ wp->config->name,
pm->dynamic.min_spare_servers, pm->dynamic.max_spare_servers, pm->max_children);
+ return(-1);
+ }
+
+ if (pm->dynamic.max_spare_servers <
pm->dynamic.min_spare_servers) {
+ zlog(ZLOG_STUFF, ZLOG_ALERT, "pool %s:
max_spare_servers must be greater or equal than min_spare_servers",
wp->config->name);
+ return(-1);
+ }
+
+ if (pm->dynamic.start_servers <= 0) {
+ pm->dynamic.start_servers =
pm->dynamic.min_spare_servers + ((pm->dynamic.max_spare_servers -
pm->dynamic.min_spare_servers) / 2);
+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "pool %s:
start_servers has been set to %d", wp->config->name, pm->dynamic.start_servers);
+ } else if (pm->dynamic.start_servers <
pm->dynamic.min_spare_servers || pm->dynamic.start_servers >
pm->dynamic.max_spare_servers) {
+ zlog(ZLOG_STUFF, ZLOG_ALERT, "pool %s:
start_servers must not be less than min_spare_servers and not greaters than
max_spare_servers", wp->config->name);
+ return(-1);
+ }
+ }
+
+
if (wp->config->request_slowlog_timeout) {
#if HAVE_FPM_TRACE
if (! (wp->config->slowlog && *wp->config->slowlog)) {
Index: sapi/fpm/fpm/fpm_process_ctl.h
===================================================================
--- sapi/fpm/fpm/fpm_process_ctl.h (révision 292067)
+++ sapi/fpm/fpm/fpm_process_ctl.h (copie de travail)
@@ -5,12 +5,18 @@
#ifndef FPM_PROCESS_CTL_H
#define FPM_PROCESS_CTL_H 1
+/* spawn max 32 children at once */
+#define FPM_MAX_SPAWN_RATE (32)
+/* 1s (in µs here) heatbeat for idle server maintenance */
+#define FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT (1000000)
+
struct fpm_child_s;
void fpm_pctl(int new_state, int action);
int fpm_pctl_can_spawn_children();
int fpm_pctl_kill(pid_t pid, int how);
void fpm_pctl_heartbeat(int fd, short which, void *arg);
+void fpm_pctl_perform_idle_server_maintenance_heartbeat(int fd, short which,
void *arg);
int fpm_pctl_child_exited();
int fpm_pctl_init_main();
Index: sapi/fpm/fpm/fpm_conf.h
===================================================================
--- sapi/fpm/fpm/fpm_conf.h (révision 292067)
+++ sapi/fpm/fpm/fpm_conf.h (copie de travail)
@@ -28,10 +28,10 @@
int style;
int max_children;
struct {
- int StartServers;
- int MinSpareServers;
- int MaxSpareServers;
- } options_apache_like;
+ int start_servers;
+ int min_spare_servers;
+ int max_spare_servers;
+ } dynamic;
};
struct fpm_listen_options_s {
@@ -62,7 +62,7 @@
unsigned catch_workers_output:1;
};
-enum { PM_STYLE_STATIC = 1, PM_STYLE_APACHE_LIKE = 2 };
+enum { PM_STYLE_STATIC = 1, PM_STYLE_DYNAMIC = 2 };
int fpm_conf_init_main();
int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc);
Index: sapi/fpm/fpm/fpm_worker_pool.c
===================================================================
--- sapi/fpm/fpm/fpm_worker_pool.c (révision 292067)
+++ sapi/fpm/fpm/fpm_worker_pool.c (copie de travail)
@@ -53,6 +53,7 @@
fpm_array_init(&ret->slots_used, sizeof(struct fpm_shm_slot_ptr_s), 50);
fpm_array_init(&ret->slots_free, sizeof(struct fpm_shm_slot_ptr_s), 50);
+ ret->idle_spawn_rate = 1;
return ret;
}
/* }}} */
Index: sapi/fpm/fpm/fpm_events.c
===================================================================
--- sapi/fpm/fpm/fpm_events.c (révision 292067)
+++ sapi/fpm/fpm/fpm_events.c (copie de travail)
@@ -100,6 +100,7 @@
event_set(&signal_fd_event, fpm_signals_get_fd(), EV_PERSIST | EV_READ,
&fpm_got_signal, 0);
event_add(&signal_fd_event, 0);
fpm_pctl_heartbeat(-1, 0, 0);
+ fpm_pctl_perform_idle_server_maintenance_heartbeat(-1, 0, 0);
zlog(ZLOG_STUFF, ZLOG_NOTICE, "libevent: entering main loop");
event_loop(0);
return 0;
Index: sapi/fpm/fpm/fpm_worker_pool.h
===================================================================
--- sapi/fpm/fpm/fpm_worker_pool.h (révision 292067)
+++ sapi/fpm/fpm/fpm_worker_pool.h (copie de travail)
@@ -35,6 +35,8 @@
/* runtime */
struct fpm_child_s *children;
int running_children;
+ int idle_spawn_rate;
+ int warn_max_children;
};
struct fpm_worker_pool_s *fpm_worker_pool_alloc();
Index: sapi/fpm/fpm/fastcgi.c
===================================================================
--- sapi/fpm/fpm/fastcgi.c (révision 292067)
+++ sapi/fpm/fpm/fastcgi.c (copie de travail)
@@ -986,13 +986,13 @@
int n = 0;
int allowed = 0;
- while
(allowed_clients[n] != INADDR_NONE) {
- if
(allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
- allowed
= 1;
- break;
- }
- n++;
+ while (allowed_clients[n] !=
INADDR_NONE) {
+ if (allowed_clients[n]
== sa.sa_inet.sin_addr.s_addr) {
+ allowed = 1;
+ break;
}
+ n++;
+ }
if (!allowed) {
fprintf(stderr,
"Connection from disallowed IP address '%s' is dropped.\n",
inet_ntoa(sa.sa_inet.sin_addr));
closesocket(req->fd);
Index: sapi/fpm/fpm/fpm_request.c
===================================================================
--- sapi/fpm/fpm/fpm_request.c (révision 292067)
+++ sapi/fpm/fpm/fpm_request.c (copie de travail)
@@ -148,3 +148,18 @@
}
/* }}} */
+int fpm_request_is_idle(struct fpm_child_s *child) /* {{{ */
+{
+ struct fpm_shm_slot_s *slot;
+ struct fpm_shm_slot_s slot_c;
+
+ slot = fpm_shm_slot(child);
+ if (!fpm_shm_slots_acquire(slot, 1)) {
+ return(-1);
+ }
+
+ slot_c = *slot;
+ fpm_shm_slots_release(slot);
+ return(!slot_c.accepted.tv_sec && !slot_c.accepted.tv_usec ? 1 : 0);
+}
+/* }}} */
Index: sapi/fpm/fpm/fpm_children.c
===================================================================
--- sapi/fpm/fpm/fpm_children.c (révision 292067)
+++ sapi/fpm/fpm/fpm_children.c (copie de travail)
@@ -32,8 +32,6 @@
static time_t *last_faults;
static int fault;
-static int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop);
-
static void fpm_children_cleanup(int which, void *arg) /* {{{ */
{
free(last_faults);
@@ -180,6 +178,7 @@
while ( (pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
char buf[128];
int severity = ZLOG_NOTICE;
+ int restart_child = 1;
child = fpm_child_find(pid);
@@ -187,6 +186,13 @@
snprintf(buf, sizeof(buf), "with code %d",
WEXITSTATUS(status));
+ /* if it's been killed because of dynamic process
management
+ * don't restart it automaticaly
+ */
+ if (child && child->idle_kill) {
+ restart_child = 0;
+ }
+
if (WEXITSTATUS(status) != 0) {
severity = ZLOG_WARNING;
}
@@ -201,6 +207,13 @@
snprintf(buf, sizeof(buf), "on signal %d %s%s",
WTERMSIG(status), signame, have_core);
+ /* if it's been killed because of dynamic process
management
+ * don't restart it automaticaly
+ */
+ if (child && child->idle_kill && WTERMSIG(status) ==
SIGTERM) {
+ restart_child = 0;
+ }
+
if (WTERMSIG(status) != SIGQUIT) { /* possible request
loss */
severity = ZLOG_WARNING;
}
@@ -227,8 +240,13 @@
timersub(&tv1, &child->started, &tv2);
- zlog(ZLOG_STUFF, severity, "child %d (pool %s) exited
%s after %ld.%06d seconds from start", (int) pid,
- child->wp->config->name, buf,
tv2.tv_sec, (int) tv2.tv_usec);
+ if (restart_child) {
+ zlog(ZLOG_STUFF, severity, "child %d (pool %s)
exited %s after %ld.%06d seconds from start", (int) pid,
+ child->wp->config->name, buf, tv2.tv_sec,
(int) tv2.tv_usec);
+ } else {
+ zlog(ZLOG_STUFF, severity, "child %d (pool %s)
has been killed by the process managment after %ld.%06d seconds from start",
(int) pid,
+ child->wp->config->name, tv2.tv_sec, (int)
tv2.tv_usec);
+ }
fpm_child_close(child, 1 /* in event_loop */);
@@ -261,11 +279,13 @@
}
}
- fpm_children_make(wp, 1 /* in event loop */);
+ if (restart_child) {
+ fpm_children_make(wp, 1 /* in event loop */, 1);
- if (fpm_globals.is_child) {
- break;
- }
+ if (fpm_globals.is_child) {
+ break;
+ }
+ }
} else {
zlog(ZLOG_STUFF, ZLOG_ALERT, "oops, unknown child
exited %s", buf);
}
@@ -326,14 +346,24 @@
}
/* }}} */
-static int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop)
/* {{{ */
+int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int
nb_to_spawn) /* {{{ */
{
int enough = 0;
pid_t pid;
struct fpm_child_s *child;
+ int max;
- while (!enough && fpm_pctl_can_spawn_children() && wp->running_children
< wp->config->pm->max_children) {
+ if (wp->config->pm->style == PM_STYLE_DYNAMIC) {
+ if (!in_event_loop) { /* stating */
+ max = wp->config->pm->dynamic.start_servers;
+ } else {
+ max = wp->running_children + nb_to_spawn;
+ }
+ } else { /* PM_STYLE_STATIC */
+ max = wp->config->pm->max_children;
+ }
+ while (!enough && fpm_pctl_can_spawn_children() && wp->running_children
< max) {
child = fpm_resources_prepare(wp);
if (!child) {
@@ -378,7 +408,7 @@
int fpm_children_create_initial(struct fpm_worker_pool_s *wp) /* {{{ */
{
- return fpm_children_make(wp, 0 /* not in event loop yet */);
+ return fpm_children_make(wp, 0 /* not in event loop yet */, 0);
}
/* }}} */
Index: sapi/fpm/conf/php-fpm.conf.in
===================================================================
--- sapi/fpm/conf/php-fpm.conf.in (révision 292067)
+++ sapi/fpm/conf/php-fpm.conf.in (copie de travail)
@@ -72,7 +72,7 @@
<value name="pm">
Sets style of controling worker process count.
- Valid values are 'static' and 'apache-like'
+ Valid values are 'static' and 'dynamic'
<value name="style">static</value>
Sets the limit on the number of simultaneous
requests that will be served.
@@ -81,20 +81,20 @@
Used with any pm_style.
<value name="max_children">5</value>
- Settings group for 'apache-like' pm style
- <value name="apache_like">
+ Settings group for 'dynamic' pm style
+ <value name="dynamic">
Sets the number of server processes
created on startup.
- Used only when 'apache-like' pm_style
is selected
- <value name="StartServers">20</value>
+ Used only when 'dynamic' pm_style is
selected
+ <value name="start_servers">20</value>
Sets the desired minimum number of idle
server processes.
- Used only when 'apache-like' pm_style
is selected
- <value name="MinSpareServers">5</value>
+ Used only when 'dynamic' pm_style is
selected
+ <value
name="min_spare_servers">5</value>
Sets the desired maximum number of idle
server processes.
- Used only when 'apache-like' pm_style
is selected
- <value name="MaxSpareServers">35</value>
+ Used only when 'dynamic' pm_style is
selected
+ <value
name="max_spare_servers">35</value>
</value>
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php