On Wednesday 15 March 2006 18:55, Perrin Harkins wrote:
> On Wed, 2006-03-15 at 12:23 -0500, Geoffrey Young wrote:
> > I actually thing that would be somewhat common. and as I understand
> > things, the fix would require the middle step to be
> >
> > -- next handler
> > my $o = $r->pnotes('foo');
> > $o->set(bar => 1); # sets $o->{_bar} = 1
> > $r->pnotes(foo => $o);
> >
> > in order for $o to maintain it's internal state. is that right? if so,
> > I don't like that very much.
>
> I agree, cloning is not the answer. What you want really want here is
> for it to behave like a normal perl variable assignment, i.e. if you
> assign a reference, it stays a reference, and if you assign a value,
> it's just a value, not a double-secret-probation reference. I don't
> think it's a good idea to change this unless it can be done that way.
The current implementation of
$r->pnotes(foo=>$x)
is halfway similar to
$r->pnotes->{foo}=\$x.
Only halfway because fetching the value works as expected: $r->pnotes('foo').
In pure Perl the exact behavior cannot be expressed.
Internally pnotes are stored in a HV. $r->pnotes without arguments returns a
reference to that HV. Hence, $r->pnotes->{foo}=$o works as a normal
assignment of a hash element:
$ perl -MDevel::Peek -e '$x=1; Dump($x); $h{x}=$x; Dump(\%h);'
SV = IV(0x816e598) at 0x816c6fc
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 1
SV = RV(0x8178d48) at 0x8151d40
REFCNT = 1
FLAGS = (TEMP,ROK)
RV = 0x816c744
SV = PVHV(0x81699c8) at 0x816c744
...
Elt "x" HASH = 0x9303a5e5
SV = IV(0x816e59c) at 0x8151c20
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 1
Note that the refcounts of both IVs the first after $x=1 and the second in %h
are 1. Also the IVs themself are different objects one at 0x816e598 the
second at 0x816e59c.
With $r->pnotes->{x}=$x the output is similar.
But with $r->pnotes(x=>$x) it changes:
SV = IV(0x84c0664) at 0x866099c
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 1
SV = RV(0x8640b68) at 0x8651a7c
REFCNT = 2
FLAGS = (TEMP,ROK)
RV = 0x86397ec
SV = PVHV(0x86453a0) at 0x86397ec
...
Elt "x" HASH = 0x9303a5e5
SV = IV(0x84c0664) at 0x866099c
REFCNT = 2
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 1
Now the both IVs are the same (0x84c0664) and the refcount after storing as a
pnote is 2. And here is the problem. $r->pnotes->{x}=$x and $r->pnotes(x=>$x)
are different operations. The first stores a copy of the IV represented by
$x. The second stores the IV $x itself. This is somehow similar to *y=\$x:
$ perl -e '$x=1; *y=\$x; $x++; print "$y\n";'
2
$ perl -MDevel::Peek -e '$x=1; Dump($x); *y=\$x; Dump($y);'
SV = IV(0x816e590) at 0x816c6f4
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 1
SV = IV(0x816e590) at 0x816c6f4
REFCNT = 2
FLAGS = (IOK,pIOK)
IV = 1
I think it is a bug even in MP1.
Here the code that produces the output in error_log:
package pn;
use strict;
use Apache2::RequestRec;
use Apache2::RequestIO;
use Apache2::RequestUtil;
use Apache2::Const -compile=>'OK';
use Devel::Peek;
sub handler {
my $r=shift;
my $x=1;
Dump($x);
$r->pnotes(x=>$x);
Dump($r->pnotes);
$r->print("ok\n");
return Apache2::Const::OK;
}
1;
Devel::Peek uses buffered output at C-level. Hence, you probably have to
restart the server to see the actual output.
Torsten
pgpXiWwBmTuqP.pgp
Description: PGP signature
