You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Ted Prah <tp...@netcasters.com> on 2002/05/22 21:47:36 UTC

Reloading Modules

Hi again,

I'm having trouble seeing module changes when I reload
a script that uses it.  I'm using Apache::Reload and my test
script/module is as follows:


test.pl
--------------------
#!/usr/local/bin/perl
use strict;
use warnings;

use My::Test qw(:subs);

print "Content-type: text/plain\r\n\r\n";
&test1();
--------------------


Test.pm
--------------------
package My::Test;
use strict;
use warnings;

BEGIN {
    use Exporter ();

    our (@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);

    @ISA       = qw(Exporter);
    @EXPORT    = qw();
    @EXPORT_OK = qw();

    %EXPORT_TAGS = (
                    subs => [qw(test1)],
                   );

    Exporter::export_ok_tags('subs');

}

sub test1 { print "In test1 func\n"; }

1;
--------------------


When I modify sub test1, and I reload - no changes appear
in the browser.  The following gets printed to error_log:
Subroutine test1 redefined at /export/home/httpd/cgi-bin/My/Test.pm line

22.

When I touch test.pl - the changes appear.  The following gets printed
to error_log:
Subroutine test1 redefined at /export/home/httpd/cgi-bin/My/test.pl line

5

Finally, if I add a new subroutine test2 to Test.pm, export it, and
update the test.pl script to call test2, the script fails with an
Internal
Server Error.  The following gets printed to error_log:
"test2" is not exported by the My::Test module at
/export/home/httpd/cgi-bin/My/test.pl line 5
[Wed May 22 15:26:12 2002] [error] Can't continue after import errors at

/export/home/httpd/cgi-bin/My/test.pl line 5
BEGIN failed--compilation aborted at /export/home/httpd/cgi-bin/
My/test.pl line 5.

Then, when I restart the server, the script runs fine.

Thank you for any help you can provide,

Ted



Re: Reloading Modules

Posted by Ted Prah <tp...@netcasters.com>.

Stas Bekman wrote:

> Ted Prah wrote:
> > Thanks for the input Stas.  I found your debugging methodology
> > to be very informative and especially useful in a mod_perl environment.
> >
> > I tried your suggestion of commenting out
> >              require $key;
> > in Reload.pm, but it did not work for me.  I'd be happy to try
> > any other suggestions you might have.
>
> But did you debug whether the module was reloaded from test.pl with the
> modified Reload.pm? If so was the import() called? If not, try to have
> it as a separate call:
>
> require My::Test;
> My::Test->import(':subs');
>

This worked!  The modification to Reload.pm was not necessary for
this to work.

>
> > Your code to work around Exporter worked fine.  However,
> > I think I'll stick with using Exporter so that I can make use
> > of the export tags.
>
> But it doesn't seem to work? You can easily extend the import() function
> I've suggested to suppport tags.
>

Right, it doesn't work unless I restart the server.  Restarting the
server has been made easier due to your advice on cloning the
apachectl script and setting the suid bit.

Thanks again for all your help,

Ted

>
> __________________________________________________________________
> Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
> http://stason.org/     mod_perl Guide ---> http://perl.apache.org
> mailto:stas@stason.org http://use.perl.org http://apacheweek.com
> http://modperlbook.org http://apache.org   http://ticketmaster.com


Re: Reloading Modules

Posted by Stas Bekman <st...@stason.org>.
Ted Prah wrote:
> Thanks for the input Stats.  I found your debugging methodology
> to be very informative and especially useful in a mod_perl environment.
> 
> I tried your suggestion of commenting out
>              require $key;
> in Reload.pm, but it did not work for me.  I'd be happy to try
> any other suggestions you might have.

But did you debug whether the module was reloaded from test.pl with the 
modified Reload.pm? If so was the import() called? If not, try to have 
it as a separate call:

require My::Test;
My::Test->import(':subs');

> Your code to work around Exporter worked fine.  However,
> I think I'll stick with using Exporter so that I can make use
> of the export tags.

But it doesn't seem to work? You can easily extend the import() function 
I've suggested to suppport tags.

__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


Re: Reloading Modules

Posted by Ted Prah <tp...@netcasters.com>.
Thanks for the input Stats.  I found your debugging methodology
to be very informative and especially useful in a mod_perl environment.

I tried your suggestion of commenting out
             require $key;
in Reload.pm, but it did not work for me.  I'd be happy to try
any other suggestions you might have.

Your code to work around Exporter worked fine.  However,
I think I'll stick with using Exporter so that I can make use
of the export tags.

Thanks again!

Ted


Stas Bekman wrote:

