You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Aaron Bannert <aa...@clove.org> on 2001/09/20 18:34:05 UTC

[PATCH] fix MaxClients to match definition in worker MPM

I've been told by numerous people that MaxClients is defined as the
Maximum number of concurrent connections that the server is allowed
to handle. This patch makes the worker MPM to match that definition.

1) At the pre_config stage, it traverses the config tree and makes sure
  that ThreadsPerChild is set before MaxClients. I opted for copying
  the data rather than moving pointers (less error prone, the data is
  all pointers so it's quick, and it only happens once at starttime, so NBD).

2) As the directive runs set_server_limit(), a few extra checks
   and calculations happen:

  a) MaxClients must be greater than ThreadsPerChild
  b) A warning is issued if MaxClients is not a multiple of ThreadsPerChild
  c) ap_daemons_limit is calculated as the integer truncation of
      (MaxClients / ThreadsPerChild)
  d) Finally, the original check to make sure ap_daemons_limit does not
     exceed HARD_SERVER_LIMIT.

 (Note: none of the checks are fatal. Each produce a warning and continue
        with an approximated setting which is described in the warning.)


I shall follow up this posting with another patch to change the default
httpd.conf, as well as change the default worker MPM defaults to something
sane. For now, if you'd like to test this, I suggest:

<IfModule worker.c>
StartServers         2
MaxClients         150
MinSpareThreads     25
MaxSpareThreads     50
ThreadsPerChild     25
MaxRequestsPerChild  0
</IfModule>

(This config should be consistent with the prefork MPM now.)

-aaron


Index: server/mpm/worker/worker.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/mpm/worker/worker.c,v
retrieving revision 1.26
diff -u -r1.26 worker.c
--- server/mpm/worker/worker.c	2001/09/19 18:47:31	1.26
+++ server/mpm/worker/worker.c	2001/09/20 16:09:02
@@ -1422,7 +1422,45 @@
 {
     static int restart_num = 0;
     int no_detach, debug;
+    ap_directive_t *pdir;
+    ap_directive_t *max_clients = NULL;
 
+    /* make sure that "ThreadsPerChild" gets set before "MaxClients" */
+    for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) {
+        if (strncasecmp(pdir->directive, "ThreadsPerChild", 15) == 0) {
+            if (!max_clients) {
+                break; /* we're in the clear, got ThreadsPerChild first */
+            }
+            else {
+                /* now to swap the data */
+                ap_directive_t temp;
+
+                temp.directive = pdir->directive;
+                temp.args = pdir->args;
+                /* Make sure you don't change 'next', or you may get loops! */
+                /* XXX: first_child, parent, and data can never be set
+                 * for these directives, right? -aaron */
+                temp.filename = pdir->filename;
+                temp.line_num = pdir->line_num;
+
+                pdir->directive = max_clients->directive;
+                pdir->args = max_clients->args;
+                pdir->filename = max_clients->filename;
+                pdir->line_num = max_clients->line_num;
+                
+                max_clients->directive = temp.directive;
+                max_clients->args = temp.args;
+                max_clients->filename = temp.filename;
+                max_clients->line_num = temp.line_num;
+                break;
+            }
+        }
+        else if (!max_clients
+                && strncasecmp(pdir->directive, "MaxClients", 10) == 0) {
+            max_clients = pdir;
+        }
+    }
+
     debug = ap_exists_config_define("DEBUG");
 
     if (debug)
@@ -1515,21 +1553,52 @@
 static const char *set_server_limit (cmd_parms *cmd, void *dummy,
 				     const char *arg) 
 {
+    int max_clients;
     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
     if (err != NULL) {
         return err;
     }
 
-    ap_daemons_limit = atoi(arg);
+    /* It is ok to use ap_threads_per_child here because we are
+     * sure that it gets set before MaxClients in the pre_config stage. */
+    max_clients = atoi(arg);
+    if (max_clients < ap_threads_per_child) {
+       ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
+                    "WARNING: MaxClients (%d) must be at least as large",
+                    max_clients);
+       ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
+                    " large as ThreadsPerChild (%d). Automatically",
+                    ap_threads_per_child);
+       ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
+                    " increasing MaxClients to %d.",
+                    ap_threads_per_child);
+       max_clients = ap_threads_per_child;
+    }
+    ap_daemons_limit = max_clients / ap_threads_per_child;
+    if ((max_clients > 0) && (max_clients % ap_threads_per_child)) {
+       ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
+                    "WARNING: MaxClients (%d) is not an integer multiple",
+                    max_clients);
+       ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
+                    " of ThreadsPerChild (%d), lowering MaxClients to %d",
+                    ap_threads_per_child,
+                    ap_daemons_limit * ap_threads_per_child);
+       ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
+                    " for a maximum of %d child processes,",
+                    ap_daemons_limit);
+    }
     if (ap_daemons_limit > HARD_SERVER_LIMIT) {
+       ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
+                    "WARNING: MaxClients of %d would require %d servers,",
+                    max_clients, ap_daemons_limit);
        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
-                    "WARNING: MaxClients of %d exceeds compile time limit "
-                    "of %d servers,", ap_daemons_limit, HARD_SERVER_LIMIT);
+                    " and would exceed the compile time limit of %d.",
+                    HARD_SERVER_LIMIT);
        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
-                    " lowering MaxClients to %d.  To increase, please "
-                    "see the", HARD_SERVER_LIMIT);
+                    " Automatically lowering MaxClients to %d.  To increase,",
+                    HARD_SERVER_LIMIT);
        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
-                    " HARD_SERVER_LIMIT define in %s.",
+                    " please see the HARD_SERVER_LIMIT define in %s.",
                     AP_MPM_HARD_LIMITS_FILE);
        ap_daemons_limit = HARD_SERVER_LIMIT;
     }