]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
mpm_event: Follow up to r1894285: new MaxSpareThreads heuristics.
authorYann Ylavic <ylavic@apache.org>
Fri, 3 Dec 2021 13:25:51 +0000 (13:25 +0000)
committerYann Ylavic <ylavic@apache.org>
Fri, 3 Dec 2021 13:25:51 +0000 (13:25 +0000)
When at MaxSpareThreads, instead of deferring the stop if we are close to
active/server limit let's wait for the pending exits to complete.

This way we always and accurately account for slow-to-exit processes to
avoid filling up the scoreboard, whether at the limits or not.

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

server/mpm/event/event.c

index c32f07da1b851bd61903b10f0fc43bfe098112ba..c3f4775ea9aec8c28991cb575162994fb07335ba 100644 (file)
@@ -3179,16 +3179,15 @@ static void perform_idle_server_maintenance(int child_bucket)
         }
     }
 
-    if (idle_thread_count > max_spare_threads / num_buckets)
-    {
+    if (idle_thread_count > max_spare_threads / num_buckets) {
         /*
          * Child processes that we ask to shut down won't die immediately
          * but may stay around for a long time when they finish their
          * requests. If the server load changes many times, many such
          * gracefully finishing processes may accumulate, filling up the
          * scoreboard. To avoid running out of scoreboard entries, we
-         * don't shut down more processes when the total number of processes
-         * is high, until there are more than max_workers/4 idle threads.
+         * don't shut down more processes if there are stopping ones
+         * already (i.e. active_daemons < total_daemons).
          *
          * XXX It would be nice if we could
          * XXX - kill processes without keepalive connections first
@@ -3196,26 +3195,21 @@ static void perform_idle_server_maintenance(int child_bucket)
          * XXX   depending on server load, later be able to resurrect them
          *       or kill them
          */
-        if ((retained->total_daemons <= active_daemons_limit
-             && retained->total_daemons < server_limit)
-            /* The above test won't transition from true to false until a child
-             * exits by itself (i.e. MaxRequestsPerChild reached), so the below
-             * test makes sure that the situation unblocks when the load falls
-             * significantly (regardless of MaxRequestsPerChild, e.g. 0) */
-            || idle_thread_count > max_workers/4 / num_buckets) {
-            /* Kill off one child */
+        int ignore = (retained->active_daemons < retained->total_daemons);
+        ap_log_error(APLOG_MARK, APLOG_TRACE5, 0, ap_server_conf,
+                     "%shutting down one child: "
+                     "active daemons %d / active limit %d / "
+                     "total daemons %d / ServerLimit %d / "
+                     "idle threads %d / max workers %d",
+                     (ignore) ? "Not s" : "S",
+                     retained->active_daemons, active_daemons_limit,
+                     retained->total_daemons, server_limit,
+                     idle_thread_count, max_workers);
+        if (!ignore) {
             ap_mpm_podx_signal(retained->buckets[child_bucket].pod,
                                AP_MPM_PODX_GRACEFUL);
-            retained->idle_spawn_rate[child_bucket] = 1;
-        } else {
-            /* Still busy enough, don't kill */
-            ap_log_error(APLOG_MARK, APLOG_TRACE5, 0, ap_server_conf,
-                         "Not shutting down child: total daemons %d / "
-                         "active limit %d / ServerLimit %d / "
-                         "idle threads %d / max workers %d",
-                         retained->total_daemons, active_daemons_limit,
-                         server_limit, idle_thread_count, max_workers);
         }
+        retained->idle_spawn_rate[child_bucket] = 1;
     }
     else if (idle_thread_count < min_spare_threads / num_buckets) {
         if (active_thread_count >= max_workers / num_buckets) {