> Ted Prah wrote:
> > Hi again,
> >
> > I'm having trouble seeing module changes when I reload
> > a script that uses it.
>
> That's because Reload.pm doesn't re-exports the symbols when reloading
> the module and test.pl doesn't call import() because it sees the module
> in %INC, therefore it still sees the old sub till the moment it gets
> recompiled. Below you will find a complete analysis.
>
> > I'm using Apache::Reload and my test
> > script/module is as follows:
> >
> >
> > test.pl
> > --------------------
> > #!/usr/local/bin/perl
> > use strict;
> > use warnings;
> >
> > use My::Test qw(:subs);
> >
> > print "Content-type: text/plain\r\n\r\n";
> > &test1();
> > --------------------
> >
> >
> > Test.pm
> > --------------------
> > package My::Test;
> > use strict;
> > use warnings;
> >
> > BEGIN {
> >     use Exporter ();
> >
> >     our (@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
> >
> >     @ISA       = qw(Exporter);
> >     @EXPORT    = qw();
> >     @EXPORT_OK = qw();
> >
> >     %EXPORT_TAGS = (
> >                     subs => [qw(test1)],
> >                    );
> >
> >     Exporter::export_ok_tags('subs');
> >
> > }
> >
> > sub test1 { print "In test1 func\n"; }
> >
> > 1;
> > --------------------
>
> adjust the test.pl to do:
>
> test1(); print \&test1, "\n";
> #test2(); print \&test2, "\n";
>
> and My::Test.pm to:
>
> ...
> warn "test1:", \&test1, "\n";
> #warn "test2:", \&test2, "\n";
> sub test1 { print "In test1 func\n"; }
> #sub test2 { print "In test2 func\n"; }
> ...
>
> The first time you run the script you will see:
>
> output:
> In test1 func
> CODE(0x85ad38c)
>
> error_log:
> test1:CODE(0x85ad38c)
>
> you can see that both test1 and My::Test::test1 point to the same sub.
>
> > When I modify sub test1, and I reload - no changes appear
> > in the browser.  The following gets printed to error_log:
> > Subroutine test1 redefined at /export/home/httpd/cgi-bin/My/Test.pm line 22.
>
> output:
> In test1 func
> CODE(0x85ad38c)
>
> error_log:
> test1:CODE(0x84ee110)
>
> as you see the test1 is not the same as My::Test::test1
>
> > When I touch test.pl - the changes appear.  The following gets printed
> > to error_log:
> > Subroutine test1 redefined at /export/home/httpd/cgi-bin/My/test.pl line 5
>
> output:
> In test11 func
> CODE(0x84ee110)
>
> now it points to the recent My::Test::test1
>
> In that way you can debug any "mysteries" in Perl code.
>
> Now, how to solve this problem. For example comment out
>              require $key;
>
> in Reload.pm
>
> that way, test.pl will see that My::Test is not in %INC, and require it
> + call its import() method.
>
> Tell if this worked and we may adjust Reload.pm to have a special mode
> where it makes Perl forget about modified modules and let the code that
> loaded them in first place do the loading (and therefore the importing).
>
> > Finally, if I add a new subroutine test2 to Test.pm, export it, and
> > update the test.pl script to call test2, the script fails with an
> > Internal
> > Server Error.  The following gets printed to error_log:
> > "test2" is not exported by the My::Test module at
> > /export/home/httpd/cgi-bin/My/test.pl line 5
> > [Wed May 22 15:26:12 2002] [error] Can't continue after import errors at
> >
> > /export/home/httpd/cgi-bin/My/test.pl line 5
> > BEGIN failed--compilation aborted at /export/home/httpd/cgi-bin/
> > My/test.pl line 5.
> >
> > Then, when I restart the server, the script runs fine.
>
> Hmm, this one is different. Seems like a bug in Exporter.
>
> if you remove Reload.pm from the setup, so it won't confuse you and
> adjust the code to do:
>
> do "My/Test.pm";
> My::Test->import(':subs');
>
> you will see that it fails as well. This code acts like Reload.pm, but
> always reloads the module. So it's not Reload.pm's fault.
>
> Is anybody else  familiar with this Exporter's (mis)behavior?
>
> The solution that I see is to use something like this:
>
> package My::Test;
>
> use strict;
> use warnings;
>
> sub import {
>      my $package = shift;
>
>      no strict 'refs';
>      for (@_) {
>          *{ (caller)[0] . "::$_" } = \&{$_};
>      }
> }
>
> sub test1 { print "In test1 func\n"; }
> sub test2 { print "In test2 func\n"; }
>
> 1;
>
> If somebody else can see the problem with Exporter may be we need to run
> it through p5p.
>
> __________________________________________________________________
> Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
> http://stason.org/     mod_perl Guide ---> http://perl.apache.org
> mailto:stas@stason.org http://use.perl.org http://apacheweek.com
> http://modperlbook.org http://apache.org   http://ticketmaster.com




Re: Reloading Modules

Posted by Stas Bekman <st...@stason.org>.
Ted Prah wrote:
> Hi again,
> 
> I'm having trouble seeing module changes when I reload
> a script that uses it.  

That's because Reload.pm doesn't re-exports the symbols when reloading 
the module and test.pl doesn't call import() because it sees the module 
in %INC, therefore it still sees the old sub till the moment it gets 
recompiled. Below you will find a complete analysis.

> I'm using Apache::Reload and my test
> script/module is as follows:
> 
> 
> test.pl
> --------------------
> #!/usr/local/bin/perl
> use strict;
> use warnings;
> 
> use My::Test qw(:subs);
> 
> print "Content-type: text/plain\r\n\r\n";
> &test1();
> --------------------
> 
> 
> Test.pm
> --------------------
> package My::Test;
> use strict;
> use warnings;
> 
> BEGIN {
>     use Exporter ();
> 
>     our (@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
> 
>     @ISA       = qw(Exporter);
>     @EXPORT    = qw();
>     @EXPORT_OK = qw();
> 
>     %EXPORT_TAGS = (
>                     subs => [qw(test1)],
>                    );
> 
>     Exporter::export_ok_tags('subs');
> 
> }
> 
> sub test1 { print "In test1 func\n"; }
> 
> 1;
> --------------------

adjust the test.pl to do:

test1(); print \&test1, "\n";
#test2(); print \&test2, "\n";

and My::Test.pm to:

...
warn "test1:", \&test1, "\n";
#warn "test2:", \&test2, "\n";
sub test1 { print "In test1 func\n"; }
#sub test2 { print "In test2 func\n"; }
...

The first time you run the script you will see:

output:
In test1 func
CODE(0x85ad38c)

error_log:
test1:CODE(0x85ad38c)

you can see that both test1 and My::Test::test1 point to the same sub.

> When I modify sub test1, and I reload - no changes appear
> in the browser.  The following gets printed to error_log:
> Subroutine test1 redefined at /export/home/httpd/cgi-bin/My/Test.pm line 22.

output:
In test1 func
CODE(0x85ad38c)

error_log:
test1:CODE(0x84ee110)

as you see the test1 is not the same as My::Test::test1

> When I touch test.pl - the changes appear.  The following gets printed
> to error_log:
> Subroutine test1 redefined at /export/home/httpd/cgi-bin/My/test.pl line 5

output:
In test11 func
CODE(0x84ee110)

now it points to the recent My::Test::test1

In that way you can debug any "mysteries" in Perl code.

Now, how to solve this problem. For example comment out
             require $key;

in Reload.pm

that way, test.pl will see that My::Test is not in %INC, and require it 
+ call its import() method.

Tell if this worked and we may adjust Reload.pm to have a special mode 
where it makes Perl forget about modified modules and let the code that 
loaded them in first place do the loading (and therefore the importing).

> Finally, if I add a new subroutine test2 to Test.pm, export it, and
> update the test.pl script to call test2, the script fails with an
> Internal
> Server Error.  The following gets printed to error_log:
> "test2" is not exported by the My::Test module at
> /export/home/httpd/cgi-bin/My/test.pl line 5
> [Wed May 22 15:26:12 2002] [error] Can't continue after import errors at
> 
> /export/home/httpd/cgi-bin/My/test.pl line 5
> BEGIN failed--compilation aborted at /export/home/httpd/cgi-bin/
> My/test.pl line 5.
> 
> Then, when I restart the server, the script runs fine.

Hmm, this one is different. Seems like a bug in Exporter.

if you remove Reload.pm from the setup, so it won't confuse you and 
adjust the code to do:

do "My/Test.pm";
My::Test->import(':subs');

you will see that it fails as well. This code acts like Reload.pm, but 
always reloads the module. So it's not Reload.pm's fault.

Is anybody else  familiar with this Exporter's (mis)behavior?

The solution that I see is to use something like this:

package My::Test;

use strict;
use warnings;

sub import {
     my $package = shift;

     no strict 'refs';
     for (@_) {
         *{ (caller)[0] . "::$_" } = \&{$_};
     }
}

sub test1 { print "In test1 func\n"; }
sub test2 { print "In test2 func\n"; }

1;

If somebody else can see the problem with Exporter may be we need to run 
it through p5p.

__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com