Apache-ASP
view release on metacpan or search on metacpan
lib/Apache/ASP/StatINC.pm view on Meta::CPAN
package Apache::ASP;
# quickly decomped out of Apache::ASP just to optionally load
# it at runtime for CGI programs ( which shouldn't need it anyway )
# will still precompile this for mod_perl
use strict;
use vars qw( $StatINCReady $StatINCInit %Stat $StatStartTime );
$StatStartTime = time();
# Apache::StatINC didn't quite work right, so writing own
sub StatINCRun {
my $self = shift;
my $stats = 0;
# include necessary libs, without nice error message...
# we only do this once if successful, to speed up code a bit,
# and load success bool into global. otherwise keep trying
# to generate consistent error messages
unless($StatINCReady) {
my $ready = 1;
for('Devel::Symdump') {
eval "use $_";
if($@) {
$ready = 0;
$self->Error("You need $_ to use StatINC: $@ ... ".
"Please download it from your nearest CPAN");
}
}
$StatINCReady = $ready;
}
return unless $StatINCReady;
# make sure that we have pre-registered all the modules before
# this only happens on the first request of a new process
unless($StatINCInit) {
$StatINCInit = 1;
$self->Debug("statinc init");
$self->StatRegisterAll();
}
while(my($key,$file) = each %INC) {
if($self->{stat_inc_match} && defined $Stat{$file}) {
# we skip only if we have already registered this file
# we need to register the codes so we don't undef imported symbols
next unless ($key =~ /$self->{stat_inc_match}/);
}
next unless (-e $file); # sometimes there is a bad file in the %INC
my $mtime = (stat($file))[9];
# its ok if this block is CPU intensive, since it should only happen
# when modules get changed, and that should be infrequent on a production site
if(! defined $Stat{$file}) {
$self->{dbg} && $self->Debug("loading symbols first time", { $key => $file});
$self->StatRegister($key, $file, $mtime);
} elsif($mtime > $Stat{$file}) {
$self->{dbg} && $self->Debug("reloading", {$key => $file});
$stats++; # count files we have reloaded
$self->StatRegisterAll();
# we need to explicitly re-register a namespace that
# we are about to undef, in case any imports happened there
# since last we checked, so we don't delete duplicate symbols
$self->StatRegister($key, $file, $mtime);
my $class = &File2Class($key);
my $sym = Devel::Symdump->new($class);
my $function;
my $is_global_package = $class eq $self->{GlobalASA}{'package'} ? 1 : 0;
my @global_events_list = $self->{GlobalASA}->EventsList;
for $function ($sym->functions()) {
my $code = \&{$function};
if($function =~ /::O_[^:]+$/) {
$self->Debug("skipping undef of troublesome $function");
next;
}
if($Apache::ASP::Codes{$code}{count} > 1) {
$self->Debug("skipping undef of multiply defined $function: $code");
next;
}
if($is_global_package) {
# skip undef if id is an include or script
if($function =~ /::__ASP_/) {
$self->Debug("skipping undef compiled ASP sub $function");
next;
}
if(grep($function eq $class."::".$_, @global_events_list)) {
$self->Debug("skipping undef global event $function");
next;
}
if($Apache::ASP::ScriptSubs{$function}) {
$self->Debug("skipping undef script subroutine $function");
next;
}
}
$self->{dbg} && $self->Debug("undef code $function: $code");
undef(&$code); # method for perl 5.6.1
delete $Apache::ASP::Codes{$code};
undef($code); # older perls
}
# extract the lib, just incase our @INC went away
(my $lib = $file) =~ s/$key$//g;
push(@INC, $lib);
# don't use "use", since we don't want symbols imported into ASP
delete $INC{$key};
$self->Debug("loading $key with require");
eval { require($key); };
if($@) {
$INC{$key} = $file; # make sure we keep trying to reload it
$self->Error("can't require/reload $key: $@");
next;
}
# if this was the same module as the global.asa package,
# then we need to reload the global.asa, since we just
# undef'd the subs
if($is_global_package) {
# we just undef'd the global.asa routines, so these too
# must be recompiled
$self->Debug("reloading global.asa file after clearing package namespace");
delete $Apache::ASP::Compiled{$self->{GlobalASA}{'id'}};
&Apache::ASP::GlobalASA::new($self);
}
$self->StatRegister($key, $file, $mtime);
# we want to register INC now in case any new libs were
# added when this module was reloaded
$self->StatRegisterAll();
}
}
$stats;
}
sub StatRegister {
my($self, $key, $file, $mtime) = @_;
# keep track of times
$Stat{$file} = $mtime;
# keep track of codes, don't undef on codes
# with multiple refs, since these are exported
my $class = &File2Class($key);
# we skip Apache stuff as on some platforms (RedHat 6.0)
# Apache::OK seems to error when getting its code ref
# these shouldn't be reloaded anyway, as they are internal to
# modperl and should require a full server restart
if($class eq 'Apache' or $class eq 'Apache::Constants') {
$self->Debug("skipping StatINC register of $class");
return;
}
$self->{dbg} && $self->Debug("stat register of $key $file $class");
if($class eq 'CGI') {
# must compensate for its autoloading behavior, and
# precompile all the routines, so we can register them
# and not delete them later
CGI->compile(':all');
}
my $sym = Devel::Symdump->new($class);
my $function;
for $function ($sym->functions()) {
my $code = \&{$function};
unless($code =~ /CODE/) {
$self->Debug("no code ref for function $function");
next;
}
# don't update if we already have this code defined for this func.
next if $Apache::ASP::Codes{$code}{funcs}{$function};
# $self->Debug("code $code for $function");
$Apache::ASP::Codes{$code}{count}++;
$Apache::ASP::Codes{$code}{libs}{$key}++;
$Apache::ASP::Codes{$code}{funcs}{$function}++;
}
( run in 0.827 second using v1.01-cache-2.11-cpan-39bf76dae61 )