Refactored Sector:: out from under Engine:: and into its own area
Rob Kinyon [Fri, 4 Dec 2009 03:33:49 +0000 (22:33 -0500)]
19 files changed:
lib/DBM/Deep.pm
lib/DBM/Deep.pod
lib/DBM/Deep/Engine/DBI.pm [new file with mode: 0644]
lib/DBM/Deep/Engine/File.pm
lib/DBM/Deep/Engine/Sector.pm
lib/DBM/Deep/Iterator.pm
lib/DBM/Deep/Null.pm
lib/DBM/Deep/SQL/Hash.pm
lib/DBM/Deep/Sector.pm [new file with mode: 0644]
lib/DBM/Deep/Sector/File.pm [new file with mode: 0644]
lib/DBM/Deep/Sector/File/BucketList.pm [moved from lib/DBM/Deep/Engine/Sector/BucketList.pm with 94% similarity]
lib/DBM/Deep/Sector/File/Data.pm [moved from lib/DBM/Deep/Engine/Sector/Data.pm with 81% similarity]
lib/DBM/Deep/Sector/File/Index.pm [moved from lib/DBM/Deep/Engine/Sector/Index.pm with 94% similarity]
lib/DBM/Deep/Sector/File/Null.pm [moved from lib/DBM/Deep/Engine/Sector/Null.pm with 93% similarity]
lib/DBM/Deep/Sector/File/Reference.pm [moved from lib/DBM/Deep/Engine/Sector/Reference.pm with 91% similarity]
lib/DBM/Deep/Sector/File/Scalar.pm [moved from lib/DBM/Deep/Engine/Sector/Scalar.pm with 92% similarity]
lib/DBM/Deep/Storage.pm [new file with mode: 0644]
lib/DBM/Deep/Storage/DBI.pm [new file with mode: 0644]
lib/DBM/Deep/Storage/File.pm

