rob_au has asked for the wisdom of the Perl Monks concerning the following question:

Fellow monks, I seek your guidance - I am having a great deal of trouble trying to sort out some problems which I am experiencing with tied hashes within the Apache::Session and CGI::Application frameworks. The specific problem is that information stored in the payments hash key, created in the default input_display run-mode, not being available in subsequent run modes - I am at a loss to explain this, although I am sure it must be something simple that I have overlooked.

The code in question follows:

#!/usr/bin/perl use strict; my $app = Self->new( 'PARAMS' => { 'mode_param' => 'action', 'run_modes' => { 'AUTOLOAD' => 'input_display', 'display' => 'input_display', 'finalise' => 'input_finalise', 'update' => 'input_update' }, 'start_mode' => 'display' } ); $app->run; exit 0; package Self; BEGIN { unshift @INC, '.'; } use Apache::Session::DB_File; use Business::CardAccess; use CGI::Carp; use Data::Dumper; use Template; use base 'CGI::Application'; use strict; sub setup { my $self = shift; $self->run_modes( $self->param('run_modes') || { 'start' => 'dump_ +html' } ); $self->mode_param( $self->param('mode_param') || 'rm' ); $self->start_mode( $self->param('start_mode') || 'start' ); $self->param( 'template' => Template->new({ 'INCLUDE_PATH' => $sel +f->param('tmpl_path') || '../templates' }) ); } sub input_display { my $self = shift; my $cgi = $self->query; my %session; eval { my $session_id = $cgi->cookie( -name => 'ecom', -path => '/' ) +; tie %session, 'Apache::Session::DB_File', $session_id, { 'File +Name' => '.sessions' }; }; tie %session, 'Apache::Session::DB_File', undef, { 'FileName' => ' +.sessions' } if $@; $session{'payments'} ||= [ { 'index' => 0, 'description' => 'One-Time Payment', 'amount' => 0 } ]; $self->header_props( -cookie => $cgi->cookie( -name => 'ecom', -path => '/', -value => $session{'_session_id'} ) ); my $html = ''; $self->param('template')->process('display.tt2', \%session, \$html +); untie %session; return $html; } sub input_update { my $self = shift; my $cgi = $self->query; my %session; eval { my $session_id = $cgi->cookie( -name => 'ecom', -path => '/' ) +; tie %session, 'Apache::Session::DB_File', $session_id, { 'File +Name' => '.sessions' }; }; croak( 'Cannot retrieve user session ID from client-side cookie' ) + if $@; $session{'payments'} ||= []; my @payments = @{$session{'payments'}}; foreach (0..$#payments) { $cgi->param('description_'.$_, $1) if $cgi->param('description +_'.$_) =~ /^([\w\-\ ]+)$/; $cgi->param('amount_'.$_, $1) if $cgi->param('amount_'.$_) =~ +/^\$?(\d+(?:|\.\d{1,2}))$/; splice( @payments, $_, 1, { 'index' => $_, 'description' => $cgi->param('description_'.$_), 'amount' => $cgi->param('amount_'.$_) } ); splice(@payments, $_, 1) if defined $cgi->param('delete_'.$_); } $session{'payments'} = \@payments; my $html = ''; $self->param('template')->process('display.tt2', \%session, \$html +); untie %session; return $html; } 1; __END__

 

Edited: ~Wed Jul 31 23:11:29 2002 (GMT) by footpad: Added <readmore> tag, per Consideration.

Replies are listed 'Best First'.
Re: Persistency issues with tied hashes
by mugwumpjism (Hermit) on Jul 31, 2002 at 14:42 UTC

    I had great problems with this at one point. I can't remember the details, but I see in my working code I am attempting the tie twice - once wrapped in an eval block supplying a SID and once supplying undef explicitly (if the fetch with SID failed).

    Perhaps Apache::Session is being weird because it's not getting undef but the empty string or something like that. See if the session ID is actually being remembered, investigate what is going into the temporary files. And untie %session as early as possible, definitely before you ->process the template.

      It sounds like you and I investigate along similar trains of thought :-)

      The puzzling thing about this problem from my perspective was that the session ID was being stored between run-levels ruling out such issues as file system permissions or limitations of the perlfunc:tie interface itself.

      Based upon your suggestion to untie the %session hash prior to the processing of the Template object however, I modified my code accordingly and found that this fixed my problem. From a summary review of the code, I suspect that the issue lies within the localise method of Template::Context which is called from the Template::Service instance to manipulate the passed argument hash - I will however dig further into this once I get a bit more time on my hands.

      Thanks again for your help mugwumpjism++

       

        Apache::Session does some scary things with persistence. In particular, it maintains an exlusive lock on the session data until the hash gets destroyed, which can mean that every other request for this session (including images if you aren't careful) will wait. The hash will not get destroyed while there is any existing reference to it. That's probably what's tripping you up.

        If you really want to use Apache::Session rather than something simpler like MLDBM::Sync, I suggest you treat it as a hot potato, i.e. create the hash, get what you want in and out of it as fast as you can, and get rid of it immediately. Don't leave it hanging around while you do other stuff.