problem with BerkeleyDB module and subdatabases

From: Mark E. Perkins (perkinsm_at_bway.net)
Date: 02/28/05


Date: Sun, 27 Feb 2005 20:40:05 -0500

Greetings,

Executive Summary:
I can't get the latest version of the BerkeleyDB module (v0.26) with the
latest version of Sleepycat (v4.3.27) to create subdatabases properly.
Sample code at end illustrates my problem.

Details:
Using the BerkeleyDB module (v0.26), Sleepycat 4.3.27 and Perl 5.8.6 under
Mac OS X 10.3.8, attempts to create a db with four subdatabases only
creates two of them. A second run of the sample code adds one of the
subdatabases that was missing, but one of those that *was* created on the
first run turns out to have data that were intended for one that went
missing on the first run. A third run of the code finally gets all four
subdatabases, but (understandably) with the same unwanted data as noted
after the second run.

I don't think this is the way subdatabases are intended to work 8) But I
can't see my error.

The sample code included below (when saved as bdb-tst), produces the
following output ('-> ' is the shell prompt string):

-> rm -f junk.db
-> ./bdb-tst
h1{k1} = v1
h2{k2} = v2
h3{k3} = v3
h4{k4} = v4
subdb names are:
hash_1
hash_4
-> ./bdb-tst
h1{k1} = v1
h2{k2} = v2
h3{k3} = v3
h4{k3} = v3
h4{k4} = v4
subdb names are:
hash_1
hash_3
hash_4
-> ./bdb-tst
h1{k1} = v1
h2{k2} = v2
h3{k3} = v3
h4{k3} = v3
h4{k4} = v4
subdb names are:
hash_1
hash_2
hash_3
hash_4
-> ./bdb-tst
h1{k1} = v1
h2{k2} = v2
h3{k3} = v3
h4{k3} = v3
h4{k4} = v4
subdb names are:
hash_1
hash_2
hash_3
hash_4

Additional observations:
I see similar (erroneous) behavior when I use the 'new' form of the the
BerkeleyDB::Hash constructor for each of the subdatabases; which
subdatabases get created on which runs is different, but still two on the
first and one on each subsequent, with similarly erroneous data. My app
needs MLDBM, hence the tied hash version in the sample code.

I see exactly the same results under Solaris 9 with Perl 5.8.4 and the same
versions of BerkeleyDB and Sleepycat noted above.

Everything works as expected under Mac OS X 10.3.8 with Perl 5.8.6,
Sleepycat 4.1.25 and BerkeleyDB 0.26.

Sample code below follows closely (and borrows from) the subdb.t test
module from BerkeleyDB...

After all that explanation, can someone point me at what I'm doing wrong?

Thanks,
Mark

---------------8<--------------- cut here ---------------8<---------------
#!/usr/bin/perl
#
#bdb-tst to illustrate subdatabase problem

use strict;
use warnings;

use BerkeleyDB;

tie my %h1, 'BerkeleyDB::Hash', -Filename => "junk.db",
                                 -Subname => "hash_1",
                                 -Flags => DB_CREATE
   or die "cannot tie h1: ($!)";

tie my %h2, 'BerkeleyDB::Hash', -Filename => "junk.db",
                                 -Subname => "hash_2",
                                 -Flags => DB_CREATE
   or die "cannot tie h2: ($!)";

tie my %h3, 'BerkeleyDB::Hash', -Filename => "junk.db",
                                 -Subname => "hash_3",
                                 -Flags => DB_CREATE
   or die "cannot tie h3: ($!)";

tie my %h4, 'BerkeleyDB::Hash', -Filename => "junk.db",
                                 -Subname => "hash_4",
                                 -Flags => DB_CREATE
   or die "cannot tie h4: ($!)";

$h1{k1} = 'v1';
$h2{k2} = 'v2';
$h3{k3} = 'v3';
$h4{k4} = 'v4';

for my $k ( sort keys %h1 ) {
     print "h1{$k} = $h1{$k}\n";
}

for my $k ( sort keys %h2 ) {
     print "h2{$k} = $h2{$k}\n";
}

for my $k ( sort keys %h3 ) {
     print "h3{$k} = $h3{$k}\n";
}

for my $k ( sort keys %h4 ) {
     print "h4{$k} = $h4{$k}\n";
}

untie %h1;
untie %h2;
untie %h3;
untie %h4;

# check to see what subdatabases are actually in the db

my $db = new BerkeleyDB::Unknown -Filename => "junk.db",
                                  -Flags => DB_RDONLY;

my $cursor = $db->db_cursor();
my ($k, $v) = ("", "");
my $status;
my @dbnames = ();
while ( ($status = $cursor->c_get($k, $v, DB_NEXT) ) == 0) {
     push @dbnames, $k;
}

print "subdb names are:\n";
print "$_\n" for @dbnames;