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

Hi everyone, I'm writing a small module for creating/managing sessions using MLDBM module. I have a method for adding a new pair of key-value to the session, but for some reason this change is not reflected on disk, so next time I open the session, that pair of key-value is not there. What am I doing wrong? The relevant code is below. I would appreciate any input. Also, if something in the code doesn't make sense please tell me as I'm only learning...
# # constructor # sub new { my $class = shift; my (%args) = @_; my $sessions = {}; my $session = {}; # settings / defaults my $session_id = $args{SESSION_ID} || ""; my $full_db_path = $args{FILE} || die "session db filename not def +ined"; my $timeout = ( $args{TIMEOUT} || $DEFAULT_TIMEOUT ) * 60; # and c +onvert to seconds $sync_dbm_obj = tie(%{$sessions}, 'MLDBM::Sync', $full_db_path, O_ +CREAT|O_RDWR, 0640) or die "could not create / open db file $full_db_path: $!"; for ( $session_id ) { if( $session_id ) { $sync_dbm_obj->Lock; my $aref = $sessions->{$session_id}; if( $aref ) { my $timestamp = $aref->{timestamp}; if( time() - $timestamp > $timeout ) { # session expired and has to be removed delete( $sessions->{$session_id} ); $sync_dbm_obj->UnLock; $session_id = ""; redo; } else { # update last access timestamp $aref->{timestamp} = time(); $aref->{a_session}->{_timestamp} = time(); #debug +only $sessions->{$session_id} = $aref; $sync_dbm_obj->UnLock; $session = $aref->{a_session}; } } else { $sync_dbm_obj->UnLock; $session_id = ""; redo; } } else { $session_id = create_session_id(); $sync_dbm_obj->Lock; $sessions->{$session_id} = { a_session => { _session_id => +$session_id, _timestamp => +time() }, # debug only timestamp => time() }; $session = $sessions->{$session_id}->{a_session}; $sync_dbm_obj->UnLock; } } return bless $session, $class; } # # # sub add_key { my $self = shift; my ($key, $value) = @_; $sync_dbm_obj->Lock; my $aref = $self; $aref->{$key} = $value; $self = $aref; $sync_dbm_obj->UnLock; } # # general destructor # sub DESTROY { my $self = shift; undef $sync_dbm_obj; untie(%{$self}); };
Here's how I'm calling the method:
my $session = MLDBMSession->new(FILE => "c:\\perl_user\sessions.db", S +ESSION_ID => $session_id, TIMEOUT => 100); $session->add_key( value1 => 20 );
Here's what I get when I do print Dumper $session and then print Dumper everything in sessions.db file:
$VAR1 = bless( { '_timestamp' => 1034001952, 'value1' => 20, '_session_id' => '1ca9437eec103d4d533dc22b5b2c45ab' }, 'MLDBMSession' ); Time now: Mon Oct 7 10:45:52 2002 $VAR1 = { 'a_session' => { '_timestamp' => 1034001952, '_session_id' => '1ca9437eec103d4d533dc22b5 +b2c45ab' }, 'timestamp' => 1034001952 }; Created/Last Accessed: Mon Oct 7 10:45:52 2002
Thank you, Alex

Replies are listed 'Best First'.
Re: Problem storing value in persistent hash with MLDBM
by perrin (Chancellor) on Oct 07, 2002 at 16:16 UTC
    It looks like the problem is that you are not updating at the top level, so the TIE interface is not picking up your changes. See the note under the BUGS section of the MLDBM (not MLDBM::Sync) docs. It's a limitation of Perl's TIE interface, and has a simple (albeit not pretty) workaround.
      Thank you for your reply. You're right. I also realized that, but only in a while after posting the message. Would you suggest a workaround based on the structure of my code? Should I make %{$sessions} a class variable or something and (try to) detect when something inside it changes? I can't think of a nice workaround for this. Does anyone know of a general solution in this case? It's pretty simple if I use a relational database, but I'm not so sure in the case with Berkeley DB files. Alex
        It's really not an issue of the storage mechanism (dbm vs. RDBMS), just a simple problem with Perl's TIE mechanism. In your case, I would change it so that you always write to $sessions->{$session_id} when you modify anything in the session. For example:
        my $aref = $sessions->{$session_id}; $aref->{timestamp} = time; $sessions->{$session_id} = $aref;
Re: Problem storing value in persistent hash with MLDBM
by princepawn (Parson) on Oct 07, 2002 at 17:13 UTC
      I thought Apache::Session only works with relational databases, in particular MySQL. I'm trying to find a solution that would use MLDBM or a similar module and Berkeley DB files.