Mailing List Archive

apparent bug in udat handling
We have been extensively using udat with great success in our software
here. However, we have discovered what seems like a bug in the way udat
handles persistence. To summarize the bug, we believe that udat does not
properly store state information unless a scalar is stored as a value for a
top-level key in udat. We are using perl 5.6, Embperl 1.3b3, mod_perl 1.24
and Apache::Session 1.03. We are using FileStore for persistence.
Documentation so that you may reproduce the bug is given below. This
message contains two embperl files and a function which is contained in the
utility.pm module. The function, set_app_state, is used to allow authors of
different applications to stay entirely under a single key in udat; this
allows each application author to avoid polluting udat's top-level
namespace. persist1.shtml: --------------- [.- use utility; $foo =
set_app_state('foo', \%udat); $bar = set_app_state('bar', $foo); -]

Now on page 1

join(", ", keys(%{$bar})) = [+ join(", ", keys(%{$bar})) +]
If you load the above page, $bar should be equivalent to
$udat{'foo'}->{'bar'}. This value will have no keys, so the "join"
expression will show an empty result. persist2.shtml: --------------- [.-
use utility; $state = set_app_state('foo', \%udat); $bar =
set_app_state('bar', $state); $bar->{'foo'} = "whee";
$udat{'foo'}->{'bar'}{'foo'} = "whee"; #$udat{'bar'} = "lalala"; -]

Now on page 2

join(", ", keys(%{$bar})) = [+ join(", ", keys(%{$bar})) +]
$udat{'foo'}->{'bar'}{'foo'} = [+ $udat{'foo'}->{'bar'}{'foo'} +]
$udat{'bar'} = [+ $udat{'bar'} +]
In the above code, $state is the same as $udat{'foo'} and $bar is the same
as $udat{'foo'}->{'bar'}. So when we say $bar->{'foo'} = "whee", that is
equivalent to saying $udat{'foo'}->{'bar'}{'foo'} = "whee". The problem is
that if we click the button to take us back to page 1, the key ("foo") for
$udat{'foo'}->{'bar'} is not displayed. In other words, %udat is not
storing the data structure we're creating. However, if we uncomment the
$udat{'bar'} = "lalala" line above, everything works as expected. Said
another way, if we assign a scalar to a key at the top level of udat, the
remainder of our data structures are saved/remembered, but if we don't have
any scalars associated with top-level keys, it doesn't work. The
set_app_state function is given below: set_app_state from utility.pm:
------------------------------ sub set_app_state { my($app, $udat_ref) =
@_; confess "function must be passed the name of the application" unless
($app); confess "function must be passed a reference to udat" unless
(ref($udat_ref) eq "HASH"); if (!defined($udat_ref->{$app})) {
$udat_ref->{$app} = {}; } return $udat_ref->{$app}; } We have worked around
this problem by simply assigning a value to a top-level key in the
set_app_state function, so this does not represent a current problem for
us. However, it took a couple hours of debugging to isolate the problem, so
IMHO this is still worth documenting/fixing. steve

--
Steven D. Arnold Que quiero sera stevena@neosynapse.net
"If you have built castles in the air, your work need not be lost; that
is where they should be. Now put the foundations under them!" -- Thoreau
RE: apparent bug in udat handling [ In reply to ]
>
> We have been extensively using udat with great success in our software
> here. However, we have discovered what seems like a bug in the way udat
> handles persistence. To summarize the bug, we believe that udat does not
> properly store state information unless a scalar is stored as a
> value for a
> top-level key in udat.

That's not a bug, but the well defined behaviour of Apache::Session. There
is no way for Apache::Session to see that a non top level key has changed.
To workaround this problem, simply do a $udat{xxx}++ in each page that
updates only non top level keys.

Gerald