The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Tie::TransactHash - Edit hash in transactions not changing order during trans.

SYNOPSIS

     use Tie::TransactHash;
     $::edit_db = tie %::edit_me, TransactHash, \%::db_as_hash, $::db; 
     while (($key, $value)=each %edit_me)) {
       $::edit_me{$key} ++ if $key =~ m/counters/ ;
     }

DESCRIPTION

Tie::TransactHash is a package which provides facilities for editing any other hash in transactions. A transaction is a group of changes which go together and are either all applied or none. When working on a standard perl hash or a hash indexed DBM file, one advantage is that the original hash remains untouched during the transaction, so its order (the order the each(), keys() or values functions give out) is maintained - changes can be made to the transact hash whilst iterating over it.

OVERVIEW

Editing a hash causes problems because it rearranges the hash. If the editing is to be done in sequence then this makes life difficult. The TransactHash class uses a fixed sequence hash class which overlays the normal hash and allows editing in place. It stores all of the changes to the original hash in memory until it is told to apply them.

As a side effect of this design, the class also provides a commit/rollback system. When a commit is called, the order of the hidden hash will be changed.

A commit will normally be done as the TransactHash object is being destroyed. This could be undesirable if your program exits when it discovers a failure. You can change the.

If you can accept the re-ordering, then you can do partial edits and commit half way through.

When working on a DBM file, if a crash occurs during the editing and no commit has been called then the original hash will be left intact. If however the crash occurs during the commit, bad things could happen.

     use DB_File;
     use Tie::TransactHash;
     use Fcntl;

     $::db = tie %::db_as_hash, DB_File, $::dbname, O_RDWR|O_CREAT, 0640, $db_type
       or die $!;

     $::edit_db = tie %::edit_me, TransactHash, \%::db_as_hash, $::db; 
     #the $::db doesn't really do any good right now, but in future it might

     my $count = 0;
     my ($key,$value)
     while(($key,$_)=each %edit_me) {
       s/bouncy/bouncy, very very bouncy./;
       m/Fred/ && do { 
         $count++;
         $edit_me{ Fred . $count } = $key;
       }
     }
     print "Found Fred in the values $count times\n";

Generally, this package should be used if you want to occasionally do small numbers of changes across the values of a large hash. If you are using it overly (often or for large numbers of changes on the database), then you should probably switch to btree indexed hashes (Berkley DBM) which give you the same ordering effect but don't use a large chunk of memory. Alternately you could consider some kind of multi-pass algorithm (scan through the database putting planned changes to a file then apply them afterwards all in one go).

METHODS

new( \%hidehash [,$hideobj] )

This creates a new TransactHash, hiding the hash \%hidehash.

TIEHASH (and other hash methods)

This is simply a call to new. See above. The other hash methods are just as for a standard hash (see perltie) and act just like one.

Iterator functions (FIRSTKEY & NEXTKEY)

The iterators first iterate over the hidden hash as normal (giving out changed values) then iterate over the storehash skipping values in the original hash.

commit() and reset()

These functions are not normally visible in the hash interface, but can be used as object methods. commit() updates the original hidden hash (which changes its order) and reset() loses all of the changes that we have made.

In the hash interface commit is called as the variable is destroyed. This should happen at exit time, but didn't seem to to me. Assigning undef to the variable you stored the object in and untie()ing the hash will force it to happen.

$transhash->autostore()

This method stores a true or false value in the object telling it whether it should automatically commit if it is destroyed. If this is set to false, then the object method $transhash->commit() must be called to store any changes, otherwise they will be lost.

If this is set to true, then be aware that exiting your program from some kind of error condition of your program (that is, not one perl knows about) would commit the changes.

$transhash->verify_write()

This function checks that a write has committed to the hash correctly. It does this by checking that all of the values in the old temporary stores match those in the new ones.

This function is untested since I don't have a sensible test case for it yet and don't need it myself. should work though.

COPYING

 Copyright (c) 1997 Michael De La Rue

This is free software and may be distributed under the same terms as perl. There is no warantee. See the file COPYING which should have been included with the distribution for one set of terms under which it may be distributed. The artistic license, distributed with perl gives the other one.