dgaudet 97/07/23 21:32:32
Modified: src CHANGES http_main.c mod_status.c scoreboard.h
Log:
Exponential spawning, and a child_main optimization for single socket
servers.
Revision Changes Path
1.362 +10 -0 apache/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /export/home/cvs/apache/src/CHANGES,v
retrieving revision 1.361
retrieving revision 1.362
diff -u -r1.361 -r1.362
--- CHANGES 1997/07/24 04:23:55 1.361
+++ CHANGES 1997/07/24 04:32:27 1.362
@@ -1,5 +1,15 @@
Changes with Apache 1.3a2
+ *) child_main avoids an uneeded call to select() when there is only one
+ listening socket. [Dean Gaudet]
+
+ *) In the event that the server is starved for idle servers it will
+ spawn 1, then 2, then 4, ..., then 32 servers each second,
+ doubling each second. It'll also give a warning in the errorlog
+ since the most common reason for this is a poor StartServers
+ setting. The define MAX_SPAWN_RATE can be used to raise/lower
+ the maximum. [Dean Gaudet]
+
*) "nph-" CGIs were not compatible with HTTP/1.1 or SSL support because
they were passed a socket that connected directly to the client.
As such they would have to implement the transport level details
1.186 +82 -34 apache/src/http_main.c
Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_main.c,v
retrieving revision 1.185
retrieving revision 1.186
diff -u -r1.185 -r1.186
--- http_main.c 1997/07/22 23:51:58 1.185
+++ http_main.c 1997/07/24 04:32:28 1.186
@@ -1094,7 +1094,7 @@
sync_scoreboard_image();
new_score_rec = scoreboard_image->servers[child_num];
- new_score_rec.pid = getpid();
+ new_score_rec.x.pid = getpid();
old_status = new_score_rec.status;
new_score_rec.status = status;
@@ -1219,7 +1219,7 @@
int i;
for (i = 0; i < max_daemons_limit; ++i)
- if (scoreboard_image->servers[i].pid == pid)
+ if (scoreboard_image->servers[i].x.pid == pid)
return i;
return -1;
@@ -1233,7 +1233,7 @@
sync_scoreboard_image();
for (i = 0; i < max_daemons_limit; ++i) {
- int pid = scoreboard_image->servers[i].pid;
+ int pid = scoreboard_image->servers[i].x.pid;
if (pid != my_pid && pid != 0) {
int waitret = 0,
@@ -1304,7 +1304,7 @@
for (n = 0; n < max_daemons_limit; ++n) {
if (scoreboard_image->servers[n].status != SERVER_DEAD
- && waitpid (scoreboard_image->servers[n].pid, &status, WNOHANG)
+ && waitpid (scoreboard_image->servers[n].x.pid, &status,
WNOHANG)
== -1
&& errno == ECHILD) {
sync_scoreboard_image ();
@@ -1337,7 +1337,7 @@
if(scoreboard_image->servers[pi].status != SERVER_DEAD)
{
e[hi] = pi;
- h[hi++] = (HANDLE)scoreboard_image->servers[pi].pid;
+ h[hi++] = (HANDLE)scoreboard_image->servers[pi].x.pid;
}
}
@@ -1347,9 +1347,9 @@
if(rv == -1)
err = GetLastError();
if((WAIT_OBJECT_0 <= (unsigned int)rv) && ((unsigned int)rv <
(WAIT_OBJECT_0 + hi)))
- return(scoreboard_image->servers[e[rv - WAIT_OBJECT_0]].pid);
+ return(scoreboard_image->servers[e[rv -
WAIT_OBJECT_0]].x.pid);
else if((WAIT_ABANDONED_0 <= (unsigned int)rv) && ((unsigned
int)rv < (WAIT_ABANDONED_0 + hi)))
- return(scoreboard_image->servers[e[rv -
WAIT_ABANDONED_0]].pid);
+ return(scoreboard_image->servers[e[rv -
WAIT_ABANDONED_0]].x.pid);
}
}
@@ -2129,7 +2129,6 @@
#endif
while (1) {
- int errsave;
BUFF *conn_io;
request_rec *r;
@@ -2169,24 +2168,24 @@
accept_mutex_on(); /* Lock around "accept", if necessary */
for (;;) {
- memcpy(&main_fds, &listenfds, sizeof(fd_set));
- srv = ap_select(listenmaxfd+1, &main_fds, NULL, NULL, NULL);
- errsave = errno;
-
- sync_scoreboard_image();
- if (scoreboard_image->global.exit_generation >= generation)
- exit(0);
-
- errno = errsave;
- if (srv < 0 && errno != EINTR)
- log_unixerr("select", "(listen)", NULL, server_conf);
-
- if (srv <= 0)
- continue;
-
- lr = find_ready_listener(&main_fds);
- if (lr == NULL) continue;
- sd = lr->fd;
+ if (listeners->next != listeners) {
+ /* more than one socket */
+ memcpy(&main_fds, &listenfds, sizeof(fd_set));
+ srv = ap_select(listenmaxfd+1, &main_fds, NULL, NULL, NULL);
+
+ if (srv < 0 && errno != EINTR)
+ log_unixerr("select", "(listen)", NULL, server_conf);
+
+ if (srv <= 0)
+ continue;
+
+ lr = find_ready_listener(&main_fds);
+ if (lr == NULL) continue;
+ sd = lr->fd;
+ } else {
+ /* there's only one socket, just pretend we the other stuff */
+ sd = listeners->fd;
+ }
/* if we accept() something we don't want to die, so we have to
* defer the exit
@@ -2223,6 +2222,12 @@
/* ok maybe not, see ya later */
exit (0);
}
+ /* or maybe we missed a signal, you never know on systems
+ * without reliable signals
+ */
+ sync_scoreboard_image();
+ if (scoreboard_image->global.exit_generation >= generation)
+ exit(0);
}
accept_mutex_off(); /* unlock after "accept" */
@@ -2404,7 +2409,7 @@
* to the same word.)
* XXX: this needs to be sync'd to disk in the non shared memory stuff
*/
- scoreboard_image->servers[slot].pid = pid;
+ scoreboard_image->servers[slot].x.pid = pid;
return 0;
}
@@ -2427,16 +2432,34 @@
}
+/*
+ * 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.
+ */
+static int idle_spawn_rate = 1;
+#ifndef MAX_SPAWN_RATE
+#define MAX_SPAWN_RATE (32)
+#endif
+
static void perform_idle_server_maintenance (void)
{
int i;
int to_kill;
- int free_slot;
int idle_count;
+ int free_head;
+ int *free_ptr;
+ int free_length;
+
+ /* initialize the free_list */
+ free_head = -1;
+ free_ptr = &free_head;
+ free_length = 0;
- free_slot = -1;
to_kill = -1;
idle_count = 0;
+
sync_scoreboard_image ();
for (i = 0; i < daemons_limit; ++i) {
switch (scoreboard_image->servers[i].status) {
@@ -2452,8 +2475,10 @@
break;
case SERVER_DEAD:
/* try to keep children numbers as low as possible */
- if (free_slot == -1) {
- free_slot = i;
+ if (free_length < idle_spawn_rate) {
+ *free_ptr = i;
+ free_ptr = &scoreboard_image->servers[i].x.free_list;
+ ++free_length;
}
break;
}
@@ -2463,9 +2488,12 @@
* shut down gracefully, in case it happened to pick up a request
* while we were counting
*/
- kill (scoreboard_image->servers[to_kill].pid, SIGUSR1);
+ kill (scoreboard_image->servers[to_kill].x.pid, SIGUSR1);
+ idle_spawn_rate = 1;
} else if (idle_count < daemons_min_free) {
- if (free_slot == -1) {
+ /* terminate the free list */
+ *free_ptr = -1;
+ if (free_head == -1) {
/* only report this condition once */
static int reported = 0;
@@ -2476,8 +2504,28 @@
reported = 1;
}
} else {
- make_child (server_conf, free_slot);
+ if (idle_spawn_rate >= 4) {
+ log_printf (server_conf,
+ "server seems busy, spawning %d children (you may need "
+ "to increase StartServers, or Min/MaxSpareServers)",
+ idle_spawn_rate);
+ }
+ i = 0;
+ while (i < idle_spawn_rate && free_head != -1) {
+ int slot = free_head;
+ free_head = scoreboard_image->servers[free_head].x.free_list;
+ make_child (server_conf, slot);
+ ++i;
+ }
+ /* the next time around we want to spawn twice as many if this
+ * wasn't good enough
+ */
+ if (idle_spawn_rate < MAX_SPAWN_RATE) {
+ idle_spawn_rate *= 2;
+ }
}
+ } else {
+ idle_spawn_rate = 1;
}
}
1.54 +2 -2 apache/src/mod_status.c
Index: mod_status.c
===================================================================
RCS file: /export/home/cvs/apache/src/mod_status.c,v
retrieving revision 1.53
retrieving revision 1.54
diff -u -r1.53 -r1.54
--- mod_status.c 1997/07/17 22:27:41 1.53
+++ mod_status.c 1997/07/24 04:32:29 1.54
@@ -472,7 +472,7 @@
i,(int)conn_lres,my_lres,lres);
else
rprintf(r,"<b>Server %d</b> (%d): %d|%lu|%lu [",
- i,(int)score_record.pid,(int)conn_lres,my_lres,lres);
+ i,(int)score_record.x.pid,(int)conn_lres,my_lres,lres);
switch (score_record.status)
{
@@ -537,7 +537,7 @@
i,(int)conn_lres,my_lres,lres);
else
rprintf(r,"<tr><td><b>%d</b><td>%d<td>%d/%lu/%lu",
- i,(int)score_record.pid,(int)conn_lres,my_lres,lres);
+ i,(int)score_record.x.pid,(int)conn_lres,my_lres,lres);
switch (score_record.status)
{
1.27 +5 -2 apache/src/scoreboard.h
Index: scoreboard.h
===================================================================
RCS file: /export/home/cvs/apache/src/scoreboard.h,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -r1.26 -r1.27
--- scoreboard.h 1997/07/21 05:53:51 1.26
+++ scoreboard.h 1997/07/24 04:32:30 1.27
@@ -76,8 +76,11 @@
#define SERVER_GRACEFUL 8 /* server is gracefully finishing request */
typedef struct {
- pid_t pid;
- char status;
+ union {
+ pid_t pid; /* if it's not DEAD then this is the pid */
+ int free_list; /* otherwise this is scratch space */
+ } x;
+ int status;
#if defined(STATUS)
unsigned long access_count;
unsigned long bytes_served;