dougm       01/07/06 06:44:41

  Modified:    .        Changes
               lib/Apache SizeLimit.pm
  Log:
  Apache::SizeLimit enhancements [Perrin Harkins <[EMAIL PROTECTED]>]:
  - Added support for minimum shared memory and maximum unshared memory
  settings.
  - Added extra diagnostics to tell how many requests a process served,
  how long it lived, and how much shared memory it was using when
  SizeLimit killed it.
  
  Revision  Changes    Path
  1.602     +7 -0      modperl/Changes
  
  Index: Changes
  ===================================================================
  RCS file: /home/cvs/modperl/Changes,v
  retrieving revision 1.601
  retrieving revision 1.602
  diff -u -r1.601 -r1.602
  --- Changes   2001/06/21 16:11:40     1.601
  +++ Changes   2001/07/06 13:44:34     1.602
  @@ -10,6 +10,13 @@
   
   =item 1.25_01-dev
   
  +Apache::SizeLimit enhancements [Perrin Harkins <[EMAIL PROTECTED]>]:
  +- Added support for minimum shared memory and maximum unshared memory
  +settings.
  +- Added extra diagnostics to tell how many requests a process served,
  +how long it lived, and how much shared memory it was using when
  +SizeLimit killed it.
  +
   win32 enhancement: APACHE_SRC can be either the build or install tree
   [Randy Kobes <[EMAIL PROTECTED]>]
   
  
  
  
  1.8       +81 -24    modperl/lib/Apache/SizeLimit.pm
  
  Index: SizeLimit.pm
  ===================================================================
  RCS file: /home/cvs/modperl/lib/Apache/SizeLimit.pm,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- SizeLimit.pm      2000/12/20 18:51:56     1.7
  +++ SizeLimit.pm      2001/07/06 13:44:39     1.8
  @@ -12,7 +12,10 @@
   
       # in your startup.pl:
       use Apache::SizeLimit;
  -    $Apache::SizeLimit::MAX_PROCESS_SIZE = 10000; # in KB, so this is 10MB
  +    # sizes are in KB
  +    $Apache::SizeLimit::MAX_PROCESS_SIZE  = 10000; # 10MB
  +    $Apache::SizeLimit::MIN_SHARE_SIZE    = 1000;  # 1MB
  +    $Apache::SizeLimit::MAX_UNSHARED_SIZE = 12000; # 12MB
   
       # in your httpd.conf:
       PerlFixupHandler Apache::SizeLimit
  @@ -25,7 +28,9 @@
   
       # in your CGI:
       use Apache::SizeLimit;
  -    &Apache::SizeLimit::setmax(10000);       # Max Process Size in KB
  +    &Apache::SizeLimit::setmax(10000);               # Max size in KB
  +    &Apache::SizeLimit::setmin(1000);                # Min share in KB
  +    &Apache::SizeLimit::setmax_unshared(12000); # Max unshared size in KB
   
   Since checking the process size can take a few system calls on some
   platforms (e.g. linux), you may want to only check the process size every
  @@ -66,10 +71,29 @@
   technique shown in this module and set my MaxRequestsPerChild value to
   6000.
   
  +=head1 SHARED MEMORY OPTIONS
  +
  +In addition to simply checking the total size of a process, this
  +module can factor in how much of the memory used by the process is
  +actually being shared by copy-on-write.  If you don't understand how
  +memory is shared in this way, take a look at the mod_perl Guide at
  +http://perl.apache.org/guide/.
  +
  +You can take advantage of the shared memory information by setting a
  +minimum shared size and/or a maximum unshared size.  Experience on one
  +heavily trafficked mod_perl site showed that setting maximum unshared
  +size and leaving the others unset is the most effective policy.  This
  +is because it only kills off processes that are truly using too much
  +physical RAM, allowing most processes to live longer and reducing the
  +process churn rate.
  +
   =head1 CAVEATS
   
   This module is platform dependent, since finding the size of a process
  -is pretty different from OS to OS, and some platforms may not be supported.
  +is pretty different from OS to OS, and some platforms may not be
  +supported.  In particular, the limits on minimum shared memory and
  +maximum shared memory are currently only supported on Linux and BSD.
  +If you can contribute support for another OS, please do.
   
   Currently supported OSes:
   
  @@ -87,6 +111,7 @@
   
   For solaris we simply retrieve the size of /proc/self/as, which
   contains the address-space image of the process, and convert to KB.
  +Shared memory calculations are not supported.
   
   NOTE: This is only known to work for solaris 2.6 and above. Evidently
   the /proc filesystem has changed between 2.5.1 and 2.6. Can anyone
  @@ -99,7 +124,8 @@
   
   =item AIX?
   
  -Uses BSD::Resource::getrusage() to determine process size.
  +Uses BSD::Resource::getrusage() to determine process size.  Not sure if the
  +shared memory calculations will work or not.  AIX users?
   
   =back
   
  @@ -121,12 +147,17 @@
   use Config;
   use strict;
   use vars qw($VERSION $HOW_BIG_IS_IT $MAX_PROCESS_SIZE
  -         $REQUEST_COUNT $CHECK_EVERY_N_REQUESTS);
  +         $REQUEST_COUNT $CHECK_EVERY_N_REQUESTS
  +         $MIN_SHARE_SIZE $MAX_UNSHARED_SIZE $START_TIME);
   
   $VERSION = '0.03';
   $CHECK_EVERY_N_REQUESTS = 1;
   $REQUEST_COUNT = 1;
  +$MAX_PROCESS_SIZE  = 0;
  +$MIN_SHARE_SIZE    = 0;
  +$MAX_UNSHARED_SIZE = 0;
   
  +
   BEGIN {
       # decide at compile time how to check for a process' memory size.
       if (($Config{'osname'} eq 'solaris') &&
  @@ -148,45 +179,58 @@
   
   # return process size (in KB)
   sub linux_size_check {
  -    my $size = 0;
  +    my ($size, $resident, $share) = (0,0,0);
       local(*FH);
  -    if (open(FH, "</proc/self/status")) {
  -     while (<FH>) { last if (($size) = (/^VmRSS:\s+(\d+)/)) }
  +    if (open(FH, "</proc/self/statm")) {
  +     ($size, $resident, $share) = split(/\s/, scalar <FH>);
        close(FH);
       } else {
        &error_log("Fatal Error: couldn't access /proc/self/status");
       }
  -    return($size);
  +    # linux on intel x86 has 4KB page size...
  +    return($size*4, $share*4);
   }
   
   sub solaris_2_6_size_check {
       my $size = -s "/proc/self/as" or
        &error_log("Fatal Error: /proc/self/as doesn't exist or is empty");
       $size = int($size/1024); # to get it into kb
  -    return($size);
  +    return($size, 0); # return 0 for share, to avoid undef warnings
   }
   
   sub bsd_size_check {
  -    return( (&BSD::Resource::getrusage())[2] );
  +    return (&BSD::Resource::getrusage())[2,3];
   }
   
   sub exit_if_too_big {
       my $r = shift;
  -    return DECLINED if ($REQUEST_COUNT++ < $CHECK_EVERY_N_REQUESTS);
  -    $REQUEST_COUNT = 1;
  -    if ($MAX_PROCESS_SIZE) {
  -     my $size = &$HOW_BIG_IS_IT();
  -     if ($size > $MAX_PROCESS_SIZE) {
  -         # I have no idea if this will work on anything but UNIX
  -         if (getppid > 1) {  # this is a  child httpd
  -             error_log("httpd process too big, exiting at SIZE=$size KB");
  +    return DECLINED if ($CHECK_EVERY_N_REQUESTS &&
  +     ($REQUEST_COUNT++ % $CHECK_EVERY_N_REQUESTS));
  +
  +    $START_TIME ||= time;
  +
  +    my($size, $share) = &$HOW_BIG_IS_IT();
  +
  +    if (($MAX_PROCESS_SIZE && $size > $MAX_PROCESS_SIZE)
  +                        ||
  +     ($MIN_SHARE_SIZE && $share < $MIN_SHARE_SIZE)
  +                        ||
  +     ($MAX_UNSHARED_SIZE && ($size - $share) > $MAX_UNSHARED_SIZE)) {
  +
  +         # wake up! time to die.
  +         if (getppid > 1) {  # this is a child httpd
  +             my $e = time - $START_TIME;
  +             my $msg = "httpd process too big, exiting at SIZE=$size KB ";
  +             $msg .= " SHARE=$share KB " if ($share);
  +                $msg .= " REQUESTS=$REQUEST_COUNT  LIFETIME=$e seconds";
  +             error_log($msg);
                $r->child_terminate;
  -         } else {            # this is the main httpd
  -             error_log("main process too big, SIZE=$size KB");
  +
  +         } else {    # this is the main httpd, whose parent is init?
  +             my $msg = "main process too big, exiting at SIZE=$size KB ";
  +             $msg .= " SHARE=$share KB" if ($share);
  +             error_log($msg);
            }
  -     }
  -    } else {
  -     error_log("you didn't set \$Apache::SizeLimit::MAX_PROCESS_SIZE");
       }
       return OK;
   }
  @@ -198,6 +242,16 @@
       Apache->request->post_connection(\&exit_if_too_big);
   }
   
  +sub setmin {
  +    $MIN_SHARE_SIZE = shift;
  +    Apache->request->post_connection(\&exit_if_too_big);
  +}
  +
  +sub setmax_unshared {
  +    $MAX_UNSHARED_SIZE = shift;
  +    Apache->request->post_connection(\&exit_if_too_big);
  +}
  +
   sub handler {
       my $r = shift || Apache->request;
       $r->post_connection(\&exit_if_too_big)
  @@ -216,5 +270,8 @@
   Doug Bagley <[EMAIL PROTECTED]>, channeling Procrustes.
   
   Brian Moseley <[EMAIL PROTECTED]>: Solaris 2.6 support
  +
  +Doug Steinwand and Perrin Harkins <[EMAIL PROTECTED]>: added support 
  +    for shared memory and additional diagnostic info
   
   =cut
  
  
  

Reply via email to