httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject [PATCH] incomplete: scoreboard work
Date Tue, 26 Aug 1997 08:47:20 GMT
Here is some work that definately includes bug fixes, fixes for some
pathologies I've seen while playing with the new scoreboard code.
It's definately not in a ready-to-commit state yet, needs a little
cleanup.  But just shout if you see something that looks obscene.

I'm really considering raising SCOREBOARD_MAINTENANCE_INTERVAL to 5s
from 1s.  It seems to respond just as nicely to problems.  But timer
granularity is now tied to the maintenance interval ... so 5s means
timers might be late by up to 10s.

Uh Doug, remember that x.pid and x.free_list thing in the scoreboard?
This patch makes it obsolete ... but I haven't deleted it.  Sorry that
I forced you to change mod_perl.  I'll probably clean this up again.

Dean

Index: main/http_main.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_main.c,v
retrieving revision 1.210
diff -u -r1.210 http_main.c
--- http_main.c	1997/08/26 00:00:55	1.210
+++ http_main.c	1997/08/26 08:38:18
@@ -1,3 +1,4 @@
+#define SCOREBOARD_MAINTENANCE_INTERVAL 5000000
 /* ====================================================================
  * Copyright (c) 1995-1997 The Apache Group.  All rights reserved.
  *
@@ -243,6 +244,9 @@
 #endif
 
 static scoreboard *scoreboard_image = NULL;
+#ifdef OPTIMIZE_TIMEOUTS
+static parent_score parent_scoreboard[HARD_SERVER_LIMIT];
+#endif
 
 /* small utility macros to make things easier to read */
 
@@ -1464,7 +1468,7 @@
 #endif
 
 #if defined(STATUS)
-#ifdef OPTIMIZE_TIMEOUTS
+#ifdef XXXXOPTIMIZE_TIMEOUTS
     ss->last_used = ss->last_rtime;	/* close enough */
 #else
     ss->last_used=time(NULL);
@@ -2860,7 +2864,7 @@
     }    
 }
 
-static int make_child(server_rec *s, int slot)
+static int make_child(server_rec *s, int slot, time_t now)
 {
     int pid;
 
@@ -2868,6 +2872,10 @@
 	max_daemons_limit = slot + 1;
     }
 
