Received: (from majordom@localhost) by hyperreal.org (8.8.5/8.8.5) id VAA01317; Wed, 23 Jul 1997 21:32:36 -0700 (PDT) Received: (from dgaudet@localhost) by hyperreal.org (8.8.5/8.8.5) id VAA01285 for apache-cvs; Wed, 23 Jul 1997 21:32:33 -0700 (PDT) Date: Wed, 23 Jul 1997 21:32:33 -0700 (PDT) From: Dean Gaudet Message-Id: <199707240432.VAA01285@hyperreal.org> To: apache-cvs@hyperreal.org Subject: cvs commit: apache/src CHANGES http_main.c mod_status.c scoreboard.h Sender: apache-cvs-owner@apache.org Precedence: bulk Reply-To: new-httpd@apache.org 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,"Server %d (%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,"%d%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) { 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;