The only indication that something is amiss (other than the unpredictable behaviour) will be the following line in your error log: Variable "$foo" will not stay shared at ...
The following code demonstrates the problem with accidental closures when using Apache::Registry.
use strict; use warnings; my $foo = 5; print "Content-type: text/plain\n"; print "Content-disposition: inline; filename=foo.txt\n\n"; printf "Package: %s\n", __PACKAGE__; printf "[%s] Before: %s\n", $$, $foo; badness(5); printf "[%s] After: %s\n", $$, $foo; sub badness { my $val = shift; printf "[%s] badness: %s\n", $$, $foo; $foo += $val; }
Apache::Registry will take the above code and create a new package for it based on the ServerName and the name of the script, and then wrap the code in a sub handler {} block.
If your script is running on "foo.com" and is named "test.pl", then this is what the above code will look like after Apache::Registry is done:
First run:package Apache::ROOTfoo_2ecom::test_2epl; use Apache qw(exit); sub handler { #line 1 /www/foo.com/test.pl use strict; use warnings; my $foo = 5; print "Content-type: text/plain\n"; print "Content-disposition: inline; filename=foo.txt\n\n"; printf "Package: %s\n", __PACKAGE__; printf "[%s] Before: %s\n", $$, $foo; badness(5); printf "[%s] After: %s\n", $$, $foo; sub badness { my $val = shift; printf "[%s] badness: %s\n", $$, $foo; $foo += $val; } }
Second:Package: Apache::ROOTfoo_2ecom::test_2epl [13520] Before: 5 [13520] badness: 5 [13520] After: 10
Third:Package: Apache::ROOTfoo_2ecom::test_2epl [19331] Before: 5 [19331] badness: 5 [19331] After: 10
Fourth:Package: Apache::ROOTfoo_2ecom::test_2epl [19331] Before: 5 [19331] badness: 10 [19331] After: 5
Notice how the number within the badness sub is increasing for each process, but the $foo that is seen by the instance script is never modified after 'badness' after the first execution for that process.Package: Apache::ROOTfoo_2ecom::test_2epl [19331] Before: 5 [19331] badness: 15 [19331] After: 5
This is because the badness function is actually an inner function now, and it keeps a reference to the instance of $foo that was created for the first run.
Edit - example of how to avoid this issue added, per rhesa's suggestion
Thankfully it is easy to avoid these problems once you know why they occur.
Tips:
use strict; use warnings; my $foo = 5; print "Content-type: text/plain\n"; print "Content-disposition: inline; filename=foo.txt\n\n"; printf "Package: %s\n", __PACKAGE__; printf "[%s] Before: %s\n", $$, $foo; badness(\$foo, 5); badness(\$foo, 5); printf "[%s] After: %s\n", $$, $foo; sub badness { my ($foo,$val) = @_; printf "[%s] badness: %s\n", $$, $$foo; $$foo += $val; }
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: mod_perl / Apache::Registry accidental closures
by rhesa (Vicar) on Jul 21, 2006 at 01:43 UTC | |
by perrin (Chancellor) on Jul 21, 2006 at 17:52 UTC | |
by imp (Priest) on Jul 21, 2006 at 18:20 UTC | |
by rhesa (Vicar) on Jul 21, 2006 at 19:13 UTC | |
Re: mod_perl / Apache::Registry accidental closures
by imp (Priest) on Jul 21, 2006 at 00:51 UTC | |
by rhesa (Vicar) on Jul 21, 2006 at 01:31 UTC | |
Re: mod_perl / Apache::Registry accidental closures
by runrig (Abbot) on Jul 21, 2006 at 20:29 UTC |