components/apache2-modules/mod_perl/patches/Reload.patch
changeset 278 77b380ba9d84
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/apache2-modules/mod_perl/patches/Reload.patch	Thu Jun 02 00:54:08 2011 -0700
@@ -0,0 +1,571 @@
+--- /dev/null	Fri Oct 16 06:02:02 2009
++++ mod_perl-2.0.4/lib/Apache2/Reload.pm	Sun Nov 19 15:31:40 2006
+@@ -0,0 +1,185 @@
++# Licensed to the Apache Software Foundation (ASF) under one or more
++# contributor license agreements.  See the NOTICE file distributed with
++# this work for additional information regarding copyright ownership.
++# The ASF licenses this file to You under the Apache License, Version 2.0
++# (the "License"); you may not use this file except in compliance with
++# the License.  You may obtain a copy of the License at
++#
++#     http://www.apache.org/licenses/LICENSE-2.0
++#
++# Unless required by applicable law or agreed to in writing, software
++# distributed under the License is distributed on an "AS IS" BASIS,
++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++# See the License for the specific language governing permissions and
++# limitations under the License.
++#
++package Apache2::Reload;
++
++use strict;
++use warnings FATAL => 'all';
++
++use mod_perl2;
++
++our $VERSION = '0.09';
++
++use Apache2::Const -compile => qw(OK);
++
++use Apache2::Connection;
++use Apache2::ServerUtil;
++use Apache2::RequestUtil;
++
++use ModPerl::Util ();
++
++use vars qw(%INCS %Stat $TouchTime);
++
++%Stat = ($INC{"Apache2/Reload.pm"} => time);
++
++$TouchTime = time;
++
++sub import {
++    my $class = shift;
++    my ($package, $file) = (caller)[0,1];
++
++    $class->register_module($package, $file);
++}
++
++sub package_to_module {
++    my $package = shift;
++    $package =~ s/::/\//g;
++    $package .= ".pm";
++    return $package;
++}
++
++sub module_to_package {
++    my $module = shift;
++    $module =~ s/\//::/g;
++    $module =~ s/\.pm$//g;
++    return $module;
++}
++
++sub register_module {
++    my ($class, $package, $file) = @_;
++    my $module = package_to_module($package);
++
++    if ($file) {
++        $INCS{$module} = $file;
++    }
++    else {
++        $file = $INC{$module};
++        return unless $file;
++        $INCS{$module} = $file;
++    }
++}
++
++sub unregister_module {
++    my ($class, $package) = @_;
++    my $module = package_to_module($package);
++    delete $INCS{$module};
++}
++
++# the first argument is:
++# $c if invoked as 'PerlPreConnectionHandler'
++# $r if invoked as 'PerlInitHandler'
++sub handler {
++    my $o = shift;
++    $o = $o->base_server if ref($o) eq 'Apache2::Connection';
++
++    my $DEBUG = ref($o) && (lc($o->dir_config("ReloadDebug") || '') eq 'on');
++
++    my $TouchFile = ref($o) && $o->dir_config("ReloadTouchFile");
++
++    my $ConstantRedefineWarnings = ref($o) && 
++        (lc($o->dir_config("ReloadConstantRedefineWarnings") || '') eq 'off') 
++            ? 0 : 1;
++
++    my $TouchModules;
++
++    if ($TouchFile) {
++        warn "Checking mtime of $TouchFile\n" if $DEBUG;
++        my $touch_mtime = (stat $TouchFile)[9] || return Apache2::Const::OK;
++        return Apache2::Const::OK unless $touch_mtime > $TouchTime;
++        $TouchTime = $touch_mtime;
++        open my $fh, $TouchFile or die "Can't open '$TouchFile': $!";
++        $TouchModules = <$fh>;
++        chomp $TouchModules if $TouchModules;
++    }
++
++    if (ref($o) && (lc($o->dir_config("ReloadAll") || 'on') eq 'on')) {
++        *Apache2::Reload::INCS = \%INC;
++    }
++    else {
++        *Apache2::Reload::INCS = \%INCS;
++        my $ExtraList = 
++                $TouchModules || 
++                (ref($o) && $o->dir_config("ReloadModules")) || 
++                '';
++        my @extra = split /\s+/, $ExtraList;
++        foreach (@extra) {
++            if (/(.*)::\*$/) {
++                my $prefix = $1;
++                $prefix =~ s/::/\//g;
++                foreach my $match (keys %INC) {
++                    if ($match =~ /^\Q$prefix\E/) {
++                        $Apache2::Reload::INCS{$match} = $INC{$match};
++                    }
++                }
++            }
++            else {
++                Apache2::Reload->register_module($_);
++            }
++        }
++    }
++
++    my $ReloadDirs = ref($o) && $o->dir_config("ReloadDirectories");
++    my @watch_dirs = split(/\s+/, $ReloadDirs||'');
++    
++    my @changed;
++    foreach my $key (sort { $a cmp $b } keys %Apache2::Reload::INCS) {
++        my $file = $Apache2::Reload::INCS{$key};
++
++        next unless defined $file;
++        next if @watch_dirs && !grep { $file =~ /^$_/ } @watch_dirs;
++        warn "Apache2::Reload: Checking mtime of $key\n" if $DEBUG;
++
++        my $mtime = (stat $file)[9];
++
++        unless (defined($mtime) && $mtime) {
++            for (@INC) {
++                $mtime = (stat "$_/$file")[9];
++                last if defined($mtime) && $mtime;
++            }
++        }
++
++        warn("Apache2::Reload: Can't locate $file\n"), next
++            unless defined $mtime and $mtime;
++
++        unless (defined $Stat{$file}) {
++            $Stat{$file} = $^T;
++        }
++
++        if ($mtime > $Stat{$file}) {
++            push @changed, $key;
++        }
++        $Stat{$file} = $mtime;
++    }
++    
++    #First, let's unload all changed modules
++    foreach my $module (@changed) {
++        my $package = module_to_package($module);
++        ModPerl::Util::unload_package($package);
++    }
++    
++    #Then, let's reload them all, so that module dependencies can satisfy
++    #themselves in the correct order.
++    foreach my $module (@changed) {
++        my $package = module_to_package($module);
++        require $module;
++        warn("Apache2::Reload: process $$ reloading $package from $module\n")
++            if $DEBUG;
++    }
++
++    return Apache2::Const::OK;
++}
++
++1;
++__END__
+--- /dev/null	Fri Oct 16 06:02:02 2009
++++ mod_perl-2.0.4/docs/api/Apache2/Reload.pod	Sun Nov 19 15:32:13 2006
+@@ -1,0 +1,380 @@
++=head1 NAME
++
++Apache2::Reload - Reload Perl Modules when Changed on Disk
++
++=head1 Synopsis
++
++  # Monitor and reload all modules in %INC:
++  # httpd.conf:
++  PerlModule Apache2::Reload
++  PerlInitHandler Apache2::Reload
++
++  # when working with protocols and connection filters
++  # PerlPreConnectionHandler Apache2::Reload
++
++  # Reload groups of modules:
++  # httpd.conf:
++  PerlModule Apache2::Reload
++  PerlInitHandler Apache2::Reload
++  PerlSetVar ReloadAll Off
++  PerlSetVar ReloadModules "ModPerl::* Apache2::*"
++  #PerlSetVar ReloadDebug On
++  
++  # Reload a single module from within itself:
++  package My::Apache2::Module;
++  use Apache2::Reload;
++  sub handler { ... }
++  1;
++
++=head1 Description
++
++C<Apache2::Reload> reloads modules that change on the disk.
++
++When Perl pulls a file via C<require>, it stores the filename in the
++global hash C<%INC>.  The next time Perl tries to C<require> the same
++file, it sees the file in C<%INC> and does not reload from disk.  This
++module's handler can be configured to iterate over the modules in
++C<%INC> and reload those that have changed on disk or only specific
++modules that have registered themselves with C<Apache2::Reload>. It can
++also do the check for modified modules, when a special touch-file has
++been modified.
++
++Note that C<Apache2::Reload> operates on the current context of
++C<@INC>.  Which means, when called as a C<Perl*Handler> it will not
++see C<@INC> paths added or removed by C<ModPerl::Registry> scripts, as
++the value of C<@INC> is saved on server startup and restored to that
++value after each request.  In other words, if you want
++C<Apache2::Reload> to work with modules that live in custom C<@INC>
++paths, you should modify C<@INC> when the server is started.  Besides,
++C<'use lib'> in the startup script, you can also set the C<PERL5LIB>
++variable in the httpd's environment to include any non-standard 'lib'
++directories that you choose.  For example, to accomplish that you can
++include a line:
++
++  PERL5LIB=/home/httpd/perl/extra; export PERL5LIB
++
++in the script that starts Apache. Alternatively, you can set this
++environment variable in I<httpd.conf>:
++
++  PerlSetEnv PERL5LIB /home/httpd/perl/extra
++
++=head2 Monitor All Modules in C<%INC>
++
++To monitor and reload all modules in C<%INC> at the beginning of
++request's processing, simply add the following configuration to your
++I<httpd.conf>:
++
++  PerlModule Apache2::Reload
++  PerlInitHandler Apache2::Reload
++
++When working with connection filters and protocol modules
++C<Apache2::Reload> should be invoked in the pre_connection stage:
++
++  PerlPreConnectionHandler Apache2::Reload
++
++See also the discussion on
++C<L<PerlPreConnectionHandler|docs::2.0::user::handlers::protocols/PerlPreConnectionHandler>>.
++
++=head2 Register Modules Implicitly
++
++To only reload modules that have registered with C<Apache2::Reload>,
++add the following to the I<httpd.conf>:
++
++  PerlModule Apache2::Reload
++  PerlInitHandler Apache2::Reload
++  PerlSetVar ReloadAll Off
++  # ReloadAll defaults to On
++
++Then any modules with the line:
++
++  use Apache2::Reload;
++
++Will be reloaded when they change.
++
++=head2 Register Modules Explicitly
++
++You can also register modules explicitly in your I<httpd.conf> file
++that you want to be reloaded on change:
++
++  PerlModule Apache2::Reload
++  PerlInitHandler Apache2::Reload
++  PerlSetVar ReloadAll Off
++  PerlSetVar ReloadModules "My::Foo My::Bar Foo::Bar::Test"
++
++Note that these are split on whitespace, but the module list B<must>
++be in quotes, otherwise Apache tries to parse the parameter list.
++
++The C<*> wild character can be used to register groups of files under
++the same namespace. For example the setting:
++
++  PerlSetVar ReloadModules "ModPerl::* Apache2::*"
++
++will monitor all modules under the namespaces C<ModPerl::> and
++C<Apache2::>.
++
++=head2 Monitor Only Certain Sub Directories
++
++To reload modules only in certain directories (and their
++subdirectories) add the following to the I<httpd.conf>:
++
++  PerlModule Apache2::Reload
++  PerlInitHandler Apache2::Reload
++  PerlSetVar ReloadDirectories "/tmp/project1 /tmp/project2"
++
++You can further narrow the list of modules to be reloaded from the
++chosen directories with C<ReloadModules> as in:
++
++  PerlModule Apache2::Reload
++  PerlInitHandler Apache2::Reload
++  PerlSetVar ReloadDirectories "/tmp/project1 /tmp/project2"
++  PerlSetVar ReloadAll Off
++  PerlSetVar ReloadModules "MyApache2::*"
++
++In this configuration example only modules from the namespace
++C<MyApache2::> found in the directories I</tmp/project1/> and
++I</tmp/project2/> (and their subdirectories) will be reloaded.
++
++=head2 Special "Touch" File
++
++You can also declare a file, which when gets C<touch(1)>ed, causes the
++reloads to be performed. For example if you set:
++
++  PerlSetVar ReloadTouchFile /tmp/reload_modules
++
++and don't C<touch(1)> the file I</tmp/reload_modules>, the reloads
++won't happen until you go to the command line and type:
++
++  % touch /tmp/reload_modules
++
++When you do that, the modules that have been changed, will be
++magically reloaded on the next request. This option works with any
++mode described before.
++
++=head2 Unregistering a module
++
++In some cases, it might be necessary to explicitely stop reloading
++a module.
++
++  Apache2::Reload->unregister_module('Some::Module');
++
++But be carefull, since unregistering a module in this way will only
++do so for the current interpreter. This feature should be used with
++care.
++
++=head1 Performance Issues
++
++This module is perfectly suited for a development environment. Though
++it's possible that you would like to use it in a production
++environment, since with C<Apache2::Reload> you don't have to restart
++the server in order to reload changed modules during software
++updates. Though this convenience comes at a price:
++
++=over
++
++=item *
++
++If the "touch" file feature is used, C<Apache2::Reload> has to stat(2)
++the touch file on each request, which adds a slight but most likely
++insignificant overhead to response times. Otherwise C<Apache2::Reload>
++will stat(2) each registered module or even worse--all modules in
++C<%INC>, which will significantly slow everything down.
++
++=item *
++
++Once the child process reloads the modules, the memory used by these
++modules is not shared with the parent process anymore. Therefore the
++memory consumption may grow significantly.
++
++=back
++
++Therefore doing a full server stop and restart is probably a better
++solution.
++
++=head1 Debug
++
++If you aren't sure whether the modules that are supposed to be
++reloaded, are actually getting reloaded, turn the debug mode on:
++
++  PerlSetVar ReloadDebug On
++
++=head1 Caveats
++
++=head2 Problems With Reloading Modules Which Do Not Declare Their Package Name
++
++If you modify modules, which don't declare their C<package>, and rely on
++C<Apache2::Reload> to reload them, you may encounter problems: i.e.,
++it'll appear as if the module wasn't reloaded when in fact it
++was. This happens because when C<Apache2::Reload> C<require()>s such a
++module all the global symbols end up in the C<Apache2::Reload>
++namespace!  So the module does get reloaded and you see the compile
++time errors if there are any, but the symbols don't get imported to
++the right namespace. Therefore the old version of the code is running.
++
++
++=head2 Failing to Find a File to Reload
++
++C<Apache2::Reload> uses C<%INC> to find the files on the filesystem. If
++an entry for a certain filepath in C<%INC> is relative,
++C<Apache2::Reload> will use C<@INC> to try to resolve that relative
++path. Now remember that mod_perl freezes the value of C<@INC> at the
++server startup, and you can modify it only for the duration of one
++request when you need to load some module which is not in on of the
++C<@INC> directories. So a module gets loaded, and registered in
++C<%INC> with a relative path. Now when C<Apache2::Reload> tries to find
++that module to check whether it has been modified, it can't find since
++its directory is not in C<@INC>. So C<Apache2::Reload> will silently
++skip that module.
++
++You can enable the C<Debug|/Debug> mode to see what C<Apache2::Reload>
++does behind the scenes.
++
++
++
++=head2 Problems with Scripts Running with Registry Handlers that Cache the Code
++
++The following problem is relevant only to registry handlers that cache
++the compiled script. For example it concerns
++C<L<ModPerl::Registry|docs::2.0::api::ModPerl::Registry>> but not
++C<L<ModPerl::PerlRun|docs::2.0::api::ModPerl::PerlRun>>.
++
++=head3 The Problem
++
++Let's say that there is a module C<My::Utils>:
++
++  #file:My/Utils.pm
++  #----------------
++  package My::Utils;
++  BEGIN { warn __PACKAGE__ , " was reloaded\n" }
++  use base qw(Exporter);
++  @EXPORT = qw(colour);
++  sub colour { "white" }
++  1;
++
++And a registry script F<test.pl>:
++
++  #file:test.pl
++  #------------
++  use My::Utils;
++  print "Content-type: text/plain\n\n";
++  print "the color is " . colour();
++
++Assuming that the server is running in a single mode, we request the
++script for the first time and we get the response:
++
++  the color is white
++
++Now we change F<My/Utils.pm>:
++
++  -  sub colour { "white" }
++  +  sub colour { "red" }
++
++And issue the request again. C<Apache2::Reload> does its job and we can
++see that C<My::Utils> was reloaded (look in the I<error_log>
++file). However the script still returns:
++
++  the color is white
++
++=head3 The Explanation
++
++Even though F<My/Utils.pm> was reloaded, C<ModPerl::Registry>'s cached
++code won't run 'C<use My::Utils;>' again (since it happens only once,
++i.e. during the compile time). Therefore the script doesn't know that
++the subroutine reference has been changed.
++
++This is easy to verify. Let's change the script to be:
++
++  #file:test.pl
++  #------------
++  use My::Utils;
++  print "Content-type: text/plain\n\n";
++  my $sub_int = \&colour;
++  my $sub_ext = \&My::Utils::colour;
++  print "int $sub_int\n";
++  print "ext $sub_ext\n";
++
++Issue a request, you will see something similar to:
++
++  int CODE(0x8510af8)
++  ext CODE(0x8510af8)
++
++As you can see both point to the same CODE reference (meaning that
++it's the same symbol). After modifying F<My/Utils.pm> again:
++
++  -  sub colour { "red" }
++  +  sub colour { "blue" }
++
++and calling the script on the secondnd time, we get:
++
++  int CODE(0x8510af8)
++  ext CODE(0x851112c)
++
++You can see that the internal CODE reference is not the same as the
++external one.
++
++=head3 The Solution
++
++There are two solutions to this problem:
++
++Solution 1: replace C<use()> with an explicit C<require()> +
++C<import()>.
++
++ - use My::Utils;
++ + require My::Utils; My::Utils->import();
++
++now the changed functions will be reimported on every request.
++
++Solution 2: remember to touch the script itself every time you change
++the module that it requires.
++
++=head1 Threaded MPM and Multiple Perl Interpreters
++
++If you use C<Apache2::Reload> with a threaded MPM and multiple Perl
++interpreters, the modules will be reloaded by each interpreter as they
++are used, not every interpreters at once.  Similar to mod_perl 1.0
++where each child has its own Perl interpreter, the modules are
++reloaded as each child is hit with a request.
++
++If a module is loaded at startup, the syntax tree of each subroutine
++is shared between interpreters (big win), but each subroutine has its
++own padlist (where lexical my variables are stored).  Once
++C<Apache2::Reload> reloads a module, this sharing goes away and each
++Perl interpreter will have its own copy of the syntax tree for the
++reloaded subroutines.
++
++
++=head1 Pseudo-hashes
++
++The short summary of this is: Don't use pseudo-hashes. They are
++deprecated since Perl 5.8 and are removed in 5.9.
++
++Use an array with constant indexes. Its faster in the general case,
++its more guaranteed, and generally, it works.
++
++The long summary is that some work has been done to get this module
++working with modules that use pseudo-hashes, but it's still broken in
++the case of a single module that contains multiple packages that all
++use pseudo-hashes.
++
++So don't do that.
++
++
++
++
++=head1 Copyright
++
++mod_perl 2.0 and its core modules are copyrighted under
++The Apache Software License, Version 2.0.
++
++
++=head1 Authors
++
++Matt Sergeant, [email protected]
++
++Stas Bekman (porting to mod_perl 2.0)
++
++A few concepts borrowed from C<Stonehenge::Reload> by Randal Schwartz
++and C<Apache::StatINC> (mod_perl 1.x) by Doug MacEachern and Ask
++Bjoern Hansen.
++
++=cut
++