You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Mark <ma...@immermail.com> on 2005/05/29 19:32:18 UTC

Apache2::Reload problem (ModPerl::Util bug)

In 2.0.0, if there are heirarchical packages, and Apache2::Reload is
configured to reload the 'parent', it blows away the 'children' package
namespaces (and doesn't reload the children.)  For example, if @INC has:

Fubar.pm
Fubar/Child.pm

And Apache2::Reload reloads package Fubar, it blows away
Fubar::Child::* and only reloads file Fubar.pm.   Only a server
restart can recover from this point.

The actual unloading work is done by ModPerl::Util::unload_package(),
whose behavior is contrary to the docs, which say:

   "unload_package()" takes care to leave sub-stashes intact while
   deleting the requested stash. So for example if "CGI" and "CGI::Carp"
   are loaded, calling "unload_package('CGI')" won't affect "CGI::Carp".


I only partly understand how unload_package() works, but it seems to
just iterate over symbols in the package and blow them away, without
regard for the actual file from which the symbol was instantiated.

I tried modifying the code to skip over symbols that correspond
to a key in %INC, which seems logical and works correctly in my tests,
but may not be a complete or perfect solution for reasons beyond
my current testing/thinking.  However, in my tests, it works correctly
if either the parent package, child package, or both are modified.

Comments/suggestions about the correctness of this patch requested.

Thanks.


*** ./blib/lib/ModPerl/Util.pm  2005-05-22 10:14:19.000000000 -0700
--- /usr/lib/perl5/site_perl/5.8.5/i686-linux/ModPerl/Util.pm   2005-05-29 10:09:02.000000000 -0700
***************
*** 36,55 ****
--- 36,58 ----
   sub unload_package_pp {
       my $package = shift;
       no strict 'refs';
       my $tab = \%{ $package . '::' };

       # below we assign to a symbol first before undef'ing it, to avoid
       # nuking aliases. If we undef directly we may undef not only the
       # alias but the original function as well

       for (keys %$tab) {
+         if (my ($subpackage) = /(.*)::/) {
+             next if exists $INC{"$package/$subpackage.pm"};
+         }
           my $fullname = join '::', $package, $_;
           # code/hash/array/scalar might be imported make sure the gv
           # does not point elsewhere before undefing each
           if (%$fullname) {
               *{$fullname} = {};
               undef %$fullname;
           }
           if (@$fullname) {
               *{$fullname} = [];
               undef @$fullname;

Re: Apache2::Reload problem (ModPerl::Util bug)

Posted by Foo Ji-Haw <jh...@nexlabs.com>.
Hello Mark,

I have the same problem as well, though I don't have a decent solution/ 
workaround for it. All I ended up doing was to use the subpackages. And 
when the subpackage changes, I touch the main package as well. That 
seems to cause Apache to reload.

Mark wrote:

> In 2.0.0, if there are heirarchical packages, and Apache2::Reload is
> configured to reload the 'parent', it blows away the 'children' package
> namespaces (and doesn't reload the children.)  For example, if @INC has:
>
> Fubar.pm
> Fubar/Child.pm
>
> And Apache2::Reload reloads package Fubar, it blows away
> Fubar::Child::* and only reloads file Fubar.pm.   Only a server
> restart can recover from this point.
>
> The actual unloading work is done by ModPerl::Util::unload_package(),
> whose behavior is contrary to the docs, which say:
>
>   "unload_package()" takes care to leave sub-stashes intact while
>   deleting the requested stash. So for example if "CGI" and "CGI::Carp"
>   are loaded, calling "unload_package('CGI')" won't affect "CGI::Carp".
>
>
> I only partly understand how unload_package() works, but it seems to
> just iterate over symbols in the package and blow them away, without
> regard for the actual file from which the symbol was instantiated.
>
> I tried modifying the code to skip over symbols that correspond
> to a key in %INC, which seems logical and works correctly in my tests,
> but may not be a complete or perfect solution for reasons beyond
> my current testing/thinking.  However, in my tests, it works correctly
> if either the parent package, child package, or both are modified.
>
> Comments/suggestions about the correctness of this patch requested.
>
> Thanks.
>
>
> *** ./blib/lib/ModPerl/Util.pm  2005-05-22 10:14:19.000000000 -0700
> --- /usr/lib/perl5/site_perl/5.8.5/i686-linux/ModPerl/Util.pm   
> 2005-05-29 10:09:02.000000000 -0700
> ***************
> *** 36,55 ****
> --- 36,58 ----
>   sub unload_package_pp {
>       my $package = shift;
>       no strict 'refs';
>       my $tab = \%{ $package . '::' };
>
>       # below we assign to a symbol first before undef'ing it, to avoid
>       # nuking aliases. If we undef directly we may undef not only the
>       # alias but the original function as well
>
>       for (keys %$tab) {
> +         if (my ($subpackage) = /(.*)::/) {
> +             next if exists $INC{"$package/$subpackage.pm"};
> +         }
>           my $fullname = join '::', $package, $_;
>           # code/hash/array/scalar might be imported make sure the gv
>           # does not point elsewhere before undefing each
>           if (%$fullname) {
>               *{$fullname} = {};
>               undef %$fullname;
>           }
>           if (@$fullname) {
>               *{$fullname} = [];
>               undef @$fullname;
>

Re: Apache2::Reload problem (ModPerl::Util bug)

Posted by Mark <ma...@immermail.com>.
Philippe M. Chiasson wrote:
> Mark wrote:
> 
>>Mark wrote:
>>
>>
>>>In 2.0.0, if there are heirarchical packages, and Apache2::Reload is
>>>configured to reload the 'parent', it blows away the 'children' package
>>>namespaces (and doesn't reload the children.)  For example, if @INC has:
>>>
>>>Fubar.pm
>>>Fubar/Child.pm
>>>
>>>And Apache2::Reload reloads package Fubar, it blows away
>>>Fubar::Child::* and only reloads file Fubar.pm.   Only a server
>>>restart can recover from this point.
>>>
>>>The actual unloading work is done by ModPerl::Util::unload_package(),
>>>whose behavior is contrary to the docs, which say:
>>>
>>>  "unload_package()" takes care to leave sub-stashes intact while
>>>  deleting the requested stash. So for example if "CGI" and "CGI::Carp"
>>>  are loaded, calling "unload_package('CGI')" won't affect "CGI::Carp".
> 
> 
> This is clearly a bug.
> 
> 
>>>I only partly understand how unload_package() works, but it seems to
>>>just iterate over symbols in the package and blow them away, without
>>>regard for the actual file from which the symbol was instantiated.
> 
> 
> Yup, it's that simple and there is a slightly smarter version in XS
> that does check the source of the symbols from.
> 
> 
>>>I tried modifying the code to skip over symbols that correspond
>>>to a key in %INC, which seems logical and works correctly in my tests,
>>>but may not be a complete or perfect solution for reasons beyond
>>>my current testing/thinking.  However, in my tests, it works correctly
>>>if either the parent package, child package, or both are modified.
>>>
>>>Comments/suggestions about the correctness of this patch requested.
>>
>>Correction. Ignore previous patch.  It only worked one level of
>>heirarchy.  Correct patch is:
> 
> 
> Much simpler patch to just skip stashes has been checked in in rev 179448.
> 
> If you can try latest-svn and confirm your problem goes away, that would be
> fantastic.

That works. Thanks.

Re: Apache2::Reload problem (ModPerl::Util bug)

Posted by "Philippe M. Chiasson" <go...@ectoplasm.org>.
Mark wrote:
> Mark wrote:
>
>> In 2.0.0, if there are heirarchical packages, and Apache2::Reload is
>> configured to reload the 'parent', it blows away the 'children' package
>> namespaces (and doesn't reload the children.)  For example, if @INC has:
>>
>> Fubar.pm
>> Fubar/Child.pm
>>
>> And Apache2::Reload reloads package Fubar, it blows away
>> Fubar::Child::* and only reloads file Fubar.pm.   Only a server
>> restart can recover from this point.
>>
>> The actual unloading work is done by ModPerl::Util::unload_package(),
>> whose behavior is contrary to the docs, which say:
>>
>>   "unload_package()" takes care to leave sub-stashes intact while
>>   deleting the requested stash. So for example if "CGI" and "CGI::Carp"
>>   are loaded, calling "unload_package('CGI')" won't affect "CGI::Carp".

This is clearly a bug.

>> I only partly understand how unload_package() works, but it seems to
>> just iterate over symbols in the package and blow them away, without
>> regard for the actual file from which the symbol was instantiated.

Yup, it's that simple and there is a slightly smarter version in XS
that does check the source of the symbols from.

>> I tried modifying the code to skip over symbols that correspond
>> to a key in %INC, which seems logical and works correctly in my tests,
>> but may not be a complete or perfect solution for reasons beyond
>> my current testing/thinking.  However, in my tests, it works correctly
>> if either the parent package, child package, or both are modified.
>>
>> Comments/suggestions about the correctness of this patch requested.
>
> Correction. Ignore previous patch.  It only worked one level of
> heirarchy.  Correct patch is:

Much simpler patch to just skip stashes has been checked in in rev 179448.

If you can try latest-svn and confirm your problem goes away, that would be
fantastic.

--------------------------------------------------------------------------------
Philippe M. Chiasson m/gozer\@(apache|cpan|ectoplasm)\.org/ GPG KeyID : 88C3A5A5
http://gozer.ectoplasm.org/     F9BF E0C2 480E 7680 1AE5 3631 CB32 A107 88C3A5A5

Re: Apache2::Reload problem (ModPerl::Util bug)

Posted by "Philippe M. Chiasson" <go...@ectoplasm.org>.
Mark wrote:
> Mark wrote:
>
>> In 2.0.0, if there are heirarchical packages, and Apache2::Reload is
>> configured to reload the 'parent', it blows away the 'children' package
>> namespaces (and doesn't reload the children.)  For example, if @INC has:
>>
>> Fubar.pm
>> Fubar/Child.pm
>>
>> And Apache2::Reload reloads package Fubar, it blows away
>> Fubar::Child::* and only reloads file Fubar.pm.   Only a server
>> restart can recover from this point.
>>
>> The actual unloading work is done by ModPerl::Util::unload_package(),
>> whose behavior is contrary to the docs, which say:
>>
>>   "unload_package()" takes care to leave sub-stashes intact while
>>   deleting the requested stash. So for example if "CGI" and "CGI::Carp"
>>   are loaded, calling "unload_package('CGI')" won't affect "CGI::Carp".

This is clearly a bug.

>> I only partly understand how unload_package() works, but it seems to
>> just iterate over symbols in the package and blow them away, without
>> regard for the actual file from which the symbol was instantiated.

Yup, it's that simple and there is a slightly smarter version in XS
that does check the source of the symbols from.

>> I tried modifying the code to skip over symbols that correspond
>> to a key in %INC, which seems logical and works correctly in my tests,
>> but may not be a complete or perfect solution for reasons beyond
>> my current testing/thinking.  However, in my tests, it works correctly
>> if either the parent package, child package, or both are modified.
>>
>> Comments/suggestions about the correctness of this patch requested.
>
> Correction. Ignore previous patch.  It only worked one level of
> heirarchy.  Correct patch is:

Much simpler patch to just skip stashes has been checked in in rev 179448.

If you can try latest-svn and confirm your problem goes away, that would be
fantastic.

--------------------------------------------------------------------------------
Philippe M. Chiasson m/gozer\@(apache|cpan|ectoplasm)\.org/ GPG KeyID : 88C3A5A5
http://gozer.ectoplasm.org/     F9BF E0C2 480E 7680 1AE5 3631 CB32 A107 88C3A5A5

Re: Apache2::Reload problem (ModPerl::Util bug)

Posted by Mark <ma...@immermail.com>.
Mark wrote:
> In 2.0.0, if there are heirarchical packages, and Apache2::Reload is
> configured to reload the 'parent', it blows away the 'children' package
> namespaces (and doesn't reload the children.)  For example, if @INC has:
> 
> Fubar.pm
> Fubar/Child.pm
> 
> And Apache2::Reload reloads package Fubar, it blows away
> Fubar::Child::* and only reloads file Fubar.pm.   Only a server
> restart can recover from this point.
> 
> The actual unloading work is done by ModPerl::Util::unload_package(),
> whose behavior is contrary to the docs, which say:
> 
>   "unload_package()" takes care to leave sub-stashes intact while
>   deleting the requested stash. So for example if "CGI" and "CGI::Carp"
>   are loaded, calling "unload_package('CGI')" won't affect "CGI::Carp".
> 
> 
> I only partly understand how unload_package() works, but it seems to
> just iterate over symbols in the package and blow them away, without
> regard for the actual file from which the symbol was instantiated.
> 
> I tried modifying the code to skip over symbols that correspond
> to a key in %INC, which seems logical and works correctly in my tests,
> but may not be a complete or perfect solution for reasons beyond
> my current testing/thinking.  However, in my tests, it works correctly
> if either the parent package, child package, or both are modified.
> 
> Comments/suggestions about the correctness of this patch requested.

Correction. Ignore previous patch.  It only worked one level of
heirarchy.  Correct patch is:

*** ./blib/lib/ModPerl/Util.pm  2005-05-22 10:14:19.000000000 -0700
--- /usr/lib/perl5/site_perl/5.8.5/i686-linux/ModPerl/Util.pm   2005-05-29 10:47:37.000000000 -0700
***************
*** 37,56 ****
--- 37,61 ----
       my $package = shift;
       no strict 'refs';
       my $tab = \%{ $package . '::' };

       # below we assign to a symbol first before undef'ing it, to avoid
       # nuking aliases. If we undef directly we may undef not only the
       # alias but the original function as well

       for (keys %$tab) {
           my $fullname = join '::', $package, $_;
+         if (my ($subpackage) = $fullname =~ /(.*)::/) {
+                 $subpackage =~ s[::][/]g;
+                 $subpackage .= ".pm";
+                 next if exists $INC{$subpackage};
+         }
           # code/hash/array/scalar might be imported make sure the gv
           # does not point elsewhere before undefing each
           if (%$fullname) {
               *{$fullname} = {};
               undef %$fullname;
           }
           if (@$fullname) {
               *{$fullname} = [];
               undef @$fullname;
           }