The header now has its own sector. A lot needs to be moved over to it, but it's there.
rkinyon@cpan.org [Fri, 20 Jun 2008 14:30:02 +0000 (14:30 +0000)]
git-svn-id: http://svn.ali.as/cpan/trunk/DBM-Deep@3610 88f4d9cd-8a04-0410-9d60-8f63309c3137

lib/DBM/Deep/Array.pm
lib/DBM/Deep/Engine.pm
lib/DBM/Deep/Engine/Sector.pm
lib/DBM/Deep/Engine/Sector/FileHeader.pm [new file with mode: 0644]
lib/DBM/Deep/Engine/Sector/Reference.pm
lib/DBM/Deep/Engine/Sector/Scalar.pm
lib/DBM/Deep/File.pm
t/03_bighash.t
t/04_array.t
t/26_scalar_ref.t

index 186817b..d6df2d6 100644 (file)
@@ -26,12 +26,17 @@ sub TIEARRAY {
 
     $args->{type} = $class->TYPE_ARRAY;
 
-    return $class->_init($args);
+    my $self = $class->_init($args);
+
+#    $self->STORESIZE;
+
+    return $self;
 }
 
 sub FETCH {
     my $self = shift->_get_self;
     my ($key) = @_;
+    warn "ARRAY:FETCH( $key )\n" if DBM::Deep::DEBUG;
 
     $self->lock_shared;
 
@@ -63,6 +68,7 @@ sub FETCH {
 sub STORE {
     my $self = shift->_get_self;
     my ($key, $value) = @_;
+    warn "ARRAY::STORE($self, $key)\n" if DBM::Deep::DEBUG;
 
     $self->lock_exclusive;
 
@@ -104,6 +110,7 @@ sub STORE {
 sub EXISTS {
     my $self = shift->_get_self;
     my ($key) = @_;
+    warn "ARRAY::EXISTS($self, $key)\n" if DBM::Deep::DEBUG;
 
     $self->lock_shared;
 
@@ -174,24 +181,31 @@ sub DELETE {
 # going to work.
 sub FETCHSIZE {
     my $self = shift->_get_self;
+    warn "ARRAY::FETCHSIZE($self)\n" if DBM::Deep::DEBUG;
 
     $self->lock_shared;
 
     my $SAVE_FILTER = $self->_engine->storage->{filter_fetch_value};
     $self->_engine->storage->{filter_fetch_value} = undef;
 
+    # If there is no flushing, then things get out of sync.
+#    warn "FETCHSIZE BEG: " . $self->_engine->_dump_file;
     my $size = $self->FETCH('length') || 0;
+#    warn "FETCHSIZE AFT: " . $self->_engine->_dump_file;
 
     $self->_engine->storage->{filter_fetch_value} = $SAVE_FILTER;
 
     $self->unlock;
 
+#    warn "FETCHSIZE END: " . $self->_engine->_dump_file;
+
     return $size;
 }
 
 sub STORESIZE {
     my $self = shift->_get_self;
     my ($new_length) = @_;
+    warn "ARRAY::STORESIZE($self, $new_length)\n" if DBM::Deep::DEBUG;
 
     $self->lock_exclusive;
 
@@ -209,6 +223,7 @@ sub STORESIZE {
 
 sub POP {
     my $self = shift->_get_self;
+    warn "ARRAY::POP($self)\n" if DBM::Deep::DEBUG;
 
     $self->lock_exclusive;
 
@@ -230,6 +245,7 @@ sub POP {
 
 sub PUSH {
     my $self = shift->_get_self;
+    warn "ARRAY::PUSH($self)\n" if DBM::Deep::DEBUG;
 
     $self->lock_exclusive;
 
@@ -256,7 +272,7 @@ sub _move_value {
 
 sub SHIFT {
     my $self = shift->_get_self;
-    warn "SHIFT($self)\n" if DBM::Deep::DEBUG;
+    warn "ARRAY::SHIFT($self)\n" if DBM::Deep::DEBUG;
 
     $self->lock_exclusive;
 
@@ -285,6 +301,7 @@ sub SHIFT {
 
 sub UNSHIFT {
     my $self = shift->_get_self;
+    warn "ARRAY::UNSHIFT($self)\n" if DBM::Deep::DEBUG;
     my @new_elements = @_;
 
     $self->lock_exclusive;
@@ -297,12 +314,15 @@ sub UNSHIFT {
             $self->_move_value( $i, $i+$new_size );
         }
 
+#        warn "BEFORE: " . $self->_dump_file;
         $self->STORESIZE( $length + $new_size );
     }
 
+#    $self->_engine->flush;
     for (my $i = 0; $i < $new_size; $i++) {
         $self->STORE( $i, $new_elements[$i] );
     }
+        warn "AFTER : " . $self->_dump_file;
 
     $self->unlock;
 
@@ -311,6 +331,7 @@ sub UNSHIFT {
 
 sub SPLICE {
     my $self = shift->_get_self;
+    warn "ARRAY::SPLICE($self)\n" if DBM::Deep::DEBUG;
 
     $self->lock_exclusive;
 
@@ -377,6 +398,7 @@ sub SPLICE {
 # We don't need to populate it, yet.
 # It will be useful, though, when we split out HASH and ARRAY
 sub EXTEND {
+    warn "ARRAY::EXTEND()\n" if DBM::Deep::DEBUG;
     ##
     # Perl will call EXTEND() when the array is likely to grow.
     # We don't care, but include it because it gets called at times.
index bb299e7..7841b1e 100644 (file)
@@ -5,13 +5,6 @@ use 5.006_000;
 use strict;
 use warnings FATAL => 'all';
 
-use DBM::Deep::Engine::Sector::BucketList;
-use DBM::Deep::Engine::Sector::Index;
-use DBM::Deep::Engine::Sector::Null;
-use DBM::Deep::Engine::Sector::Reference;
-use DBM::Deep::Engine::Sector::Scalar;
-use DBM::Deep::Iterator;
-
 # Never import symbols into our namespace. We are a class, not a library.
 # -RobK, 2008-05-27
 use Scalar::Util ();
@@ -47,6 +40,16 @@ my %StP = (
 );
 sub StP { $StP{$_[1]} }
 
+# Import these after the SIG_* definitions because those definitions are used
+# in the headers of these classes. -RobK, 2008-06-20
+use DBM::Deep::Engine::Sector::BucketList;
+use DBM::Deep::Engine::Sector::FileHeader;
+use DBM::Deep::Engine::Sector::Index;
+use DBM::Deep::Engine::Sector::Null;
+use DBM::Deep::Engine::Sector::Reference;
+use DBM::Deep::Engine::Sector::Scalar;
+use DBM::Deep::Iterator;
+
 ################################################################################
 
 sub new {
@@ -183,7 +186,7 @@ sub make_reference {
 
     # This will be a Reference sector
     my $sector = $self->_load_sector( $obj->_base_offset )
-        or DBM::Deep->_throw_error( "How did get_classname fail (no sector for '$obj')?!" );
+        or DBM::Deep->_throw_error( "How did make_reference fail (no sector for '$obj')?!" );
 
     if ( $sector->staleness != $obj->_staleness ) {
         return;
@@ -281,10 +284,10 @@ sub write_value {
 
     # This will be a Reference sector
     my $sector = $self->_load_sector( $obj->_base_offset )
-        or DBM::Deep->_throw_error( "Cannot write to a deleted spot in DBM::Deep." );
+        or DBM::Deep->_throw_error( "1: Cannot write to a deleted spot in DBM::Deep." );
 
     if ( $sector->staleness != $obj->_staleness ) {
-        DBM::Deep->_throw_error( "Cannot write to a deleted spot in DBM::Deep." );
+        DBM::Deep->_throw_error( "2: Cannot write to a deleted spot in DBM::Deep." );
     }
 
     my ($class, $type);
@@ -411,45 +414,44 @@ sub setup_fh {
     my $self = shift;
     my ($obj) = @_;
 
-    # We're opening the file.
-    unless ( $obj->_base_offset ) {
-        my $bytes_read = $self->_read_file_header;
+    return 1 if $obj->_base_offset;
 
-        # Creating a new file
-        unless ( $bytes_read ) {
-            $self->_write_file_header;
+    my $header = DBM::Deep::Engine::Sector::FileHeader->new({
+        engine => $self,
+    });
 
-            # 1) Create Array/Hash entry
-            my $initial_reference = DBM::Deep::Engine::Sector::Reference->new({
-                engine => $self,
-                type   => $obj->_type,
-            });
-            $obj->{base_offset} = $initial_reference->offset;
-            $obj->{staleness} = $initial_reference->staleness;
+    # Creating a new file
+    if ( $header->is_new ) {
+        # 1) Create Array/Hash entry
+        my $sector = DBM::Deep::Engine::Sector::Reference->new({
+            engine => $self,
+            type   => $obj->_type,
+        });
+        $obj->{base_offset} = $sector->offset;
+        $obj->{staleness} = $sector->staleness;
 
-            $self->storage->flush;
+        $self->flush;
+    }
+    # Reading from an existing file
+    else {
+        $obj->{base_offset} = $header->size;
+        my $sector = DBM::Deep::Engine::Sector::Reference->new({
+            engine => $self,
+            offset => $obj->_base_offset,
+        });
+        unless ( $sector ) {
+            DBM::Deep->_throw_error("Corrupted file, no master index record");
         }
-        # Reading from an existing file
-        else {
-            $obj->{base_offset} = $bytes_read;
-            my $initial_reference = DBM::Deep::Engine::Sector::Reference->new({
-                engine => $self,
-                offset => $obj->_base_offset,
-            });
-            unless ( $initial_reference ) {
-                DBM::Deep->_throw_error("Corrupted file, no master index record");
-            }
-
-            unless ($obj->_type eq $initial_reference->type) {
-                DBM::Deep->_throw_error("File type mismatch");
-            }
 
-            $obj->{staleness} = $initial_reference->staleness;
+        unless ($obj->_type eq $sector->type) {
+            DBM::Deep->_throw_error("File type mismatch");
         }
 
-        $self->storage->set_inode;
+        $obj->{staleness} = $sector->staleness;
     }
 
+    $self->storage->set_inode;
+
     return 1;
 }
 
@@ -654,157 +656,65 @@ sub clear_entries {
 
 ################################################################################
 
-{
-    my $header_fixed = length( SIG_FILE ) + 1 + 4 + 4;
-    my $this_file_version = 3;
-
-    sub _write_file_header {
-        my $self = shift;
-
-        my $nt = $self->num_txns;
-        my $bl = $self->txn_bitfield_len;
-
-        my $header_var = 1 + 1 + 1 + 1 + $bl + $STALE_SIZE * ($nt - 1) + 3 * $self->byte_size;
-
-        my $loc = $self->storage->request_space( $header_fixed + $header_var );
-
-        $self->storage->print_at( $loc,
-            SIG_FILE,
-            SIG_HEADER,
-            pack('N', $this_file_version), # At this point, we're at 9 bytes
-            pack('N', $header_var),        # header size
-            # --- Above is $header_fixed. Below is $header_var
-            pack('C', $self->byte_size),
-
-            # These shenanigans are to allow a 256 within a C
-            pack('C', $self->max_buckets - 1),
-            pack('C', $self->data_sector_size - 1),
-
-            pack('C', $nt),
-            pack('C' . $bl, 0 ),                           # Transaction activeness bitfield
-            pack($StP{$STALE_SIZE}.($nt-1), 0 x ($nt-1) ), # Transaction staleness counters
-            pack($StP{$self->byte_size}, 0), # Start of free chain (blist size)
-            pack($StP{$self->byte_size}, 0), # Start of free chain (data size)
-            pack($StP{$self->byte_size}, 0), # Start of free chain (index size)
-        );
-
-        #XXX Set these less fragilely
-        $self->set_trans_loc( $header_fixed + 4 );
-        $self->set_chains_loc( $header_fixed + 4 + $bl + $STALE_SIZE * ($nt-1) );
-
-        return;
-    }
+sub _load_sector {
+    my $self = shift;
+    my ($offset) = @_;
 
-    sub _read_file_header {
-        my $self = shift;
+    # Add a catch for offset of 0 or 1
+    return if !$offset || $offset <= 1;
 
-        my $buffer = $self->storage->read_at( 0, $header_fixed );
-        return unless length($buffer);
+    unless ( exists $self->sector_cache->{ $offset } ) {
+        my $type = $self->storage->read_at( $offset, $self->SIG_SIZE );
 
-        my ($file_signature, $sig_header, $file_version, $size) = unpack(
-            'A4 A N N', $buffer
-        );
+        # XXX Don't we want to do something more proactive here? -RobK, 2008-06-19
+        return if $type eq chr(0);
 
-        unless ( $file_signature eq SIG_FILE ) {
-            $self->storage->close;
-            DBM::Deep->_throw_error( "Signature not found -- file is not a Deep DB" );
+        if ( $type eq $self->SIG_ARRAY || $type eq $self->SIG_HASH ) {
+            $self->sector_cache->{$offset} = DBM::Deep::Engine::Sector::Reference->new({
+                engine => $self,
+                type   => $type,
+                offset => $offset,
+            });
         }
-
-        unless ( $sig_header eq SIG_HEADER ) {
-            $self->storage->close;
-            DBM::Deep->_throw_error( "Pre-1.00 file version found" );
+        # XXX Don't we need key_md5 here?
+        elsif ( $type eq $self->SIG_BLIST ) {
+            $self->sector_cache->{$offset} = DBM::Deep::Engine::Sector::BucketList->new({
+                engine => $self,
+                type   => $type,
+                offset => $offset,
+            });
         }
-
-        unless ( $file_version == $this_file_version ) {
-            $self->storage->close;
-            DBM::Deep->_throw_error(
-                "Wrong file version found - " .  $file_version .
-                " - expected " . $this_file_version
-            );
+        elsif ( $type eq $self->SIG_INDEX ) {
+            $self->sector_cache->{$offset} = DBM::Deep::Engine::Sector::Index->new({
+                engine => $self,
+                type   => $type,
+                offset => $offset,
+            });
         }
-
-        my $buffer2 = $self->storage->read_at( undef, $size );
-        my @values = unpack( 'C C C C', $buffer2 );
-
-        if ( @values != 4 || grep { !defined } @values ) {
-            $self->storage->close;
-            DBM::Deep->_throw_error("Corrupted file - bad header");
+        elsif ( $type eq $self->SIG_NULL ) {
+            $self->sector_cache->{$offset} = DBM::Deep::Engine::Sector::Null->new({
+                engine => $self,
+                type   => $type,
+                offset => $offset,
+            });
         }
-
-        #XXX Add warnings if values weren't set right
-        @{$self}{qw(byte_size max_buckets data_sector_size num_txns)} = @values;
-
-        # These shenangians are to allow a 256 within a C
-        $self->{max_buckets} += 1;
-        $self->{data_sector_size} += 1;
-
-        my $bl = $self->txn_bitfield_len;
-
-        my $header_var = scalar(@values) + $bl + $STALE_SIZE * ($self->num_txns - 1) + 3 * $self->byte_size;
-        unless ( $size == $header_var ) {
-            $self->storage->close;
-            DBM::Deep->_throw_error( "Unexpected size found ($size <-> $header_var)." );
+        elsif ( $type eq $self->SIG_DATA ) {
+            $self->sector_cache->{$offset} = DBM::Deep::Engine::Sector::Scalar->new({
+                engine => $self,
+                type   => $type,
+                offset => $offset,
+            });
+        }
+        # This was deleted from under us, so just return and let the caller figure it out.
+        elsif ( $type eq $self->SIG_FREE ) {
+            return;
+        }
+        else {
+            DBM::Deep->_throw_error( "'$offset': Don't know what to do with type '$type'" );
         }
-
-        $self->set_trans_loc( $header_fixed + scalar(@values) );
-        $self->set_chains_loc( $header_fixed + scalar(@values) + $bl + $STALE_SIZE * ($self->num_txns - 1) );
-
-        return length($buffer) + length($buffer2);
-    }
-}
-
-sub _load_sector {
-    my $self = shift;
-    my ($offset) = @_;
-
-    # Add a catch for offset of 0 or 1
-    return if !$offset || $offset <= 1;
-
-    my $type = $self->storage->read_at( $offset, 1 );
-    return if $type eq chr(0);
-
-    if ( $type eq $self->SIG_ARRAY || $type eq $self->SIG_HASH ) {
-        return DBM::Deep::Engine::Sector::Reference->new({
-            engine => $self,
-            type   => $type,
-            offset => $offset,
-        });
-    }
-    # XXX Don't we need key_md5 here?
-    elsif ( $type eq $self->SIG_BLIST ) {
-        return DBM::Deep::Engine::Sector::BucketList->new({
-            engine => $self,
-            type   => $type,
-            offset => $offset,
-        });
-    }
-    elsif ( $type eq $self->SIG_INDEX ) {
-        return DBM::Deep::Engine::Sector::Index->new({
-            engine => $self,
-            type   => $type,
-            offset => $offset,
-        });
-    }
-    elsif ( $type eq $self->SIG_NULL ) {
-        return DBM::Deep::Engine::Sector::Null->new({
-            engine => $self,
-            type   => $type,
-            offset => $offset,
-        });
-    }
-    elsif ( $type eq $self->SIG_DATA ) {
-        return DBM::Deep::Engine::Sector::Scalar->new({
-            engine => $self,
-            type   => $type,
-            offset => $offset,
-        });
-    }
-    # This was deleted from under us, so just return and let the caller figure it out.
-    elsif ( $type eq $self->SIG_FREE ) {
-        return;
     }
 
-    DBM::Deep->_throw_error( "'$offset': Don't know what to do with type '$type'" );
+    return $self->sector_cache->{$offset};
 }
 
 sub _apply_digest {
@@ -877,11 +787,26 @@ sub _request_sector {
 
 ################################################################################
 
+sub sector_cache {
+    my $self = shift;
+    return $self->{sector_cache} ||= {};
+}
+
+sub clear_sector_cache {
+    my $self = shift;
+    $self->{sector_cache} = {};
+}
+
 sub dirty_sectors {
     my $self = shift;
     return $self->{dirty_sectors} ||= {};
 }
 
+sub clear_dirty_sectors {
+    my $self = shift;
+    $self->{dirty_sectors} = {};
+}
+
 sub add_dirty_sector {
     my $self = shift;
     my ($sector) = @_;
@@ -893,19 +818,17 @@ sub add_dirty_sector {
     $self->dirty_sectors->{ $sector->offset } = $sector;
 }
 
-sub clear_dirty_sectors {
-    my $self = shift;
-    $self->{dirty_sectors} = {};
-}
-
 sub flush {
     my $self = shift;
 
-    for (values %{ $self->dirty_sectors }) {
-        $_->flush;
+    my $sectors = $self->dirty_sectors;
+    for my $offset (sort { $a <=> $b } keys %{ $sectors }) {
+        $sectors->{$offset}->flush;
     }
 
     $self->clear_dirty_sectors;
+
+    $self->clear_sector_cache;
 }
 
 ################################################################################
@@ -971,9 +894,12 @@ sub clear_cache { %{$_[0]->cache} = () }
 
 sub _dump_file {
     my $self = shift;
+    $self->flush;
 
     # Read the header
-    my $spot = $self->_read_file_header();
+    my $header_sector = DBM::Deep::Engine::Sector::FileHeader->new({
+        engine => $self,
+    });
 
     my %types = (
         0 => 'B',
@@ -1018,6 +944,7 @@ sub _dump_file {
         $return .= $/;
     }
 
+    my $spot = $header_sector->size;
     SECTOR:
     while ( $spot < $self->storage->{end} ) {
         # Read each sector in order.
index 990d357..1438b5c 100644 (file)
@@ -22,6 +22,9 @@ sub new {
 
     $self->_init;
 
+    # Add new sectors to the sector cache.
+    $self->engine->sector_cache->{$self->offset} = $self;
+
     return $self;
 }
 
diff --git a/lib/DBM/Deep/Engine/Sector/FileHeader.pm b/lib/DBM/Deep/Engine/Sector/FileHeader.pm
new file mode 100644 (file)
index 0000000..a6bb82c
--- /dev/null
@@ -0,0 +1,128 @@
+package DBM::Deep::Engine::Sector::FileHeader;
+
+use 5.006;
+
+use strict;
+use warnings FATAL => 'all';
+
+use DBM::Deep::Engine::Sector;
+our @ISA = qw( DBM::Deep::Engine::Sector );
+
+my $header_fixed = length( &DBM::Deep::Engine::SIG_FILE ) + 1 + 4 + 4;
+my $this_file_version = 3;
+
+sub _init {
+    my $self = shift;
+
+    my $e = $self->engine;
+
+    # This means the file is being created.
+    # Use defined() here because the offset should always be 0. -RobK. 2008-06-20
+    unless ( $e->storage->size ) {
+        my $nt = $e->num_txns;
+        my $bl = $e->txn_bitfield_len;
+
+        my $header_var = $self->header_var_size;
+
+        $self->{offset} = $e->storage->request_space( $header_fixed + $header_var );
+        DBM::Deep::_throw_error( "Offset wasn't 0, it's '$self->{offset}'" ) unless $self->offset == 0;
+
+        $self->write( $self->offset,
+            $e->SIG_FILE
+          . $e->SIG_HEADER
+          . pack('N', $this_file_version) # At this point, we're at 9 bytes
+          . pack('N', $header_var)        # header size
+            # --- Above is $header_fixed. Below is $header_var
+          . pack('C', $e->byte_size)
+
+            # These shenanigans are to allow a 256 within a C
+          . pack('C', $e->max_buckets - 1)
+          . pack('C', $e->data_sector_size - 1)
+
+          . pack('C', $nt)
+          . pack('C' . $bl, 0 )                           # Transaction activeness bitfield
+          . pack($e->StP($DBM::Deep::Engine::STALE_SIZE).($nt-1), 0 x ($nt-1) ) # Transaction staleness counters
+          . pack($e->StP($e->byte_size), 0) # Start of free chain (blist size)
+          . pack($e->StP($e->byte_size), 0) # Start of free chain (data size)
+          . pack($e->StP($e->byte_size), 0) # Start of free chain (index size)
+        );
+
+        $e->set_trans_loc( $header_fixed + 4 );
+        $e->set_chains_loc( $header_fixed + 4 + $bl + $DBM::Deep::Engine::STALE_SIZE * ($nt-1) );
+
+        $self->{is_new} = 1;
+    }
+    else {
+        $self->{offset} = 0;
+
+        my $s = $e->storage;
+
+        my $buffer = $s->read_at( $self->offset, $header_fixed );
+        return unless length($buffer);
+
+        my ($file_signature, $sig_header, $file_version, $size) = unpack(
+            'A4 A N N', $buffer
+        );
+
+        unless ( $file_signature eq $e->SIG_FILE ) {
+            $s->close;
+            DBM::Deep->_throw_error( "Signature not found -- file is not a Deep DB" );
+        }
+
+        unless ( $sig_header eq $e->SIG_HEADER ) {
+            $s->close;
+            DBM::Deep->_throw_error( "Pre-1.00 file version found" );
+        }
+
+        unless ( $file_version == $this_file_version ) {
+            $s->close;
+            DBM::Deep->_throw_error(
+                "Wrong file version found - " .  $file_version .
+                " - expected " . $this_file_version
+            );
+        }
+
+        my $buffer2 = $s->read_at( undef, $size );
+        my @values = unpack( 'C C C C', $buffer2 );
+
+        if ( @values != 4 || grep { !defined } @values ) {
+            $s->close;
+            DBM::Deep->_throw_error("Corrupted file - bad header");
+        }
+
+        #XXX Add warnings if values weren't set right
+        @{$e}{qw(byte_size max_buckets data_sector_size num_txns)} = @values;
+
+        # These shenangians are to allow a 256 within a C
+        $e->{max_buckets} += 1;
+        $e->{data_sector_size} += 1;
+
+        my $header_var = $self->header_var_size;
+        unless ( $size == $header_var ) {
+            $s->close;
+            DBM::Deep->_throw_error( "Unexpected size found ($size <-> $header_var)." );
+        }
+
+        $e->set_trans_loc( $header_fixed + scalar(@values) );
+
+        my $bl = $e->txn_bitfield_len;
+        $e->set_chains_loc( $header_fixed + scalar(@values) + $bl + $DBM::Deep::Engine::STALE_SIZE * ($e->num_txns - 1) );
+
+        $self->{is_new} = 1;
+    }
+}
+
+sub header_var_size {
+    my $self = shift;
+    my $e = $self->engine;
+    return 1 + 1 + 1 + 1 + $e->txn_bitfield_len + $DBM::Deep::Engine::STALE_SIZE * ($e->num_txns - 1) + 3 * $e->byte_size;
+}
+
+sub size   {
+    my $self = shift;
+    $self->{size} ||= $header_fixed + $self->header_var_size;
+}
+sub is_new { $_[0]{is_new} }
+
+1;
+__END__
index 29d33dc..5586f9d 100644 (file)
@@ -236,7 +236,7 @@ sub get_bucket_list {
     }
 
     my $sector = $engine->_load_sector( $blist_loc )
-        or DBM::Deep->_throw_error( "Cannot read sector at $blist_loc in get_bucket_list()" );
+        or DBM::Deep->_throw_error( "1: Cannot read sector at $blist_loc in get_bucket_list()" );
     my $i = 0;
     my $last_sector = undef;
     while ( $sector->isa( 'DBM::Deep::Engine::Sector::Index' ) ) {
@@ -244,7 +244,7 @@ sub get_bucket_list {
         $last_sector = $sector;
         if ( $blist_loc ) {
             $sector = $engine->_load_sector( $blist_loc )
-                or DBM::Deep->_throw_error( "Cannot read sector at $blist_loc in get_bucket_list()" );
+                or DBM::Deep->_throw_error( "2: Cannot read sector at $blist_loc in get_bucket_list()" );
         }
         else {
             $sector = undef;
index b4810ff..332e849 100644 (file)
@@ -1,4 +1,4 @@
-#TODO: Convert this to a string
+#TODO: Add chaining back in.
 package DBM::Deep::Engine::Sector::Scalar;
 
 use 5.006_000;
@@ -35,45 +35,19 @@ sub _init {
         my $dlen = length $data;
 
         my $data_section = $self->size - $self->base_size - $engine->byte_size - 1;
+        my $next_offset = 0;
 
-        my $curr_offset = $self->offset;
-        my $continue = 1;
-        while ( $continue ) {
-            my $next_offset = 0;
-
-            my ($leftover, $this_len, $chunk);
-            if ( $dlen > $data_section ) {
-                $leftover = 0;
-                $this_len = $data_section;
-                $chunk = substr( $data, 0, $this_len );
-
-                $dlen -= $data_section;
-                $next_offset = $engine->_request_data_sector( $self->size );
-                $data = substr( $data, $this_len );
-            }
-            else {
-                $leftover = $data_section - $dlen;
-                $this_len = $dlen;
-                $chunk = $data;
-
-                $continue = 0;
-            }
-
-            my $string = chr(0) x $self->size;
-            substr( $string, 0, $engine->SIG_SIZE, $self->type );
-            substr( $string, $self->base_size, $engine->byte_size + 1,
-                pack( $engine->StP($engine->byte_size), $next_offset ) # Chain loc
-              . pack( $engine->StP(1), $this_len ),                    # Data length
-            );
-            substr( $string, $self->base_size + $engine->byte_size + 1, $this_len,
-                $chunk,
-            );
-
-            $engine->storage->print_at( $curr_offset, $string );
-
-            $curr_offset = $next_offset;
+        if ( $dlen > $data_section ) {
+            DBM::Deep->_throw_error( "Storage of values longer than $data_section not supported." );
         }
 
+        $self->write( 0, $self->type );
+        $self->write( $self->base_size,
+            pack( $engine->StP($engine->byte_size), $next_offset ) # Chain loc
+          . pack( $engine->StP(1), $dlen )                         # Data length
+          . $data
+        );
+
         return;
     }
 }
@@ -81,19 +55,18 @@ sub _init {
 sub data_length {
     my $self = shift;
 
-    my $buffer = $self->engine->storage->read_at(
-        $self->offset + $self->base_size + $self->engine->byte_size, 1
+    return unpack(
+        $self->engine->StP(1),
+        $self->read( $self->base_size + $self->engine->byte_size, 1 ),
     );
-
-    return unpack( $self->engine->StP(1), $buffer );
 }
 
 sub chain_loc {
     my $self = shift;
     return unpack(
         $self->engine->StP($self->engine->byte_size),
-        $self->engine->storage->read_at(
-            $self->offset + $self->base_size,
+        $self->read(
+            $self->base_size,
             $self->engine->byte_size,
         ),
     );
@@ -101,16 +74,12 @@ sub chain_loc {
 
 sub data {
     my $self = shift;
-#    my ($args) = @_;
-#    $args ||= {};
 
     my $data;
     while ( 1 ) {
         my $chain_loc = $self->chain_loc;
 
-        $data .= $self->engine->storage->read_at(
-            $self->offset + $self->base_size + $self->engine->byte_size + 1, $self->data_length,
-        );
+        $data .= $self->read( $self->base_size + $self->engine->byte_size + 1, $self->data_length );
 
         last unless $chain_loc;
 
index b4ae51d..aa1ea32 100644 (file)
@@ -87,6 +87,13 @@ sub close {
     return 1;
 }
 
+sub size {
+    my $self = shift;
+
+    return 0 unless $self->{fh};
+    return -s $self->{fh};
+}
+
 sub set_inode {
     my $self = shift;
 
index b362c0f..c1f0079 100644 (file)
@@ -30,9 +30,11 @@ my $foo = $db->{foo};
 ##
 my $max_keys = 4000;
 
+warn localtime(time) . ": before put\n";
 for ( 0 .. $max_keys ) {
     $foo->put( "hello $_" => "there " . $_ * 2 );
 }
+warn localtime(time) . ": after put\n";
 
 my $count = -1;
 for ( 0 .. $max_keys ) {
@@ -42,8 +44,10 @@ for ( 0 .. $max_keys ) {
     };
 }
 is( $count, $max_keys, "We read $count keys" );
+warn localtime(time) . ": after read\n";
 
 my @keys = sort keys %$foo;
+warn localtime(time) . ": after keys\n";
 cmp_ok( scalar(@keys), '==', $max_keys + 1, "Number of keys is correct" );
 my @control =  sort map { "hello $_" } 0 .. $max_keys;
 cmp_deeply( \@keys, \@control, "Correct keys are there" );
@@ -53,5 +57,7 @@ is( $foo->{does_not_exist}, undef, "autovivification works on large hashes" );
 ok( exists $foo->{does_not_exist}, "EXISTS works on large hashes for newly-existent keys" );
 cmp_ok( scalar(keys %$foo), '==', $max_keys + 2, "Number of keys after autovivify is correct" );
 
+warn localtime(time) . ": before clear\n";
 $db->clear;
+warn localtime(time) . ": after clear\n";
 cmp_ok( scalar(keys %$db), '==', 0, "Number of keys after clear() is correct" );
index 24b52ec..3bfc933 100644 (file)
@@ -19,10 +19,13 @@ my $db = DBM::Deep->new(
 # basic put/get/push
 ##
 $db->[0] = "elem1";
-$db->push( "elem2" );
-$db->put(2, "elem3");
-$db->store(3, "elem4");
+#$db->push( "elem2" );
+#$db->put(2, "elem3");
+#$db->store(3, "elem4");
+warn $db->_engine->_dump_file;
 $db->unshift("elem0");
+warn $db->_engine->_dump_file;
+__END__
 
 is( $db->[0], 'elem0', "Array get for shift works" );
 is( $db->[1], 'elem1', "Array get for array set works" );
index 7f6e3e7..30237ec 100644 (file)
@@ -32,7 +32,9 @@ my $x = 25;
     } qr/Storage of references of type 'GLOB' is not supported/,
     'Storage of glob refs not supported';
 
+    warn "\n1: " . $db->_engine->_dump_file;
     $db->{scalar} = $x;
+    warn "\n2: " . $db->_engine->_dump_file;
     TODO: {
         todo_skip "Refs to DBM::Deep objects aren't implemented yet", 2;
         lives_ok {
@@ -41,6 +43,8 @@ my $x = 25;
 
         is( ${$db->{selfref}}, $x, "A ref to a DBM::Deep object is ok" );
     }
+
+    warn $db->_engine->_dump_file;
 }
 
 {