Author: autarch Date: Wed Jul 5 08:19:00 2006 New Revision: 419253 URL: http://svn.apache.org/viewvc?rev=419253&view=rev Log: All of these changes come from reviewing the code with Perrin at YAPC ...
* Increase the version number to 0.9. This thing has been around forever, so hopefully we think it works reasonably well ;) * Change the Win32 code to use the same style as everything else in the file. * Remove the "goto" bit in _linux_smaps_size_check() and just use a normal sub call. * Lots of doc changes. Still lots to do to give it a modern API and deprecate the current one. Modified: perl/Apache-SizeLimit/trunk/lib/Apache/SizeLimit.pm Modified: perl/Apache-SizeLimit/trunk/lib/Apache/SizeLimit.pm URL: http://svn.apache.org/viewvc/perl/Apache-SizeLimit/trunk/lib/Apache/SizeLimit.pm?rev=419253&r1=419252&r2=419253&view=diff ============================================================================== --- perl/Apache-SizeLimit/trunk/lib/Apache/SizeLimit.pm (original) +++ perl/Apache-SizeLimit/trunk/lib/Apache/SizeLimit.pm Wed Jul 5 08:19:00 2006 @@ -30,7 +30,7 @@ $USE_SMAPS ); -$VERSION = '0.06'; +$VERSION = '0.9'; $CHECK_EVERY_N_REQUESTS = 1; $REQUEST_COUNT = 1; $MAX_PROCESS_SIZE = 0; @@ -87,7 +87,7 @@ } sub _linux_smaps_size_check { - goto &linux_size_check unless $USE_SMAPS; + return _linux_size_check() unless $USE_SMAPS; my $s = Linux::Smaps->new($$)->all; return ($s->size, $s->shared_clean + $s->shared_dirty); @@ -123,13 +123,13 @@ sub _win32_size_check { # get handle on current process - my $GetCurrentProcess = Win32::API->new( + my $get_current_process = Win32::API->new( 'kernel32', - 'GetCurrentProcess', + 'get_current_process', [], 'I' ); - my $hProcess = $GetCurrentProcess->Call(); + my $proc = $get_current_process->Call(); # memory usage is bundled up in ProcessMemoryCounters structure # populated by GetProcessMemoryInfo() win32 call @@ -138,39 +138,29 @@ # build a buffer structure to populate my $pmem_struct = "$DWORD" x 2 . "$SIZE_T" x 8; - my $pProcessMemoryCounters + my $mem_counters = pack( $pmem_struct, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); # GetProcessMemoryInfo is in "psapi.dll" - my $GetProcessMemoryInfo = new Win32::API( + my $get_process_memory_info = new Win32::API( 'psapi', 'GetProcessMemoryInfo', [ 'I', 'P', 'I' ], 'I' ); - my $bool = $GetProcessMemoryInfo->Call( - $hProcess, - $pProcessMemoryCounters, - length($pProcessMemoryCounters) + my $bool = $get_process_memory_info->Call( + $proc, + $mem_counters, + length $mem_counters, ); # unpack ProcessMemoryCounters structure - my ( - $cb, - $PageFaultCount, - $PeakWorkingSetSize, - $WorkingSetSize, - $QuotaPeakPagedPoolUsage, - $QuotaPagedPoolUsage, - $QuotaPeakNonPagedPoolUsage, - $QuotaNonPagedPoolUsage, - $PagefileUsage, - $PeakPagefileUsage - ) = unpack( $pmem_struct, $pProcessMemoryCounters ); + my $peak_working_set_size = + ( unpack( $pmem_struct, $mem_counters ) )[2]; # only care about peak working set size - my $size = int( $PeakWorkingSetSize / 1024 ); + my $size = int( $peak_working_set_size / 1024 ); return ( $size, 0 ); } @@ -220,8 +210,8 @@ return OK; } -# setmax can be called from within a CGI/Registry script to tell the httpd -# to exit if the CGI causes the process to grow too big. +# setmax can be called from within a Registry script to tell the server +# to exit if the script causes the process to grow too big. sub setmax { $MAX_PROCESS_SIZE = shift; @@ -244,7 +234,6 @@ my $r = Apache->request or return; - return if $Apache::Server::Starting || $Apache::Server::ReStarting; return if $r->pnotes('size_limit_cleanup'); $r->post_connection( \&_exit_if_too_big ); @@ -284,7 +273,7 @@ =head1 SYNOPSIS <Perl> - $Apache::SizeLimit::MAX_UNSHARED_SIZE = 120000; # 120MB + $Apache::SizeLimit::MAX_UNSHARED_SIZE = 120 * 1024; # 120MB </Perl> PerlCleanupHandler Apache::SizeLimit @@ -296,8 +285,8 @@ overall size, by setting a minimum limit on shared memory, or a maximum on unshared memory. -You can set limits for each of these sizes, and if any limit is not -met, the process will be killed. +You can set limits for each of these sizes, and if any limit is +exceeded, the process will be killed. You can also limit the frequency that these sizes are checked so that this module only checks every N requests. @@ -321,22 +310,9 @@ PerlCleanupHandler Apache::SizeLimit -If you want to use C<Apache::SizeLimit> from a registry script, you -must call one of the above functions for every request: - - use Apache::SizeLimit - - main(); - - sub { - Apache::SizeLimit::setmax(150_000); - - # handle request - }; - Calling any one of C<setmax()>, C<setmin()>, or C<setmax_unshared()> -will install C<Apache::SizeLimit> as a cleanup handler, if it's not -already installed. +will install C<Apache::SizeLimit> as a cleanup handler for the current +request, if it's not already installed. If you want to combine this module with a cleanup handler of your own, make sure that C<Apache::SizeLimit> is the last handler run: @@ -347,14 +323,16 @@ they're defined in your configuration. You can explicitly call the C<Apache::SizeLimit::handler()> function -from your own handler: +from your own cleanup handler: package My::CleanupHandler sub handler { my $r = shift; - # do my thing + # Causes File::Temp to remove any temp dirs created during the + # request + File::Temp::cleanup(); return Apache::SizeLimit::handler($r); } @@ -420,8 +398,8 @@ 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/. +memory is shared in this way, take a look at the mod_perl docs at +http://perl.apache.org/docs/. You can take advantage of the shared memory information by setting a minimum shared size and/or a maximum unshared size. Experience on one @@ -442,14 +420,10 @@ Currently supported OSes: -=over 4 - -=item linux +=head2 linux -For linux we read the process size out of F</proc/self/statm>. This -is a little slow, but usually not too bad. If you are worried about -performance, try only setting up the the exit handler inside CGIs -(with the C<setmax()> function), and see if the CHECK_EVERY_N_REQUESTS +For linux we read the process size out of F</proc/self/statm>. If you +are worried about performance, see if the CHECK_EVERY_N_REQUESTS option is of benefit. Since linux 2.6 F</proc/self/statm> does not report the amount of @@ -469,16 +443,13 @@ C<Apache::SizeLimit> from using F</proc/self/smaps> and turn on the old behaviour by setting C<$Apache::SizeLimit::USE_SMAPS> to 0. -C<Apache::SizeLimit> itself will C<$Apache::SizeLimit::USE_SMAPS> to 0 -if it cannot load C<Linux::Smaps> or if your kernel does not support -F</proc/self/smaps>. Thus, you can check it to determine what is -actually used. - NOTE: Reading F</proc/self/smaps> is expensive compared to -F</proc/self/statm>. It must look at each page table entry of a process. -Further, on multiprocessor systems the access is synchronized with -spinlocks. Hence, you are encouraged to set the C<CHECK_EVERY_N_REQUESTS> -option. +F</proc/self/statm>. It must look at each page table entry of a +process. Further, on multiprocessor systems the access is +synchronized with spinlocks. Hence, you may want to set the +C<CHECK_EVERY_N_REQUESTS> option. + +=head3 Copy-on-write and Shared Memory The following example shows the effect of copy-on-write: @@ -488,7 +459,7 @@ use strict; use Apache::Constants qw(OK); - my $x= "a" x (1024*1024); + my $x = "a" x (1024*1024); sub handler { my $r = shift; @@ -507,11 +478,11 @@ PerlResponseHandler X </Location> -The parent apache allocates a megabyte for the string in C<$x>. The +The parent apache allocates memory for the string in C<$x>. The C<tr>-command then overwrites all "a" with "b" if the handler is called with an argument. This write is done in place, thus, the -process size doesn't change. Only C<$x> is not shared anymore by -means of copy-on-write between the parent and the child. +process size doesn't change. Only C<$x> is not shared anymore by means +of copy-on-write between the parent and the child. If F</proc/self/smaps> is available curl shows: @@ -530,7 +501,7 @@ One can see the kernel lies about the shared memory. It simply doesn't count copy-on-write pages as shared. -=item solaris 2.6 and above +=head2 solaris 2.6 and above For solaris we simply retrieve the size of F</proc/self/as>, which contains the address-space image of the process, and convert to KB. @@ -540,24 +511,24 @@ the F</proc> filesystem has changed between 2.5.1 and 2.6. Can anyone confirm or deny? -=item *bsd* +=head2 BSD (and OSX) Uses C<BSD::Resource::getrusage()> to determine process size. This is pretty efficient (a lot more efficient than reading it from the F</proc> fs anyway). -=item AIX? +=head2 AIX? Uses C<BSD::Resource::getrusage()> to determine process size. Not sure if the shared memory calculations will work or not. AIX users? -=item Win32 +=head2 Win32 Uses C<Win32::API> to access process memory information. C<Win32::API> can be installed under ActiveState perl using the supplied ppm utility. -=back +=head2 Everything Else If your platform is not supported, then please send a patch to check the process size. The more portable/efficient/correct the solution the @@ -576,7 +547,17 @@ <[EMAIL PROTECTED]>: Win32 support Dave Rolsky <[EMAIL PROTECTED]>, maintenance and fixes outside of -mod_perl tree (0.06). +mod_perl tree (0.04+). =cut +=head1 TODO + +* Create new set/get accessors for all globals, with nice names + (set_max_process_size) - keep old names with "push a handler a + behavior" + +* Add a new "add_cleanup_handler" method to push handler for one + request. + +=cut