]> granicus.if.org Git - apache/commitdiff
Speed up the server's response to a spike in incoming workload
authorGreg Ames <gregames@apache.org>
Sun, 5 Aug 2001 18:08:49 +0000 (18:08 +0000)
committerGreg Ames <gregames@apache.org>
Sun, 5 Aug 2001 18:08:49 +0000 (18:08 +0000)
or restarts.

New processes aren't able to start all their threads right away
if other dying processes share the same scoreboard real estate.
So give empty process slots in the scoreboard top priority.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@89928 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
server/mpm/threaded/threaded.c
server/mpm/worker/worker.c

diff --git a/CHANGES b/CHANGES
index 26dd0c0c6174dfde19af3b5facb4d80209f74b38..be88dea07790c73f20b55e522aa957059b61bb3a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
 Changes with Apache 2.0.23-dev
 
+  *) Speed up the server's response to a spike in incoming workload
+     or restarts by assigning empty scoreboard slots to new processes
+     when they are available.  [Greg Ames]
+
   *) Add a handler to mod_includes.c.  This handler is designed to
      implement the XbitHack directive.  This can't be done with a
      fixup, because we need to check the content-type, which is
index 76c45d4a5b688f84b6350c9a488dc57885a7ee25..68d7c63bbbc41cbf06e88e7997e7d1c0a32b5b58 100644 (file)
@@ -973,6 +973,7 @@ static void perform_idle_server_maintenance(void)
     worker_score *ws;
     process_score *ps;
     int free_length;
+    int totally_free_length = 0;
     int free_slots[MAX_SPAWN_RATE];
     int last_non_dead;
     int total_non_dead;
@@ -993,16 +994,21 @@ static void perform_idle_server_maintenance(void)
        int status = SERVER_DEAD;
        int any_dying_threads = 0;
        int any_dead_threads = 0;
+       int all_dead_threads = 1;
 
-       if (i >= ap_max_daemons_limit && free_length == idle_spawn_rate)
+       if (i >= ap_max_daemons_limit && totally_free_length == idle_spawn_rate)
            break;
         ps = &ap_scoreboard_image->parent[i];
        for (j = 0; j < ap_threads_per_child; j++) {
             ws = &ap_scoreboard_image->servers[i][j];
            status = ws->status;
 
+            /* XXX any_dying_threads is probably no longer needed    GLA */
            any_dying_threads = any_dying_threads || (status == SERVER_GRACEFUL);
            any_dead_threads = any_dead_threads || (status == SERVER_DEAD);
+           all_dead_threads = all_dead_threads &&
+                                   (status == SERVER_DEAD ||
+                                    status == SERVER_GRACEFUL);
 
            /* We consider a starting server as idle because we started it
             * at least a cycle ago, and if it still hasn't finished starting
@@ -1020,13 +1026,28 @@ static void perform_idle_server_maintenance(void)
                ++idle_thread_count;
            }
        }
-        /* XXX any_dead_threads may not be needed any more GLA */
-        if (any_dead_threads && free_length < idle_spawn_rate 
+        if (any_dead_threads && totally_free_length < idle_spawn_rate 
                 && (!ps->pid               /* no process in the slot */
                     || ps->quiescing)) {   /* or at least one is going away */
-           free_slots[free_length] = i;
+            if (all_dead_threads) {
+                /* great! we prefer these, because the new process can
+                 * start more threads sooner.  So prioritize this slot 
+                 * by putting it ahead of any slots with active threads.
+                 *
+                 * first, make room by moving a slot that's potentially still
+                 * in use to the end of the array
+                 */
+                free_slots[free_length] = free_slots[totally_free_length];
+                free_slots[totally_free_length++] = i;
+            }
+            else {
+                /* slot is still in use - back of the bus
+                 */
+               free_slots[free_length] = i;
+            }
            ++free_length;
        }
+        /* XXX if (!ps->quiescing)     is probably more reliable  GLA */
        if (!any_dying_threads) {
             last_non_dead = i;
             ++total_non_dead;
@@ -1057,7 +1078,9 @@ static void perform_idle_server_maintenance(void)
            idle_spawn_rate = 1;
        }
        else {
-           
+            if (free_length > idle_spawn_rate) {
+                free_length = idle_spawn_rate;
+            }
            if (idle_spawn_rate >= 8) {
                ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf,
                             "server seems busy, (you may need "
index 668a6c61eefcdac1a3c05d8f9b8c73882739c569..b272342293739f43811b9f19475404ae67b70158 100644 (file)
@@ -1023,6 +1023,7 @@ static void perform_idle_server_maintenance(void)
     worker_score *ws;
     process_score *ps;
     int free_length;
+    int totally_free_length = 0;
     int free_slots[MAX_SPAWN_RATE];
     int last_non_dead;
     int total_non_dead;
@@ -1043,16 +1044,21 @@ static void perform_idle_server_maintenance(void)
        int status = SERVER_DEAD;
        int any_dying_threads = 0;
        int any_dead_threads = 0;
+       int all_dead_threads = 1;
 
-       if (i >= ap_max_daemons_limit && free_length == idle_spawn_rate)
+       if (i >= ap_max_daemons_limit && totally_free_length == idle_spawn_rate)
            break;
         ps = &ap_scoreboard_image->parent[i];
        for (j = 0; j < ap_threads_per_child; j++) {
             ws = &ap_scoreboard_image->servers[i][j];
            status = ws->status;
 
+            /* XXX any_dying_threads is probably no longer needed    GLA */
            any_dying_threads = any_dying_threads || (status == SERVER_GRACEFUL);
            any_dead_threads = any_dead_threads || (status == SERVER_DEAD);
+           all_dead_threads = all_dead_threads &&
+                                   (status == SERVER_DEAD ||
+                                    status == SERVER_GRACEFUL);
 
            /* We consider a starting server as idle because we started it
             * at least a cycle ago, and if it still hasn't finished starting
@@ -1070,13 +1076,28 @@ static void perform_idle_server_maintenance(void)
                ++idle_thread_count;
            }
        }
-        /* XXX any_dead_threads may not be needed any more GLA */
-        if (any_dead_threads && free_length < idle_spawn_rate 
+        if (any_dead_threads && totally_free_length < idle_spawn_rate 
                 && (!ps->pid               /* no process in the slot */
                     || ps->quiescing)) {   /* or at least one is going away */
+            if (all_dead_threads) {
+                /* great! we prefer these, because the new process can
+                 * start more threads sooner.  So prioritize this slot 
+                 * by putting it ahead of any slots with active threads.
+                 *
+                 * first, make room by moving a slot that's potentially still
+                 * in use to the end of the array
+                 */
+                free_slots[free_length] = free_slots[totally_free_length];
+                free_slots[totally_free_length++] = i;
+            }
+            else {
+                /* slot is still in use - back of the bus
+                 */
            free_slots[free_length] = i;
+            }
            ++free_length;
        }
+        /* XXX if (!ps->quiescing)     is probably more reliable  GLA */
        if (!any_dying_threads) {
             last_non_dead = i;
             ++total_non_dead;
@@ -1107,7 +1128,9 @@ static void perform_idle_server_maintenance(void)
            idle_spawn_rate = 1;
        }
        else {
-           
+            if (free_length > idle_spawn_rate) {
+                free_length = idle_spawn_rate;
+            }
            if (idle_spawn_rate >= 8) {
                ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf,
                             "server seems busy, (you may need "