Have a header now
rkinyon [Fri, 7 Apr 2006 01:31:09 +0000 (01:31 +0000)]
lib/DBM/Deep.pm
lib/DBM/Deep/Engine.pm
t/06_error.t

index 688e936..21adc09 100644 (file)
@@ -122,8 +122,6 @@ sub _init {
         ? $args->{root}
         : DBM::Deep::_::Root->new( $args );
 
-    #XXX Right before this line, we have to set the physical parameters like
-    #XXX 2S vs. 4N vs. 8Q or max_buckets, etc.
     $self->{engine}->setup_fh( $self );
 
     return $self;
@@ -1461,6 +1459,9 @@ L<http://search.cpan.org/search?module=Digest::SHA256> for more information.
 B<Note:> Your returned digest strings must be B<EXACTLY> the number
 of bytes you specify in the hash_size parameter (in this case 32).
 
+B<Note:> If you do choose to use a custom digest algorithm, you must set it
+every time you access this file. Otherwise, the default (MD5) will be used.
+
 =head1 CIRCULAR REFERENCES
 
 DBM::Deep has B<experimental> support for circular references.  Meaning you
index 81135c2..3527091 100644 (file)
@@ -69,11 +69,17 @@ sub new {
         $self->{max_buckets} = 16;
     }
 
+    return $self;
+}
+
+sub calculate_sizes {
+    my $self = shift;
+
     $self->{index_size}       = (2**8) * $self->{long_size};
     $self->{bucket_size}      = $self->{hash_size} + $self->{long_size} * 2;
     $self->{bucket_list_size} = $self->{max_buckets} * $self->{bucket_size};
 
-    return $self;
+    return;
 }
 
 sub write_file_header {
@@ -83,10 +89,18 @@ sub write_file_header {
     my $fh = $obj->_fh;
 
     my $loc = $self->_request_space(
-        $obj, length( SIG_FILE ) + $self->{data_size},
+        $obj, length( SIG_FILE ) + 12,
     );
     seek($fh, $loc + $obj->_root->{file_offset}, SEEK_SET);
-    print( $fh SIG_FILE, pack('N', 0) );
+    print( $fh
+        SIG_FILE,
+        pack('N', 0),
+        pack('S', $self->{long_size}),
+        pack('A', $self->{long_pack}),
+        pack('S', $self->{data_size}),
+        pack('A', $self->{data_pack}),
+        pack('S', $self->{max_buckets}),
+    );
 
     return;
 }
@@ -100,15 +114,21 @@ sub read_file_header {
     seek($fh, 0 + $obj->_root->{file_offset}, SEEK_SET);
     my $buffer;
     my $bytes_read = read(
-        $fh, $buffer, length(SIG_FILE) + $self->{data_size},
+        $fh, $buffer, length(SIG_FILE) + 12,
     );
 
     if ( $bytes_read ) {
-        my ($signature, $version) = unpack( 'A4 N', $buffer );
+        my ($signature, $version, @values) = unpack( 'A4 N S A S A S', $buffer );
         unless ($signature eq SIG_FILE) {
             $self->close_fh( $obj );
             $obj->_throw_error("Signature not found -- file is not a Deep DB");
         }
+
+        $#values = 4;
+        if ( grep { !defined } @values ) {
+            die "DBM::Deep: Corrupted file - bad header\n";
+        }
+        @{$self}{qw( long_size long_pack data_size data_pack max_buckets )} = @values;
     }
 
     return $bytes_read;
@@ -123,9 +143,12 @@ sub setup_fh {
     my $fh = $obj->_fh;
     flock $fh, LOCK_EX;
 
+    #XXX The duplication of calculate_sizes needs to go away
     unless ( $obj->{base_offset} ) {
         my $bytes_read = $self->read_file_header( $obj );
 
+        $self->calculate_sizes;
+
         ##
         # File is empty -- write header and master index
         ##
@@ -160,6 +183,9 @@ sub setup_fh {
             }
         }
     }
+    else {
+        $self->calculate_sizes;
+    }
 
     #XXX We have to make sure we don't mess up when autoflush isn't turned on
     unless ( $obj->_root->{inode} ) {
index 9f3e59e..b680d82 100644 (file)
@@ -19,7 +19,7 @@ print FH 'DPDB';
 close FH;
 throws_ok {
     DBM::Deep->new( $filename );
-} qr/DBM::Deep: Corrupted file, no master index record/, "Fail if there's no master index record";
+} qr/DBM::Deep: Corrupted file - bad header/, "Fail if there's a bad header";
 
 {
     my ($fh, $filename) = new_fh();