1752793 Members
6067 Online
108789 Solutions
New Discussion юеВ

DBM and hash of hash

 
SOLVED
Go to solution
Paul Thach
New Member

DBM and hash of hash

This sample code does not work as expected. I call a function to set a hash of hash and save it to DBM file [setHoHandSaveToDbm()] and then call another funtion to print out the hash of hash [printHoHFromDbm()]. That work fine. After saving the hash of hash in the DBM database I should be able to comment out the 'setHoHandSaveToDbm()' and just call the 'printHoHFromDbm', but when I do that I only get the hash key. Can someone please explain the error?


#!/usr/bin/perl
use AnyDBM_File;
# use NDBM_File; # load database module
use Fcntl; # for O_ constants

my $DATAFILE = "/tmp/data";

&setHoHandSaveToDbm();
&printHoHFromDbm();

exit();

sub printHoHFromDbm {
print "printHoHFromDbm \n";
my %D = ();
#tie( %D, "NDBM_File", $DATAFILE, O_RDONLY, 0644 )
# or die "Can't open $DATAFILE:$!\n";
dbmopen( %D, $DATAFILE, 0644 )
or die "Can't open for reading $DATAFILE:$!\n";
for my $k1 ( sort keys %D ) {
print "$k1 $D{$K1}\n";
for my $k2 ( sort keys %{$D{$k1}}) {
print "\t$k2\n";
for my $k3 ( sort keys %{$D{$k1}{$k2}} ) {
print "\t\t$k3 => $D{$k1}{$k2}{$k3}\n";
}
}
}
dbmclose(%D);
#untie(%D);
}

sub setHoHandSaveToDbm(){
my $DATA = ();
#tie( %DATA, "NDBM_File", $DATAFILE, O_RDWR | O_CREAT, 0666 )
# or die "Can't open $DATAFILE:$!\n";
dbmopen ( %DATA, $DATAFILE, 0644 )
or die "Can't open $DATAFILE:$!\n";
$DATA{'bt000'}{'Los'}{'10.184.136.105'} = "Mar 21 2006 01:20";
$DATA{'bt001'}{'Crt17'}{'10.165.248.40'} = "Mar 21 2006 01:51";
#untie (%DATA);
dbmclose(%DATA);
}

4 REPLIES 4
Patrice Le Guyader
Respected Contributor
Solution

Re: DBM and hash of hash

Hi Paul,

I'm not a senior programmer in perl but I wonder if you can store such structure without MLDBM. What I can propose you is this :
---------------------------------------------
#!/usr/bin/perl
use AnyDBM_File;
use Fcntl; # for O_ constants

my $DATAFILE = "/temp/data";
### The pack and unpack template.
$PACKFORMAT = 'A10 A15 A17';

#setHoHandSaveToDbm();
printHoHFromDbm();

exit();

sub printHoHFromDbm {
print "printHoHFromDbm \n";
my %D = ();
dbmopen( %D, $DATAFILE, 0644 ) or die "Can't open for reading $DATAFILE:$!\n";
### Dump the database
foreach my $key ( keys %D ) {
my ( $location, $IP, $date ) = unpack( $PACKFORMAT, $D{$key} );
print "Nom : $key, \n\n";
print "Location: $location\n";
print "Ip : $IP\n";
print "Date: $date\n\n";
}
dbmclose(%D);
}

sub setHoHandSaveToDbm{
my $DATA = ();
#tie( %DATA, "NDBM_File", $DATAFILE, O_RDWR | O_CREAT, 0666 )
# or die "Can't open $DATAFILE:$!\n";
dbmopen ( %DATA, $DATAFILE, 0644 )
or die "Can't open $DATAFILE:$!\n";
$DATA{'bt000'} =
pack( $PACKFORMAT, 'Los', '10.184.136.105',
'Mar 21 2006 01:20');
$DATA{'bt001'} =
pack( $PACKFORMAT, 'Crt17', '10.165.248.40',
'Mar 21 2006 01:51');
dbmclose(%DATA);
}
---------------------------------------------
with the following output :

printHoHFromDbm
Nom : bt000,
Location: Los
Ip : 10.184.136.105
Date: Mar 21 2006 01:20
Nom : bt001,
Location: Crt17
Ip : 10.165.248.40
Date: Mar 21 2006 01:51