+#ifdef XXXXOPTIMIZE_TIMEOUTS
+    scoreboard_image->servers[slot].last_rtime = now;
+#endif
+
     if (one_process) {
 	signal (SIGHUP, just_die);
 	signal (SIGTERM, just_die);
@@ -2924,12 +2932,13 @@
 static void startup_children (int number_to_start)
 {
     int i;
+    time_t now = time(0);
 
     for (i = 0; number_to_start && i < daemons_limit; ++i ) {
 	if (scoreboard_image->servers[i].status != SERVER_DEAD) {
 	    continue;
 	}
-	if (make_child (server_conf, i) < 0) {
+	if (make_child (server_conf, i, now) < 0) {
 	    break;
 	}
 	--number_to_start;
@@ -2954,26 +2963,32 @@
     int i;
     int to_kill;
     int idle_count;
-    int free_head;
-    int *free_ptr;
-    int free_length;
     short_score *ss;
-#ifdef OPTIMIZE_TIMEOUTS
-    time_t now = time(0);
-#endif
+    time_t now;
+    int free_length;
+    int free_slots[MAX_SPAWN_RATE];
+    int last_non_dead;
+
+    now = time(0);
 
     /* initialize the free_list */
-    free_head = -1;
-    free_ptr = &free_head;
     free_length = 0;
 
     to_kill = -1;
     idle_count = 0;
+    last_non_dead = -1;
 
     sync_scoreboard_image ();
     for (i = 0; i < daemons_limit; ++i) {
+	if (i >= max_daemons_limit && free_length == idle_spawn_rate) break;
 	ss = &scoreboard_image->servers[i];
 	switch (ss->status) {
+	    /* We consider a starting server as idle because we started it
+	     * at least a cycle ago, and if it still hasn't finished starting
+	     * then we're just going to swamp things worse by forking more.
+	     * So we hopefully won't need to fork more if we count it.
+	     */
+	case SERVER_STARTING:
 	case SERVER_READY:
 	    ++idle_count;
 	    /* always kill the highest numbered child if we have to...
@@ -2987,28 +3002,33 @@
 	case SERVER_DEAD:
 	    /* try to keep children numbers as low as possible */
 	    if (free_length < idle_spawn_rate) {
-		*free_ptr = i;
-		free_ptr = &scoreboard_image->servers[i].x.free_list;
+		free_slots[free_length] = i;
 		++free_length;
 	    }
 	    break;
 	}
+	if (ss->status != SERVER_DEAD) {
+	    last_non_dead = i;
 #ifdef OPTIMIZE_TIMEOUTS
-	if (ss->status != SERVER_DEAD && ss->timeout_len) {
-	    /* if it's a live server, with a live timeout then start checking
-	     * its timeout */
-	    if (ss->cur_vtime != ss->last_vtime) {
-		/* it has made progress, so update its last_rtime, last_vtime */
-		ss->last_rtime = now;
-		ss->last_vtime = ss->cur_vtime;
-	    } else if (ss->last_rtime + ss->timeout_len < now) {
-		/* no progress, and the timeout length has been exceeded */
-		ss->timeout_len = 0;
-		kill (ss->x.pid, SIGALRM);
+	    if (ss->timeout_len) {
+		/* if it's a live server, with a live timeout then
+		 * start checking its timeout */
+		parent_score *ps = &parent_scoreboard[i];
+		if (ss->cur_vtime != ps->last_vtime) {
+		    /* it has made progress, so update its last_rtime,
+		     * last_vtime */
+		    ps->last_rtime = now;
+		    ps->last_vtime = ss->cur_vtime;
+		} else if (ps->last_rtime + ss->timeout_len < now) {
+		    /* no progress, and the timeout length has been exceeded */
+		    ss->timeout_len = 0;
+		    kill (ss->x.pid, SIGALRM);
+		}
 	    }
-	}
 #endif
+	}
     }
+    max_daemons_limit = last_non_dead + 1;
     if (idle_count > daemons_max_free) {
 	/* kill off one child... we use SIGUSR1 because that'll cause it to
 	 * shut down gracefully, in case it happened to pick up a request
@@ -3018,8 +3038,7 @@
 	idle_spawn_rate = 1;
     } else if (idle_count < daemons_min_free) {
 	/* terminate the free list */
-	*free_ptr = -1;
-	if (free_head == -1) {
+	if (free_length == 0) {
 	    /* only report this condition once */
 	    static int reported = 0;
 
@@ -3029,6 +3048,7 @@
 		    " raising the MaxClients setting");
 		reported = 1;
 	    }
+	    idle_spawn_rate = 1;
 	} else {
 	    if (idle_spawn_rate >= 4) {
 		log_printf (server_conf,
@@ -3036,12 +3056,8 @@
 		    "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;
+	    for (i = 0; i < free_length; ++i) {
+		make_child (server_conf, free_slots[i], now);
 	    }
 	    /* the next time around we want to spawn twice as many if this
 	     * wasn't good enough, but not if we've just done a graceful
@@ -3164,10 +3180,8 @@
 			/* we're still doing a 1-for-1 replacement of dead
 			 * children with new children
 			 */
-			make_child (server_conf, child_slot);
+			make_child (server_conf, child_slot, time(0));
 			--remaining_children_to_start;
-			/* don't perform idle maintenance yet */
-			continue;
 		    }
 		} else if (is_graceful) {
 		    /* Great, we've probably just lost a slot in the
@@ -3177,6 +3191,12 @@
 		    log_printf (server_conf,
 			"long lost child came home! (pid %d)", pid );
 		}
+		/* Don't perform idle maintenance when a child dies,
+		 * only do it when there's a timeout.  Remember only a
+		 * finite number of children can die, and it's pretty
+		 * pathological for a lot to die suddenly.
+		 */
+		continue;
 	    } else if (remaining_children_to_start) {
 		/* we hit a 1 second timeout in which none of the previous
 	 	 * generation of children needed to be reaped... so assume
Index: main/scoreboard.h
===================================================================
RCS file: /export/home/cvs/apachen/src/main/scoreboard.h,v
retrieving revision 1.28
diff -u -r1.28 scoreboard.h
--- scoreboard.h	1997/08/17 11:40:14	1.28
+++ scoreboard.h	1997/08/26 08:38:18
@@ -96,8 +96,6 @@
 	int free_list;		/* otherwise this is scratch space */
     } x;
 #ifdef OPTIMIZE_TIMEOUTS
-    vtime_t last_vtime;		/* the last vtime the parent has seen */
-    time_t last_rtime;		/* time(0) of the last change */
     vtime_t cur_vtime;		/* the child's current vtime */
     unsigned short timeout_len;	/* length of the timeout */
 #endif
@@ -135,6 +133,14 @@
     short_score servers[HARD_SERVER_LIMIT];
     global_score global;
     } scoreboard;
+
+
+#ifdef OPTIMIZE_TIMEOUTS
+typedef struct {
+    time_t last_rtime;		/* time(0) of the last change */
+    vtime_t last_vtime;		/* the last vtime the parent has seen */
+} parent_score;
+#endif
 
 #define SCOREBOARD_SIZE		sizeof(scoreboard)
 


Mime
View raw message