index 68693f0..3998791 100644 (file)
@@ -56,14 +56,11 @@ sub new {
     my $args = $class->_get_args( @_ );
     my $self;
     
-    ##
-    # Check for SQL storage
-    ##
     if (exists $args->{dbi}) {
         eval {
             require DBIx::Abstract;
         }; if ( $@ ) {
-            DBM::Deep->_throw_error('DBIx::Abstract not installed. You cannot use the SQL mode.');
+            __PACKAGE__->_throw_error('DBIx::Abstract not installed. You cannot use the SQL mode.');
         }
         unless (UNIVERSAL::isa($args->{dbi}, 'DBIx::Abstract')) {
             $args->{dbi} = DBIx::Abstract->connect($args->{dbi});
@@ -71,7 +68,7 @@ sub new {
 
         if (defined $args->{id}) {
             unless ($args->{id} =~ /^\d+$/ && $args->{id} > 0) {
-                DBM::Deep->_throw_error('Invalid SQL record id');
+                __PACKAGE__->_throw_error('Invalid SQL record id');
             }
             my $util = {dbi => $args->{dbi}};
             bless $util, 'DBM::Deep::SQL::Util';
@@ -155,8 +152,16 @@ sub _init {
         engine      => undef,
     }, $class;
 
-    $args->{engine} = DBM::Deep::Engine::File->new( { %{$args}, obj => $self } )
-        unless exists $args->{engine};
+    unless ( exists $args->{engine} ) {
+        my $class = exists $args->{dbi}
+            ? 'DBM::Deep::Engine::DBI'
+            : 'DBM::Deep::Engine::File';
+
+        $args->{engine} = $class->new({
+            %{$args},
+            obj => $self,
+        });
+    }
 
     # Grab the parameters we want to use
     foreach my $param ( keys %$self ) {
@@ -165,15 +170,15 @@ sub _init {
     }
 
     eval {
-      local $SIG{'__DIE__'};
+        local $SIG{'__DIE__'};
 
-      $self->lock_exclusive;
-      $self->_engine->setup( $self );
-      $self->unlock;
+        $self->lock_exclusive;
+        $self->_engine->setup( $self );
+        $self->unlock;
     }; if ( $@ ) {
-      my $e = $@;
-      eval { local $SIG{'__DIE__'}; $self->unlock; };
-      die $e;
+        my $e = $@;
+        eval { local $SIG{'__DIE__'}; $self->unlock; };
+        die $e;
     }
 
     return $self;
@@ -219,13 +224,14 @@ sub _copy_value {
         if ( $r eq 'ARRAY' ) {
             $tied = tied(@$value);
         }
-        # This assumes hash or array only. This is a bad assumption moving
-        # forward. -RobK, 2008-05-27
-        else {
+        elsif ( $r eq 'HASH' ) {
             $tied = tied(%$value);
         }
+        else {
+            __PACKAGE__->_throw_error( "Unknown type for '$value'" );
+        }
 
-        if ( eval { local $SIG{__DIE__}; $tied->isa( 'DBM::Deep' ) } ) {
+        if ( eval { local $SIG{__DIE__}; $tied->isa( __PACKAGE__ ) } ) {
             ${$spot} = $tied->_repr;
             $tied->_copy_node( ${$spot} );
         }
@@ -239,7 +245,7 @@ sub _copy_value {
         }
 
         my $c = Scalar::Util::blessed( $value );
-        if ( defined $c && !$c->isa( 'DBM::Deep') ) {
+        if ( defined $c && !$c->isa( __PACKAGE__ ) ) {
             ${$spot} = bless ${$spot}, $c
         }
     }
@@ -282,7 +288,7 @@ sub _check_legality {
     return $r if 'HASH' eq $r;
     return $r if 'ARRAY' eq $r;
 
-    DBM::Deep->_throw_error(
+    __PACKAGE__->_throw_error(
         "Storage of references of type '$r' is not supported."
     );
 }
@@ -295,11 +301,11 @@ sub import {
 
     my $type = $self->_check_legality( $struct );
     if ( !$type ) {
-        DBM::Deep->_throw_error( "Cannot import a scalar" );
+        __PACKAGE__->_throw_error( "Cannot import a scalar" );
     }
 
     if ( substr( $type, 0, 1 ) ne $self->_type ) {
-        DBM::Deep->_throw_error(
+        __PACKAGE__->_throw_error(
             "Cannot import " . ('HASH' eq $type ? 'a hash' : 'an array')
             . " into " . ('HASH' eq $type ? 'an array' : 'a hash')
         );
@@ -373,7 +379,7 @@ sub optimize {
 
     #XXX Should we use tempfile() here instead of a hard-coded name?
     my $temp_filename = $self->_engine->storage->{file} . '.tmp';
-    my $db_temp = DBM::Deep->new(
+    my $db_temp = __PACKAGE__->new(
         file => $temp_filename,
         type => $self->_type,
 
@@ -429,7 +435,7 @@ sub clone {
     ##
     my $self = shift->_get_self;
 
-    return DBM::Deep->new(
+    return __PACKAGE__->new(
         type        => $self->_type,
         base_offset => $self->_base_offset,
         staleness   => $self->_staleness,
@@ -546,7 +552,7 @@ sub STORE {
         $value = $self->_engine->storage->{filter_store_value}->( $value );
     }
 
-    $self->_engine->write_value( $self, $key, $value);
+    $self->_engine->write_value( $self, $key, $value );
 
     $self->unlock;
 
@@ -561,7 +567,7 @@ sub FETCH {
 
     $self->lock_shared;
 
-    my $result = $self->_engine->read_value( $self, $key);
+    my $result = $self->_engine->read_value( $self, $key );
 
     $self->unlock;
 
index fdd38c2..1a8f24c 100644 (file)
@@ -156,14 +156,14 @@ one of these two constants:
 
 =over 4
 
-=item * C<DBM::Deep-E<gt>TYPE_HASH>
+=item * C<<DBM::Deep->TYPE_HASH>>
 
-=item * C<DBM::Deep-E<gt>TYPE_ARRAY>.
+=item * C<<DBM::Deep->TYPE_ARRAY>>
 
 =back
 
 This only takes effect when beginning a new file. This is an optional
-parameter, and defaults to C<DBM::Deep-E<gt>TYPE_HASH>.
+parameter, and defaults to C<<DBM::Deep->TYPE_HASH>>.
 
 =item * locking
 
@@ -309,7 +309,7 @@ assign a temporary variable to C<$db->{foo}>, then pass that to each().
 As with hashes, you can treat any DBM::Deep object like a normal Perl array
 reference. This includes inserting, removing and manipulating elements,
 and the C<push()>, C<pop()>, C<shift()>, C<unshift()> and C<splice()> functions.
-The object must have first been created using type C<DBM::Deep-E<gt>TYPE_ARRAY>,
+The object must have first been created using type C<<DBM::Deep->TYPE_ARRAY>>,
 or simply be a nested array reference inside a hash. Example:
 
   my $db = DBM::Deep->new(
@@ -321,9 +321,9 @@ or simply be a nested array reference inside a hash. Example:
   push @$db, "bar", "baz";
   unshift @$db, "bah";
 
-  my $last_elem = pop @$db; # baz
-  my $first_elem = shift @$db; # bah
-  my $second_elem = $db->[1]; # bar
+  my $last_elem   = pop @$db;   # baz
+  my $first_elem  = shift @$db; # bah
+  my $second_elem = $db->[1];   # bar
 
   my $num_elements = scalar @$db;
 
@@ -728,7 +728,7 @@ DBM::Deep by default uses 32-bit file offset tags, but these can be changed
 by specifying the 'pack_size' parameter when constructing the file.
 
   DBM::Deep->new(
-      filename  => $filename,
+      file      => $filename,
       pack_size => 'large',
   );
 
@@ -736,7 +736,7 @@ This tells DBM::Deep to pack all file offsets with 8-byte (64-bit) quad words
 instead of 32-bit longs. After setting these values your DB files have a
 theoretical maximum size of 16 XB (exabytes).
 
-You can also use C<pack_size =E<gt> 'small'> in order to use 16-bit file
+You can also use C<<pack_size => 'small'>> in order to use 16-bit file
 offsets.
 
 B<Note:> Changing these values will B<NOT> work for existing database files.
@@ -946,7 +946,7 @@ the reference. Again, this would generally be considered a feature.
 
 =head2 External references and transactions
 
-If you do C<my $x = $db-E<gt>{foo};>, then start a transaction, $x will be
+If you do C<<my $x = $db->{foo};>>, then start a transaction, $x will be
 referencing the database from outside the transaction. A fix for this (and other
 issues with how external references into the database) is being looked into. This
 is the skipped set of tests in t/39_singletons.t and a related issue is the focus
diff --git a/lib/DBM/Deep/Engine/DBI.pm b/lib/DBM/Deep/Engine/DBI.pm
new file mode 100644 (file)
index 0000000..ebd5f52
--- /dev/null
@@ -0,0 +1,149 @@
+package DBM::Deep::Engine::DBI;
+
+use 5.006_000;
+
+use strict;
+use warnings FATAL => 'all';
+
+use base 'DBM::Deep::Engine';
+
+sub read_value {
+    my $self = shift;
+    my ($obj, $key) = @_;
+}
+
+sub get_classname {
+    my $self = shift;
+    my ($obj) = @_;
+}
+
+sub make_reference {
+    my $self = shift;
+    my ($obj, $old_key, $new_key) = @_;
+}
+
+sub key_exists {
+    my $self = shift;
+    my ($obj, $key) = @_;
+}
+
+sub delete_key {
+    my $self = shift;
+    my ($obj, $key) = @_;
+}
+
+sub write_value {
+    my $self = shift;
+    my ($obj, $key, $value) = @_;
+
+    my $r = Scalar::Util::reftype( $value ) || '';
+    {
+        last if $r eq '';
+        last if $r eq 'HASH';
+        last if $r eq 'ARRAY';
+
+        DBM::Deep->_throw_error(
+            "Storage of references of type '$r' is not supported."
+        );
+    }
+
+    # Load the reference entry
+    # Determine if the row was deleted under us
+    # 
+
+    my ($type);
+    if ( $r eq 'ARRAY' || $r eq 'HASH' ) {
+        my $tmpvar;
+        if ( $r eq 'ARRAY' ) {
+            $tmpvar = tied @$value;
+        } elsif ( $r eq 'HASH' ) {
+            $tmpvar = tied %$value;
+        }
+
+        if ( $tmpvar ) {
+            my $is_dbm_deep = eval { local $SIG{'__DIE__'}; $tmpvar->isa( 'DBM::Deep' ); };
+
+            unless ( $is_dbm_deep ) {
+                DBM::Deep->_throw_error( "Cannot store something that is tied." );
+            }
+
+            unless ( $tmpvar->_engine->storage == $self->storage ) {
+                DBM::Deep->_throw_error( "Cannot store values across DBM::Deep files. Please use export() instead." );
+            }
+
+            # Load $tmpvar's sector
+
+            # First, verify if we're storing the same thing to this spot. If we
+            # are, then this should be a no-op. -EJS, 2008-05-19
+            
+            # See whether or not we are storing ourselves to ourself.
+            # Write the sector as data in this reference (keyed by $key)
+            $value_sector->increment_refcount;
+
+            return 1;
+        }
+
+        $type = substr( $r, 0, 1 );
+    }
+    else {
+        if ( tied($value) ) {
+            DBM::Deep->_throw_error( "Cannot store something that is tied." );
+        }
+    }
+
+    # This code is to make sure we write all the values in the $value to the
+    # disk and to make sure all changes to $value after the assignment are
+    # reflected on disk. This may be counter-intuitive at first, but it is
+    # correct dwimmery.
+    #   NOTE - simply tying $value won't perform a STORE on each value. Hence,
+    # the copy to a temp value.
+    if ( $r eq 'ARRAY' ) {
+        my @temp = @$value;
+        tie @$value, 'DBM::Deep', {
+            base_offset => $value_sector->offset,
+            staleness   => $value_sector->staleness,
+            storage     => $self->storage,
+            engine      => $self,
+        };
+        @$value = @temp;
+        bless $value, 'DBM::Deep::Array' unless Scalar::Util::blessed( $value );
+    }
+    elsif ( $r eq 'HASH' ) {
+        my %temp = %$value;
+        tie %$value, 'DBM::Deep', {
+            base_offset => $value_sector->offset,
+            staleness   => $value_sector->staleness,
+            storage     => $self->storage,
+            engine      => $self,
+        };
+
+        %$value = %temp;
+        bless $value, 'DBM::Deep::Hash' unless Scalar::Util::blessed( $value );
+    }
+
+    return 1;
+}
+
+sub setup {
+    my $self = shift;
+    my ($obj) = @_;
+}
+
+sub begin_work {
+    my $self = shift;
+    my ($obj) = @_;
+}
+
+sub rollback {
+    my $self = shift;
+    my ($obj) = @_;
+}
+
+sub commit {
+    my $self = shift;
+    my ($obj) = @_;
+}
+
+
+1;
+__END__
index 08c8335..878f436 100644 (file)
@@ -7,18 +7,11 @@ use warnings FATAL => 'all';
 
 use base qw( DBM::Deep::Engine );
 
-# Never import symbols into our namespace. We are a class, not a library.
 use Scalar::Util ();
 
-use DBM::Deep::Storage::File ();
-
-use DBM::Deep::Engine::Sector::Data ();
-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::Null ();
+use DBM::Deep::Sector::File ();
+use DBM::Deep::Storage::File ();
 
 my $STALE_SIZE = 2;
 
@@ -128,7 +121,7 @@ sub read_value {
     my ($obj, $key) = @_;
 
     # This will be a Reference sector
-    my $sector = $self->_load_sector( $obj->_base_offset )
+    my $sector = DBM::Deep::Sector::File->load( $self, $obj->_base_offset )
         or return;
 
     if ( $sector->staleness != $obj->_staleness ) {
@@ -143,7 +136,7 @@ sub read_value {
     });
 
     unless ( $value_sector ) {
-        $value_sector = DBM::Deep::Engine::Sector::Null->new({
+        $value_sector = DBM::Deep::Sector::File::Null->new({
             engine => $self,
             data   => undef,
         });
@@ -163,7 +156,7 @@ sub get_classname {
     my ($obj) = @_;
 
     # This will be a Reference sector
-    my $sector = $self->_load_sector( $obj->_base_offset )
+    my $sector = DBM::Deep::Sector::File->load( $self, $obj->_base_offset )
         or DBM::Deep->_throw_error( "How did get_classname fail (no sector for '$obj')?!" );
 
     if ( $sector->staleness != $obj->_staleness ) {
@@ -178,7 +171,7 @@ sub make_reference {
     my ($obj, $old_key, $new_key) = @_;
 
     # This will be a Reference sector
-    my $sector = $self->_load_sector( $obj->_base_offset )
+    my $sector = DBM::Deep::Sector::File->load( $self, $obj->_base_offset )
         or DBM::Deep->_throw_error( "How did make_reference fail (no sector for '$obj')?!" );
 
     if ( $sector->staleness != $obj->_staleness ) {
@@ -193,7 +186,7 @@ sub make_reference {
     });
 
     unless ( $value_sector ) {
-        $value_sector = DBM::Deep::Engine::Sector::Null->new({
+        $value_sector = DBM::Deep::Sector::File::Null->new({
             engine => $self,
             data   => undef,
         });
@@ -205,7 +198,7 @@ sub make_reference {
         });
     }
 
-    if ( $value_sector->isa( 'DBM::Deep::Engine::Sector::Reference' ) ) {
+    if ( $value_sector->isa( 'DBM::Deep::Sector::File::Reference' ) ) {
         $sector->write_data({
             key     => $new_key,
             key_md5 => $self->_apply_digest( $new_key ),
@@ -229,7 +222,7 @@ sub key_exists {
     my ($obj, $key) = @_;
 
     # This will be a Reference sector
-    my $sector = $self->_load_sector( $obj->_base_offset )
+    my $sector = DBM::Deep::Sector::File->load( $self, $obj->_base_offset )
         or return '';
 
     if ( $sector->staleness != $obj->_staleness ) {
@@ -249,7 +242,7 @@ sub delete_key {
     my $self = shift;
     my ($obj, $key) = @_;
 
-    my $sector = $self->_load_sector( $obj->_base_offset )
+    my $sector = DBM::Deep::Sector::File->load( $self, $obj->_base_offset )
         or return;
 
     if ( $sector->staleness != $obj->_staleness ) {
@@ -278,7 +271,7 @@ sub write_value {
     }
 
     # This will be a Reference sector
-    my $sector = $self->_load_sector( $obj->_base_offset )
+    my $sector = DBM::Deep::Sector::File->load( $self, $obj->_base_offset )
         or DBM::Deep->_throw_error( "Cannot write to a deleted spot in DBM::Deep." );
 
     if ( $sector->staleness != $obj->_staleness ) {
@@ -287,7 +280,7 @@ sub write_value {
 
     my ($class, $type);
     if ( !defined $value ) {
-        $class = 'DBM::Deep::Engine::Sector::Null';
+        $class = 'DBM::Deep::Sector::File::Null';
     }
     elsif ( $r eq 'ARRAY' || $r eq 'HASH' ) {
         my $tmpvar;
@@ -308,8 +301,8 @@ sub write_value {
                 DBM::Deep->_throw_error( "Cannot store values across DBM::Deep files. Please use export() instead." );
             }
 
-            # First, verify if we're storing the same thing to this spot. If we are, then
-            # this should be a no-op. -EJS, 2008-05-19
+            # First, verify if we're storing the same thing to this spot. If we
+            # are, then this should be a no-op. -EJS, 2008-05-19
             my $loc = $sector->get_data_location_for({
                 key_md5 => $self->_apply_digest( $key ),
                 allow_head => 1,
@@ -320,7 +313,7 @@ sub write_value {
             }
 
             #XXX Can this use $loc?
-            my $value_sector = $self->_load_sector( $tmpvar->_base_offset );
+            my $value_sector = DBM::Deep::Sector::File->load( $self, $tmpvar->_base_offset );
             $sector->write_data({
                 key     => $key,
                 key_md5 => $self->_apply_digest( $key ),
@@ -331,18 +324,18 @@ sub write_value {
             return 1;
         }
 
-        $class = 'DBM::Deep::Engine::Sector::Reference';
+        $class = 'DBM::Deep::Sector::File::Reference';
         $type = substr( $r, 0, 1 );
     }
     else {
         if ( tied($value) ) {
             DBM::Deep->_throw_error( "Cannot store something that is tied." );
         }
-        $class = 'DBM::Deep::Engine::Sector::Scalar';
+        $class = 'DBM::Deep::Sector::File::Scalar';
     }
 
-    # Create this after loading the reference sector in case something bad happens.
-    # This way, we won't allocate value sector(s) needlessly.
+    # Create this after loading the reference sector in case something bad
+    # happens. This way, we won't allocate value sector(s) needlessly.
     my $value_sector = $class->new({
         engine => $self,
         data   => $value,
@@ -355,11 +348,12 @@ sub write_value {
         value   => $value_sector,
     });
 
-    # This code is to make sure we write all the values in the $value to the disk
-    # and to make sure all changes to $value after the assignment are reflected
-    # on disk. This may be counter-intuitive at first, but it is correct dwimmery.
-    #   NOTE - simply tying $value won't perform a STORE on each value. Hence, the
-    # copy to a temp value.
+    # This code is to make sure we write all the values in the $value to the
+    # disk and to make sure all changes to $value after the assignment are
+    # reflected on disk. This may be counter-intuitive at first, but it is
+    # correct dwimmery.
+    #   NOTE - simply tying $value won't perform a STORE on each value. Hence,
+    # the copy to a temp value.
     if ( $r eq 'ARRAY' ) {
         my @temp = @$value;
         tie @$value, 'DBM::Deep', {
@@ -400,7 +394,7 @@ sub setup {
             $self->_write_file_header;
 
             # 1) Create Array/Hash entry
-            my $initial_reference = DBM::Deep::Engine::Sector::Reference->new({
+            my $initial_reference = DBM::Deep::Sector::File::Reference->new({
                 engine => $self,
                 type   => $obj->_type,
             });
@@ -412,7 +406,7 @@ sub setup {
         # Reading from an existing file
         else {
             $obj->{base_offset} = $bytes_read;
-            my $initial_reference = DBM::Deep::Engine::Sector::Reference->new({
+            my $initial_reference = DBM::Deep::Sector::File::Reference->new({
                 engine => $self,
                 offset => $obj->_base_offset,
             });
@@ -486,7 +480,7 @@ sub rollback {
         $self->storage->print_at( $read_loc, pack( $StP{$self->byte_size}, 0 ) );
 
         if ( $data_loc > 1 ) {
-            $self->_load_sector( $data_loc )->free;
+            DBM::Deep::Sector::File->load( $self, $data_loc )->free;
         }
     }
 
@@ -530,7 +524,7 @@ sub commit {
         );
 
         if ( $head_loc > 1 ) {
-            $self->_load_sector( $head_loc )->free;
+            DBM::Deep::Sector::File->load( $self, $head_loc )->free;
         }
     }
 
@@ -829,67 +823,6 @@ settings that set how the file is interpreted.
     }
 }
 
-=head2 _load_sector( $offset )
-
-This will instantiate and return the sector object that represents the data found
-at $offset.
-
-=cut
-
-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'" );
-}
-
 =head2 _apply_digest( @stuff )
 
 This will apply the digest methd (default to Digest::MD5::md5) to the arguments
@@ -1108,8 +1041,8 @@ sub _dump_file {
 
     my %sizes = (
         'D' => $self->data_sector_size,
-        'B' => DBM::Deep::Engine::Sector::BucketList->new({engine=>$self,offset=>1})->size,
-        'I' => DBM::Deep::Engine::Sector::Index->new({engine=>$self,offset=>1})->size,
+        'B' => DBM::Deep::Sector::File::BucketList->new({engine=>$self,offset=>1})->size,
+        'I' => DBM::Deep::Sector::File::Index->new({engine=>$self,offset=>1})->size,
     );
 
     my $return = "";
@@ -1143,7 +1076,7 @@ sub _dump_file {
     SECTOR:
     while ( $spot < $self->storage->{end} ) {
         # Read each sector in order.
-        my $sector = $self->_load_sector( $spot );
+        my $sector = DBM::Deep::Sector::File->load( $self, $spot );
         if ( !$sector ) {
             # Find it in the free-sectors that were found already
             foreach my $type ( keys %sectors ) {
index d99e9ea..9bbf29c 100644 (file)
@@ -5,51 +5,33 @@ use 5.006_000;
 use strict;
 use warnings FATAL => 'all';
 
-my $STALE_SIZE = 2;
-
-# Please refer to the pack() documentation for further information
-my %StP = (
-    1 => 'C', # Unsigned char value (no order needed as it's just one byte)
-    2 => 'n', # Unsigned short in "network" (big-endian) order
-    4 => 'N', # Unsigned long in "network" (big-endian) order
-    8 => 'Q', # Usigned quad (no order specified, presumably machine-dependent)
-);
-
-sub new {
-    my $self = bless $_[1], $_[0];
-    Scalar::Util::weaken( $self->{engine} );
-    $self->_init;
-    return $self;
-}
-
-#sub _init {}
-#sub clone { DBM::Deep->_throw_error( "Must be implemented in the child class" ); }
-
-sub engine { $_[0]{engine} }
-sub offset { $_[0]{offset} }
-sub type   { $_[0]{type} }
-
-sub base_size {
-   my $self = shift;
-   return $self->engine->SIG_SIZE + $STALE_SIZE;
-}
-
-sub free {
-    my $self = shift;
-
-    my $e = $self->engine;
-
-    $e->storage->print_at( $self->offset, $e->SIG_FREE );
-    # Skip staleness counter
-    $e->storage->print_at( $self->offset + $self->base_size,
-        chr(0) x ($self->size - $self->base_size),
-    );
-
-    my $free_meth = $self->free_meth;
-    $e->$free_meth( $self->offset, $self->size );
-
-    return;
-}
-
 1;
 __END__
+
+new({
+    engine =>
+    type   =>
+    offset =>
+})
+    _init( $args )
+staleness
+get_data_for({
+    key_md5    =>
+    allow_head =>
+})
+get_data_location_for({
+    key_md5    =>
+    allow_head =>
+})
+write_data({
+    key     =>
+    key_md5 =>
+    value   => $value_sector,
+})
+size
+get_classname
+delete_key({
+    key_md5    =>
+    allow_head =>
+})
+get_refcount
index 4fd10e3..7c28b6f 100644 (file)
@@ -78,16 +78,16 @@ sub get_sector_iterator {
     my $self = shift;
     my ($loc) = @_;
 
-    my $sector = $self->{engine}->_load_sector( $loc )
+    my $sector = DBM::Deep::Sector::File->load( $self->{engine}, $loc )
         or return;
 
-    if ( $sector->isa( 'DBM::Deep::Engine::Sector::Index' ) ) {
+    if ( $sector->isa( 'DBM::Deep::Sector::File::Index' ) ) {
         return DBM::Deep::Iterator::Index->new({
             iterator => $self,
             sector   => $sector,
         });
     }
-    elsif ( $sector->isa( 'DBM::Deep::Engine::Sector::BucketList' ) ) {
+    elsif ( $sector->isa( 'DBM::Deep::Sector::File::BucketList' ) ) {
         return DBM::Deep::Iterator::BucketList->new({
             iterator => $self,
             sector   => $sector,
@@ -110,7 +110,7 @@ sub get_next_key {
 
     unless ( @$crumbs ) {
         # This will be a Reference sector
-        my $sector = $e->_load_sector( $self->{base_offset} )
+        my $sector = DBM::Deep::Sector::File->load( $e, $self->{base_offset} )
             # If no sector is found, this must have been deleted from under us.
             or return;
 
index feb79ac..df6dd05 100644 (file)
@@ -1,5 +1,3 @@
-# This was copied from MARCEL's Class::Null. However, I couldn't use it because
-# I need an undef value, not an implementation of the Null Class pattern.
 package DBM::Deep::Null;
 
 use 5.006_000;
index ee3d59e..7eddf0f 100644 (file)
@@ -394,31 +394,25 @@ sub STORE
        my $obj = $tobj->_get_self();
        my $vt;
        $val = '' unless (defined $val);
-       if (ref $val)
-       {
+       if (ref $val) {
                my $done = 0;
-               unless ($obj->{'serialize'})
-               {
-                       if ($val =~ /HASH/)
-                       {
+               unless ($obj->{'serialize'}) {
+                       if ($val =~ /HASH/) {
                                my $id = $obj->_create('hash');
                                my $ta = $obj->_tiehash($id);
                                $dval = $ta;
-                               foreach my $k (keys %$val)
-                               {
+                               foreach my $k (keys %$val) {
                                        $ta->{$k} = $val->{$k};
                                }
                                $vt = 'hash';
                                $val = $id;
                                $done = 1;
                        }
-                       elsif ($val =~ /ARRAY/)
-                       {
+                       elsif ($val =~ /ARRAY/) {
                                my $id = $obj->_create('array');
                                my $ta = $obj->_tiearray($id);
                                $dval = $ta;
-                               foreach my $i (0..$#{$val})
-                               {
+                               foreach my $i (0..$#{$val}) {
                                        $ta->[$i] = $val->[$i];
                                }
                                $vt = 'array';
@@ -426,8 +420,7 @@ sub STORE
                                $done = 1;
                        }
                }
-               unless ($done)
-               {
+               unless ($done) {
                        my $data = nfreeze($val);
                        $val = $obj->_create('value_data', {
                                'data' => $data,
@@ -435,15 +428,13 @@ sub STORE
                        $vt = 'data';
                }
        }
-       elsif (length($val) > 255)
-       {
+       elsif (length($val) > 255) {
                $val = $obj->_create('value_data', {
                        'data' => $val,
                });
                $vt = 'text';
        }
-       else
-       {
+       else {
                $vt = 'value';
        }
        my $hcode = md5_base64($k);
@@ -456,10 +447,8 @@ sub STORE
                },
        );
        my $create = 1;
-       if (scalar @$c)
-       {
-               if ($c->[0]->[0] eq 'value')
-               {
+       if (scalar @$c) {
+               if ($c->[0]->[0] eq 'value') {
                        $create = 0;
                        $obj->_update(
                                'table' => 'rec_hash_item',
@@ -472,23 +461,19 @@ sub STORE
                                },
                        );
                }
-               else
-               {
+               else {
                        $obj->_delete($k);
                }
        }
-       if ($create)
-       {
+       if ($create) {
                my $kt;
-               if (length($k) > 255)
-               {
+               if (length($k) > 255) {
                        $k = $obj->_create('value_text', {
                                'data' => $k,
                        });
                        $kt = 'text';
                }
-               else
-               {
+               else {
                        $kt = 'value';
                }
                $obj->_create('hash_item', {
diff --git a/lib/DBM/Deep/Sector.pm b/lib/DBM/Deep/Sector.pm
new file mode 100644 (file)
index 0000000..8174f1a
--- /dev/null
@@ -0,0 +1,27 @@
+package DBM::Deep::Sector;
+
+use 5.006_000;
+
+use strict;
+use warnings FATAL => 'all';
+
+use Scalar::Util ();
+
+sub new {
+    my $self = bless $_[1], $_[0];
+    Scalar::Util::weaken( $self->{engine} );
+    $self->_init;
+    return $self;
+}
+
+sub _init {}
+sub clone { die "clone must be implemented in a child class" }
+
+sub engine { $_[0]{engine} }
+sub offset { $_[0]{offset} }
+sub type   { $_[0]{type}   }
+
+sub load { die "load must be implemented in a child class" }
+
+1;
+__END__
diff --git a/lib/DBM/Deep/Sector/File.pm b/lib/DBM/Deep/Sector/File.pm
new file mode 100644 (file)
index 0000000..21f6273
--- /dev/null
@@ -0,0 +1,104 @@
+package DBM::Deep::Sector::File;
+
+use 5.006_000;
+
+use strict;
+use warnings FATAL => 'all';
+
+use base qw( DBM::Deep::Sector );
+
+use DBM::Deep::Sector::File::Reference;
+use DBM::Deep::Sector::File::BucketList;
+use DBM::Deep::Sector::File::Index;
+use DBM::Deep::Sector::File::Null;
+use DBM::Deep::Sector::File::Scalar;
+
+my $STALE_SIZE = 2;
+
+sub base_size {
+    my $self = shift;
+    return $self->engine->SIG_SIZE + $STALE_SIZE;
+}
+
+sub free_meth { die "free_meth must be implemented in a child class" }
+
+sub free {
+    my $self = shift;
+
+    my $e = $self->engine;
+
+    $e->storage->print_at( $self->offset, $e->SIG_FREE );
+    # Skip staleness counter
+    $e->storage->print_at( $self->offset + $self->base_size,
+        chr(0) x ($self->size - $self->base_size),
+    );
+
+    my $free_meth = $self->free_meth;
+    $e->$free_meth( $self->offset, $self->size );
+
+    return;
+}
+
+=head2 load( $offset )
+
+This will instantiate and return the sector object that represents the data
+found at $offset.
+
+=cut
+
+sub load {
+    my $self = shift;
+    my ($engine, $offset) = @_;
+
+    # Add a catch for offset of 0 or 1
+    return if !$offset || $offset <= 1;
+
+    my $type = $engine->storage->read_at( $offset, 1 );
+    return if $type eq chr(0);
+
+    if ( $type eq $engine->SIG_ARRAY || $type eq $engine->SIG_HASH ) {
+        return DBM::Deep::Sector::File::Reference->new({
+            engine => $engine,
+            type   => $type,
+            offset => $offset,
+        });
+    }
+    # XXX Don't we need key_md5 here?
+    elsif ( $type eq $engine->SIG_BLIST ) {
+        return DBM::Deep::Sector::File::BucketList->new({
+            engine => $engine,
+            type   => $type,
+            offset => $offset,
+        });
+    }
+    elsif ( $type eq $engine->SIG_INDEX ) {
+        return DBM::Deep::Sector::File::Index->new({
+            engine => $engine,
+            type   => $type,
+            offset => $offset,
+        });
+    }
+    elsif ( $type eq $engine->SIG_NULL ) {
+        return DBM::Deep::Sector::File::Null->new({
+            engine => $engine,
+            type   => $type,
+            offset => $offset,
+        });
+    }
+    elsif ( $type eq $engine->SIG_DATA ) {
+        return DBM::Deep::Sector::File::Scalar->new({
+            engine => $engine,
+            type   => $type,
+            offset => $offset,
+        });
+    }
+    # This was deleted from under us, so just return and let the caller figure it out.
+    elsif ( $type eq $engine->SIG_FREE ) {
+        return;
+    }
+
+    DBM::Deep->_throw_error( "'$offset': Don't know what to do with type '$type'" );
+}
+
+1;
+__END__
similarity index 94%
rename from lib/DBM/Deep/Engine/Sector/BucketList.pm
rename to lib/DBM/Deep/Sector/File/BucketList.pm
index 65887db..349fa3a 100644 (file)
@@ -1,11 +1,11 @@
-package DBM::Deep::Engine::Sector::BucketList;
+package DBM::Deep::Sector::File::BucketList;
 
 use 5.006_000;
 
 use strict;
 use warnings FATAL => 'all';
 
-use base qw( DBM::Deep::Engine::Sector );
+use base qw( DBM::Deep::Sector::File );
 
 my $STALE_SIZE = 2;
 
@@ -68,7 +68,7 @@ sub free {
 
         # Delete the keysector
         my $l = unpack( $StP{$e->byte_size}, substr( $rest, $e->hash_size, $e->byte_size ) );
-        my $s = $e->_load_sector( $l ); $s->free if $s;
+        my $s = DBM::Deep::Sector::File->load( $e, $l ); $s->free if $s;
 
         # Delete the HEAD sector
         $l = unpack( $StP{$e->byte_size},
@@ -77,7 +77,7 @@ sub free {
                 $e->byte_size,
             ),
         );
-        $s = $e->_load_sector( $l ); $s->free if $s;
+        $s = DBM::Deep::Sector::File->load( $e, $l ); $s->free if $s;
 
         foreach my $txn ( 0 .. $e->num_txns - 2 ) {
             my $l = unpack( $StP{$e->byte_size},
@@ -86,7 +86,7 @@ sub free {
                     $e->byte_size,
                 ),
             );
-            my $s = $e->_load_sector( $l ); $s->free if $s;
+            my $s = DBM::Deep::Sector::File->load( $e, $l ); $s->free if $s;
         }
     }
 
@@ -198,7 +198,7 @@ sub write_md5 {
     $engine->add_entry( $args->{trans_id}, $spot );
 
     unless ($self->{found}) {
-        my $key_sector = DBM::Deep::Engine::Sector::Scalar->new({
+        my $key_sector = DBM::Deep::Sector::File::Scalar->new({
             engine => $engine,
             data   => $args->{key},
         });
@@ -283,7 +283,7 @@ sub delete_md5 {
 
     $key_sector->free;
 
-    my $data_sector = $self->engine->_load_sector( $location );
+    my $data_sector = DBM::Deep::Sector::File->load( $self->engine, $location );
     my $data = $data_sector->data({ export => 1 });
     $data_sector->free;
 
@@ -350,7 +350,7 @@ sub get_data_for {
     my $location = $self->get_data_location_for({
         allow_head => $args->{allow_head},
     });
-    return $self->engine->_load_sector( $location );
+    return DBM::Deep::Sector::File->load( $self->engine, $location );
 }
 
 sub get_key_for {
@@ -369,7 +369,7 @@ sub get_key_for {
     $location = unpack( $StP{$self->engine->byte_size}, $location );
     DBM::Deep->_throw_error( "get_key_for: No location?" ) unless $location;
 
-    return $self->engine->_load_sector( $location );
+    return DBM::Deep::Sector::File->load( $self->engine, $location );
 }
 
 1;
similarity index 81%
rename from lib/DBM/Deep/Engine/Sector/Data.pm
rename to lib/DBM/Deep/Sector/File/Data.pm
index 1e1f7e2..fa9b43f 100644 (file)
@@ -1,11 +1,11 @@
-package DBM::Deep::Engine::Sector::Data;
+package DBM::Deep::Sector::File::Data;
 
 use 5.006_000;
 
 use strict;
 use warnings FATAL => 'all';
 
-use base qw( DBM::Deep::Engine::Sector );
+use base qw( DBM::Deep::Sector::File );
 
 # This is in bytes
 sub size { $_[0]{engine}->data_sector_size }
similarity index 94%
rename from lib/DBM/Deep/Engine/Sector/Index.pm
rename to lib/DBM/Deep/Sector/File/Index.pm
index a985bd8..de0fa73 100644 (file)
@@ -1,6 +1,6 @@
-package DBM::Deep::Engine::Sector::Index;
+package DBM::Deep::Sector::File::Index;
 
-use base qw( DBM::Deep::Engine::Sector );
+use base qw( DBM::Deep::Sector::File );
 
 my $STALE_SIZE = 2;
 
@@ -49,7 +49,7 @@ sub free {
 
     for my $i ( 0 .. $e->hash_chars - 1 ) {
         my $l = $self->get_entry( $i ) or next;
-        $e->_load_sector( $l )->free;
+        DBM::Deep::Sector::File->load( $e, $l )->free;
     }
 
     $self->SUPER::free();
similarity index 93%
rename from lib/DBM/Deep/Engine/Sector/Null.pm
rename to lib/DBM/Deep/Sector/File/Null.pm
index c755bc8..22632b1 100644 (file)
@@ -1,11 +1,11 @@
-package DBM::Deep::Engine::Sector::Null;
+package DBM::Deep::Sector::File::Null;
 
 use 5.006_000;
 
 use strict;
 use warnings FATAL => 'all';
 
-use base qw( DBM::Deep::Engine::Sector::Data );
+use base qw( DBM::Deep::Sector::File::Data );
 
 my $STALE_SIZE = 2;
 
similarity index 91%
rename from lib/DBM/Deep/Engine/Sector/Reference.pm
rename to lib/DBM/Deep/Sector/File/Reference.pm
index ff40670..e86bf23 100644 (file)
@@ -1,11 +1,11 @@
-package DBM::Deep::Engine::Sector::Reference;
+package DBM::Deep::Sector::File::Reference;
 
 use 5.006_000;
 
 use strict;
 use warnings FATAL => 'all';
 
-use base qw( DBM::Deep::Engine::Sector::Data );
+use base qw( DBM::Deep::Sector::File::Data );
 
 my $STALE_SIZE = 2;
 
@@ -28,7 +28,7 @@ sub _init {
 
         my $class_offset = 0;
         if ( defined $classname ) {
-            my $class_sector = DBM::Deep::Engine::Sector::Scalar->new({
+            my $class_sector = DBM::Deep::Sector::File::Scalar->new({
                 engine => $e,
                 data   => $classname,
             });
@@ -93,7 +93,7 @@ sub get_data_for {
     my $location = $self->get_data_location_for( $args )
         or return;
 
-    return $self->engine->_load_sector( $location );
+    return DBM::Deep::Sector::File->load( $self->engine, $location );
 }
 
 sub write_data {
@@ -175,7 +175,7 @@ sub delete_key {
     my $location = $blist->get_data_location_for({
         allow_head => 0,
     });
-    my $old_value = $location && $self->engine->_load_sector( $location );
+    my $old_value = $location && DBM::Deep::Sector::File->load( $self->engine, $location );
 
     my @trans_ids = $self->engine->get_running_txn_ids;
 
@@ -234,7 +234,7 @@ sub get_bucket_list {
     unless ( $blist_loc ) {
         return unless $args->{create};
 
-        my $blist = DBM::Deep::Engine::Sector::BucketList->new({
+        my $blist = DBM::Deep::Sector::File::BucketList->new({
             engine  => $engine,
             key_md5 => $args->{key_md5},
         });
@@ -246,15 +246,15 @@ sub get_bucket_list {
         return $blist;
     }
 
-    my $sector = $engine->_load_sector( $blist_loc )
+    my $sector = DBM::Deep::Sector::File->load( $engine, $blist_loc )
         or DBM::Deep->_throw_error( "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' ) ) {
+    while ( $sector->isa( 'DBM::Deep::Sector::File::Index' ) ) {
         $blist_loc = $sector->get_entry( ord( substr( $args->{key_md5}, $i++, 1 ) ) );
         $last_sector = $sector;
         if ( $blist_loc ) {
-            $sector = $engine->_load_sector( $blist_loc )
+            $sector = DBM::Deep::Sector::File->load( $engine, $blist_loc )
                 or DBM::Deep->_throw_error( "Cannot read sector at $blist_loc in get_bucket_list()" );
         }
         else {
@@ -270,7 +270,7 @@ sub get_bucket_list {
         DBM::Deep->_throw_error( "No last_sector when attempting to build a new entry" )
             unless $last_sector;
 
-        my $blist = DBM::Deep::Engine::Sector::BucketList->new({
+        my $blist = DBM::Deep::Sector::File::BucketList->new({
             engine  => $engine,
             key_md5 => $args->{key_md5},
         });
@@ -289,7 +289,7 @@ sub get_bucket_list {
     if ( !$sector->has_md5 && $args->{create} && $sector->{idx} == -1 ) {{
         my $redo;
 
-        my $new_index = DBM::Deep::Engine::Sector::Index->new({
+        my $new_index = DBM::Deep::Sector::File::Index->new({
             engine => $engine,
         });
 
@@ -301,7 +301,7 @@ sub get_bucket_list {
 
             # XXX This is inefficient
             my $blist = $blist_cache{$idx}
-                ||= DBM::Deep::Engine::Sector::BucketList->new({
+                ||= DBM::Deep::Sector::File::BucketList->new({
                     engine => $engine,
                 });
 
@@ -322,7 +322,7 @@ sub get_bucket_list {
                 ++$i, ++$redo;
             } else {
                 my $blist = $blist_cache{$idx}
-                    ||= DBM::Deep::Engine::Sector::BucketList->new({
+                    ||= DBM::Deep::Sector::File::BucketList->new({
                         engine => $engine,
                     });
     
@@ -333,14 +333,14 @@ sub get_bucket_list {
                 $blist->write_md5({
                     key     => $args->{key},
                     key_md5 => $args->{key_md5},
-                    value   => DBM::Deep::Engine::Sector::Null->new({
+                    value   => DBM::Deep::Sector::File::Null->new({
                         engine => $engine,
                         data   => undef,
                     }),
                 });
             }
 #            my $blist = $blist_cache{$idx}
-#                ||= DBM::Deep::Engine::Sector::BucketList->new({
+#                ||= DBM::Deep::Sector::File::BucketList->new({
 #                    engine => $engine,
 #                });
 #
@@ -351,7 +351,7 @@ sub get_bucket_list {
 #            $blist->write_md5({
 #                key     => $args->{key},
 #                key_md5 => $args->{key_md5},
-#                value   => DBM::Deep::Engine::Sector::Null->new({
+#                value   => DBM::Deep::Sector::File::Null->new({
 #                    engine => $engine,
 #                    data   => undef,
 #                }),
@@ -404,7 +404,7 @@ sub get_classname {
 
     return unless $class_offset;
 
-    return $self->engine->_load_sector( $class_offset )->data;
+    return DBM::Deep::Sector::File->load( $self->engine, $class_offset )->data;
 }
 
 sub data {
@@ -460,10 +460,10 @@ sub free {
     delete $self->engine->cache->{ $self->offset };
 
     my $blist_loc = $self->get_blist_loc;
-    $self->engine->_load_sector( $blist_loc )->free if $blist_loc;
+    DBM::Deep::Sector::File->load( $self->engine, $blist_loc )->free if $blist_loc;
 
     my $class_loc = $self->get_class_offset;
-    $self->engine->_load_sector( $class_loc )->free if $class_loc;
+    DBM::Deep::Sector::File->load( $self->engine, $class_loc )->free if $class_loc;
 
     $self->SUPER::free();
 }
similarity index 92%
rename from lib/DBM/Deep/Engine/Sector/Scalar.pm
rename to lib/DBM/Deep/Sector/File/Scalar.pm
index 7dfb1b9..bfbae22 100644 (file)
@@ -1,11 +1,11 @@
-package DBM::Deep::Engine::Sector::Scalar;
+package DBM::Deep::Sector::File::Scalar;
 
 use 5.006_000;
 
 use strict;
 use warnings FATAL => 'all';
 
-use base qw( DBM::Deep::Engine::Sector::Data );
+use base qw( DBM::Deep::Sector::File::Data );
 
 my $STALE_SIZE = 2;
 
@@ -25,7 +25,7 @@ sub free {
     $self->SUPER::free();
 
     if ( $chain_loc ) {
-        $self->engine->_load_sector( $chain_loc )->free;
+        DBM::Deep::Sector::File->load( $self->engine, $chain_loc )->free;
     }
 
     return;
@@ -120,7 +120,7 @@ sub data {
 
         last unless $chain_loc;
 
-        $self = $self->engine->_load_sector( $chain_loc );
+        $self = DBM::Deep::Sector::File->load( $self->engine, $chain_loc );
     }
 
     return $data;
diff --git a/lib/DBM/Deep/Storage.pm b/lib/DBM/Deep/Storage.pm
new file mode 100644 (file)
index 0000000..78f8217
--- /dev/null
@@ -0,0 +1,66 @@
+package DBM::Deep::Storage;
+
+use 5.006_000;
+
+use strict;
+use warnings FATAL => 'all';
+
+=head2 flush()
+
+This flushes the filehandle. This takes no parameters and returns nothing.
+
+=cut
+
+sub flush { die "flush must be implemented in a child class" }
+
+=head2 is_writable()
+
+This takes no parameters. It returns a boolean saying if this filehandle is
+writable.
+
+Taken from L<http://www.perlmonks.org/?node_id=691054/>.
+
+=cut
+
+sub is_writable { die "is_writable must be implemented in a child class" }
+
+=head1 LOCKING
+
+This is where the actual locking of the storage medium is performed.
+Nested locking is supported.
+
+B<NOTE>: It is unclear what will happen if a read lock is taken, then
+a write lock is taken as a nested lock, then the write lock is released.
+
+Currently, the only locking method supported is flock(1). This is a
+whole-file lock. In the future, more granular locking may be supported.
+The API for that is unclear right now.
+
+The following methods manage the locking status. In all cases, they take
+a L<DBM::Deep/> object and returns nothing.
+
+=over 4
+
+=item * lock_exclusive( $obj )
+
+Take a lock usable for writing.
+
+=item * lock_shared( $obj )
+
+Take a lock usable for reading.
+
+=item * unlock( $obj )
+
+Releases the last lock taken. If this is the outermost lock, then the
+object is actually unlocked.
+
+=back
+
+=cut
+
+sub lock_exclusive { die "lock_exclusive must be implemented in a child class" }
+sub lock_shared { die "lock_shared must be implemented in a child class" }
+sub unlock { die "unlock must be implemented in a child class" }
+
+1;
+__END__
diff --git a/lib/DBM/Deep/Storage/DBI.pm b/lib/DBM/Deep/Storage/DBI.pm
new file mode 100644 (file)
index 0000000..b2c88a6
--- /dev/null
@@ -0,0 +1,28 @@
+package DBM::Deep::Storage::DBI;
+
+use 5.006_000;
+
+use strict;
+use warnings FATAL => 'all';
+
+use base 'DBM::Deep::Storage';
+
+sub is_writable {
+    my $self = shift;
+    return 1;
+}
+
+sub lock_exclusive {
+    my $self = shift;
+}
+
+sub lock_shared {
+    my $self = shift;
+}
+
+sub unlock {
+    my $self = shift;
+}
+
+1;
+__END__
index 2d03880..20c90a3 100644 (file)
@@ -9,6 +9,8 @@ use Fcntl qw( :DEFAULT :flock :seek );
 
 use constant DEBUG => 0;
 
+use base 'DBM::Deep::Storage';
+
 =head1 NAME
 
 DBM::Deep::Storage::File
@@ -263,44 +265,6 @@ sub request_space {
     return $loc;
 }
 
-=head2 flush()
-
-This flushes the filehandle. This takes no parameters and returns nothing.
-
-=cut
-
-sub flush {
-    my $self = shift;
-
-    # Flush the filehandle
-    my $old_fh = select $self->{fh};
-    my $old_af = $|; $| = 1; $| = $old_af;
-    select $old_fh;
-
-    return 1;
-}
-
-=head2 is_writable()
-
-This takes no parameters. It returns a boolean saying if this filehandle is
-writable.
-
-Taken from L<http://www.perlmonks.org/?node_id=691054/>.
-
-=cut
-
-sub is_writable {
-    my $self = shift;
-
-    my $fh = $self->{fh};
-    return unless defined $fh;
-    return unless defined fileno $fh;
-    local $\ = '';  # just in case
-    no warnings;    # temporarily disable warnings
-    local $^W;      # temporarily disable warnings
-    return print $fh '';
-}
-
 =head2 copy_stats( $target_filename )
 
 This will take the stats for the current filehandle and apply them to
@@ -328,39 +292,28 @@ sub copy_stats {
     chmod( $perms, $temp_filename );
 }
 
-=head1 LOCKING
-
-This is where the actual locking of the storage medium is performed.
-Nested locking is supported.
-
-B<NOTE>: It is unclear what will happen if a read lock is taken, then
-a write lock is taken as a nested lock, then the write lock is released.
-
-Currently, the only locking method supported is flock(1). This is a
-whole-file lock. In the future, more granular locking may be supported.
-The API for that is unclear right now.
-
-The following methods manage the locking status. In all cases, they take
-a L<DBM::Deep/> object and returns nothing.
-
-=over 4
-
-=item * lock_exclusive( $obj )
-
-Take a lock usable for writing.
-
-=item * lock_shared( $obj )
-
-Take a lock usable for reading.
+sub flush {
+    my $self = shift;
 
-=item * unlock( $obj )
+    # Flush the filehandle
+    my $old_fh = select $self->{fh};
+    my $old_af = $|; $| = 1; $| = $old_af;
+    select $old_fh;
 
-Releases the last lock taken. If this is the outermost lock, then the
-object is actually unlocked.
+    return 1;
+}
 
-=back
+sub is_writable {
+    my $self = shift;
 
-=cut
+    my $fh = $self->{fh};
+    return unless defined $fh;
+    return unless defined fileno $fh;
+    local $\ = '';  # just in case
+    no warnings;    # temporarily disable warnings
+    local $^W;      # temporarily disable warnings
+    return print $fh '';
+}
 
 sub lock_exclusive {
     my $self = shift;