httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrew Wilson <and...@www.elsevier.co.uk>
Subject Things and stuff... (long)
Date Mon, 03 Apr 1995 15:22:03 GMT

My new sys-admin picked this up from some list or other (good sys-admin, have
a biscuit...)  Anyone got any quick comments on the 3 patches offered here?
They're quite meaty.

Cheers,
Ay.

     Andrew Wilson	     URL: http://www.cm.cf.ac.uk/User/Andrew.Wilson/
Elsevier Science, Oxford   Office: +44 0865 843155     Mobile: +44 0589 616144


----- Begin Included Message -----

Newsgroups: comp.unix.solaris,comp.infosystems.www.providers

>From appro Wed Oct 19 15:32:42 1994
To: httpd@ncsa.uiuc.edu
Subject: Turbocharging httpd 1.3

Hi!

I was setting up NCSA httpd 1.3 under Solaris 2.3 and have run into
performance problem. I mean I've found my server unresonably slow. So I
had a look at source code and found three ways to improve performance.
In my setup performance improvement was simply dramatic and you'll sure
see why...

1. Actually I call this problem "automounter bug". You see I have
   document root tree in automounted directory (I want it there,
   because it's backed up daily in my place). I've found that the
   server spends a lot of time trying to mount
   /automounteddir/.htaccess. And this turned to be really "expensive"
   operation, I'm talking about ~1.5 seconds per request!  And indeed,
   httpd looks for .htaccess files in the whole tree starting in /. I do
   believe the real intension was to check .htaccess files in document
   tree only.  So I did as following:

---------------------------cut here-----------------------------------
*** http_access.c.orig  Tue Oct 18 16:02:18 1994
--- http_access.c       Wed Oct 19 11:41:48 1994
***************
*** 133,139 ****
      if((override[n]) || (!(opts[n] & OPT_SYM_LINKS)) || 
         (opts[n] & OPT_SYM_OWNER))
          {
!             for(x=0;x<num_dirs;x++) {
                  y = num_sec;
                  make_dirstr(path,x+1,d);
                  if((!(opts[x] & OPT_SYM_LINKS)) || (opts[x] &
OPT_SYM_OWNER)) {
--- 133,139 ----
      if((override[n]) || (!(opts[n] & OPT_SYM_LINKS)) || 
         (opts[n] & OPT_SYM_OWNER))
          {
!             for(x=tackle_on_docroot(path);x<num_dirs;x++) {
                  y = num_sec;
                  make_dirstr(path,x+1,d);
                  if((!(opts[x] & OPT_SYM_LINKS)) || (opts[x] &
OPT_SYM_OWNER)) {
*** http_alias.c.orig   Tue Oct 18 15:02:07 1994
--- http_alias.c        Wed Oct 19 11:42:36 1994
***************
*** 112,114 ****
--- 112,128 ----
          }
      }
  }
+ 
+ int tackle_on_docroot(char *name) {
+     register int x,l;
+ 
+     l=strlen(document_root);
+     if(!strncmp(name,document_root,l))
+         return count_dirs(document_root);
+     for(x=0;x < num_a; x++) {
+         l=strlen(a[x].real);
+         if(!strncmp(name,a[x].real,l))
+           return count_dirs(a[x].real);
+     }
+     return 0;
+ }
---------------------------cut here-----------------------------------

2. The second workaround takes its origin in the fact that I run NIS+.
   Well, the problem would be still there even if I would run YP.
   Referencies to NIS are also rather "expensive", it's not seconds,
   but it's not milliseconds either, it's tenths of second with NIS+
   and one can feel it, if I have a number of for example GIF pictures
   in my HTML page. Workaround is to cache group IDs set for user ID
   assigned to serve http requests:

---------------------------cut here-----------------------------------
*** httpd.c.orig        Wed Oct 19 09:33:03 1994
--- httpd.c     Wed Oct 19 11:44:37 1994
***************
*** 90,95 ****
--- 90,116 ----
  
  void set_signals();
  
+ static int   target_ngids;
+ static gid_t target_gid_set [NGROUPS_MAX];
+ 
+ get_groupset ()
+ { int n_gids;
+   gid_t current_gid_set [NGROUPS_MAX];
+   struct passwd* pwent;
+     if (!getuid())
+     {  if ((n_gids = getgroups (NGROUPS_MAX,current_gid_set)) < 0)
+           die(SERVER_ERROR,"couldn't determine group IDs set",stdout);
+        if ((pwent = getpwuid(user_id)) == NULL)
+           die(SERVER_ERROR,"couldn't determine user name from uid",stdout);
+        /* Reset `groups' attribute. */
+        if (initgroups(pwent->pw_name, group_id) == -1)
+           die(SERVER_ERROR,"unable to setgroups",stdout);
+        if ((target_ngids = getgroups (NGROUPS_MAX,target_gid_set)) < 0)
+           die(SERVER_ERROR,"unable to get target group IDs set",stdout);
+        setgroups (n_gids,current_gid_set);
+     }
+ }
+ 
  void restart() {
      log_error_noclose("httpd: caught SIGHUP, restarting");
      kill_mime();
***************
*** 104,109 ****
--- 125,131 ----
      open_logs();
      log_error_noclose("httpd: successful restart");
      get_local_host();
+     get_groupset ();
      set_signals();
  }
  
***************
*** 154,159 ****
--- 176,182 ----
      }
      listen(sd,5);
  
+     get_groupset ();
      set_signals();
      log_pid();
  
***************
*** 174,180 ****
          if((pid = fork()) == -1)
              log_error("unable to fork new process");
          else if(!pid) {
-           struct passwd* pwent;
              struct linger sl;
  
              sl.l_onoff = 1;
--- 197,202 ----
***************
*** 196,208 ****
              if(!getuid()) {
                  /* Now, make absolutely certain we don't have any privileges
                   * except those mentioned in the configuration file. */
!                 if ((pwent = getpwuid(user_id)) == NULL)
!                     die(SERVER_ERROR,"couldn't determine user name from uid",
!                         stdout);
!                 /* Reset `groups' attribute. */
!                 if (initgroups(pwent->pw_name, group_id) == -1)
!                     die(SERVER_ERROR,"unable to setgroups",stdout);
! 
                  /* Note the order, first setgid() and then setuid(), it
                   * wouldn't work the other way around. */
                  if (setgid(group_id) == -1)
--- 218,224 ----
              if(!getuid()) {
                  /* Now, make absolutely certain we don't have any privileges
                   * except those mentioned in the configuration file. */
!                 setgroups (target_ngids,target_gid_set);
                  /* Note the order, first setgid() and then setuid(), it
                   * wouldn't work the other way around. */
                  if (setgid(group_id) == -1)
*** httpd.h.orig        Wed Oct 19 09:57:43 1994
--- httpd.h     Wed Oct 19 09:58:27 1994
***************
*** 346,351 ****
--- 346,352 ----
  #include <pwd.h>
  #include <grp.h>
  #include <fcntl.h>
+ #include <limits.h>
  
  #ifndef NEXT
  #include <unistd.h>
---------------------------cut here-----------------------------------

3. This workaround is not actually workaround, but rather matter of
   taste. Actually it was the first thing I've thought of and
   implemented. Idea is to get rid of numerious read(fd,&c,1) system
   calls in utils.c:getline() function and replace it with function
   calls. Arithmetic is simple: instead of having >1000
   going-to-kernel system calls, I have just few system calls and >1000
   stay-in-user-mode function calls. Well, the cost of a system call
   (at least under Solaris 2.x) not only context switching, it's rising
   process priority as well, so that patched following way httpd would
   leave more CPU time for interactive processes under heavy loads:

---------------------------cut here-----------------------------------
*** util.c.orig Tue Oct 18 16:14:49 1994
--- util.c      Wed Oct 19 11:47:18 1994
***************
*** 266,278 ****
      exit(0);
  }
  
  int getline(char *s, int n, int f, unsigned int timeout) {
      register int i=0, ret;
  
-     signal(SIGALRM,getline_timed_out);
-     alarm(timeout);
      while(1) {
!         if((ret = read(f,&s[i],1)) <= 0) {
              /* Mmmmm, Solaris.  */
              if((ret == -1) && (errno == EINTR))
                  continue;
--- 266,303 ----
      exit(0);
  }
  
+ int my_read_timeout (int fd,char *buf,int l,int tout)
+ { static char buffer [2048];
+   static int  in_buffer=0, cnt=0;
+   int ret=0,n;
+   struct pollfd pollset;
+     if (tout > 0) tout *= 1000;
+     while (l)
+     {  if (cnt == in_buffer)
+        {  cnt = in_buffer = 0;
+           pollset.fd = fd,
+           pollset.events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI;
+           n=poll(&pollset,1,tout);
+           if (n < 0)
+           {  if (errno == EAGAIN || errno == EINTR) continue;
+              else return -1;
+           }
+           else if (n == 0)
+           {  getline_timed_out (SIGALRM); /* NOT REACHED */ return -1; }
+           if ((n=read (fd,buffer,sizeof(buffer))) <= 0)
+              return (ret ? ret : n);
+           in_buffer = n;
+        }
+        *(buf++) = buffer [cnt++], l--, ret++;
+     }
+     return ret;
+ }
+ 
  int getline(char *s, int n, int f, unsigned int timeout) {
      register int i=0, ret;
  
      while(1) {
!         if((ret = my_read_timeout(f,&s[i],1,timeout)) <= 0) {
              /* Mmmmm, Solaris.  */
              if((ret == -1) && (errno == EINTR))
                  continue;
***************
*** 281,291 ****
          }
  
          if(s[i] == CR)
!             read(f,&s[i],1);
  
          if((s[i] == LF) || (i == (n-1))) {
-             alarm(0);
-             signal(SIGALRM,SIG_IGN);
              s[i] = '\0';
              return 0;
          }
--- 306,314 ----
          }
  
          if(s[i] == CR)
!             my_read_timeout(f,&s[i],1,timeout);
  
          if((s[i] == LF) || (i == (n-1))) {
              s[i] = '\0';
              return 0;
          }
*** http_auth.c.orig    Tue Oct 18 17:48:57 1994
--- http_auth.c Wed Oct 19 11:48:35 1994
***************
*** 246,252 ****
          char buf[1024];
          int n,t;
          t = content_length-nr;
!         if((n = read(sfd,buf,(t > 1024 ? 1024 : t))) < 1) {
              close(tfd);
              unlink(tn);
              die(SERVER_ERROR,"Failed to read the full encrypted
request",*out);
--- 246,252 ----
          char buf[1024];
          int n,t;
          t = content_length-nr;
!         if((n = my_read_timeout(sfd,buf,(t > 1024 ? 1024 : t),1200)) < 1) {
              close(tfd);
              unlink(tn);
              die(SERVER_ERROR,"Failed to read the full encrypted
request",*out);
---------------------------cut here-----------------------------------


Thanks for your time. Andy.
=========================================================================
Andy Polyakov,  System Manager
-------------------------------------------------------------------------
E-Mail: appro@fy.chalmers.se    | Mail: Fysikgrand 3
                                |       Chalmers University of Technology
Phone:  +46(31)7723390          |       S-412 96 Goteborg
FAX:    +46(31)7723471          |       Sweden
-------------------------------------------------------------------------

----- End Included Message -----


Mime
View raw message