Hope this helps and that a perl guru has the answer. Note that I didn't take the time to tune the $PACKFORMAT for you need.
Pat
Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement.
Paul Thach
New Member

Re: DBM and hash of hash

Thanks Pat,

The data get pretty large 9,000+ lines. I need to keep it in hash of hash format for fast accessibility, rather then having to traversing the hash to find the information. Is there a way for me save a hash of hash into DBM file?

Paul
Patrice Le Guyader
Respected Contributor

Re: DBM and hash of hash

Hi paul,

As I have previously asked you should use MLDBM to do this. This module has some limitation, it use Data::Dumper module to store data ,it convert data structures to and from strings so that they can be stored in a DBM file. It doesn't store references, instead it stores the data that the references refer to so you can't access directly to it, you must use temporary variables.
If you want I can modify previous exemple for MLDBM,unfortunately I don't have MLDBM module on my laptop to try it, so I just need some time to test what I'm going to give to you. :-)

Regards
Kenavo
Pat
Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement.
Patrice Le Guyader
Respected Contributor

Re: DBM and hash of hash

Demat Paul (Again)

With the mldbm module you should have to get the dbm_file one too. Another possibility should be DBD::DBM. No matter here is the next version of your script and I hope this is what you expected to do :-)
---------------------------------------------
#!/usr/bin/perl

use mldbm qw( DB_File Data::Dumper );
# MLDBM uses Data::Dumper to convert data structures to and from strings so that they can be stored in a DBM file.
# It doesn't store references, instead it stores the data that the references refer to.

# An important limitation of MLDBM is that you can't add to or alter the structure in the reference without assignment to a temporary variable.
# To compare data that you retrieve from a MLDBM database, you need to compare the values within the structure.
# Each time MLDBM retrieves a data structure from the DBM file, it generates a new copy of that data.

use Fcntl; # for O_ constants

my $DATAFILE = "/temp/data.dat";

setHoHandSaveToDbm();
printHoHFromDbm();
exit();

sub printHoHFromDbm {
print "printHoHFromDbm \n";
my %D = ();

# Each time MLDBM retrieves a data structure from the DBM file,
# it generates a new copy of that data.
# To compare data that you retrieve from a MLDBM database, you need to compare
# the values within the structure:
tie my %D, 'MLDBM', $DATAFILE, O_RDWR, 0666 or die "Can't open for reading $DATAFILE:$!\n";
# Dump the database
# Just with Data::Dumper
print Data::Dumper->Dump( [ \%D ] );
# or by accessing the duplicate structure
my $btref=$D{'bt001'};
printf "The name %s has the IP %s at the date :%s \n",
$btref->{name},
$btref->{Ip},
$btref->{date};
# Try to modify the IP of Crt17
$btref->{Ip}="10.165.248.250";
$D{'bt001'}=$btref;

# Is our modification OK ?
my $btref1=$D{'bt001'};
printf "The name %s has the IP %s at the date :%s \n",
$btref1->{name},
$btref1->{Ip},
$btref1->{date};

untie(%D);
}

sub setHoHandSaveToDbm{

# Remove the datafile file in case it exists already
unlink $DATAFILE;

tie my %DATA, 'MLDBM', $DATAFILE, O_CREAT | O_RDWR, 0666 or die "Can't open $DATAFILE:$!\n";

# Inserting records in the database
%DATA = (
'bt000' => {
name => 'Los',
Ip => '10.184.136.105',
date => 'Mar 21 2006 01:20'
},
'bt001' => {
name => 'Crt17',
Ip => '10.165.248.40',
date => 'Mar 21 2006 01:51'
}
);

untie %DATA;
}
---------------------------------------------
It produce this for me :
$VAR1 = {
'bt000' => {
'date' => 'Mar 21 2006 01:20',
'name' => 'Los',
'Ip' => '10.184.136.105'
},
'bt001' => {
'date' => 'Mar 21 2006 01:51',
'name' => 'Crt17',
'Ip' => '10.165.248.40'
}
};
The name Crt17 has the IP 10.165.248.40 at the date :Mar 21 2006 01:51
The name Crt17 has the IP 10.165.248.250 at the date :Mar 21 2006 01:51

As you can see perl is a great toolbox.

Hope this helps
Kenavo
pat
Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement.