Created concept of Storage:: in order to start adding more storage backends
Rob Kinyon [Mon, 30 Nov 2009 02:30:28 +0000 (21:30 -0500)]
MANIFEST
etc/mysql_tables.sql
lib/DBM/Deep.pm
lib/DBM/Deep/Array.pm
lib/DBM/Deep/Engine.pm
lib/DBM/Deep/Hash.pm
lib/DBM/Deep/Iterator.pm
lib/DBM/Deep/Storage/File.pm [moved from lib/DBM/Deep/File.pm with 93% similarity]
t/11_optimize.t
t/common.pm

index 02e437f..56d1b9d 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -12,7 +12,7 @@ lib/DBM/Deep/Engine/Sector/Index.pm
 lib/DBM/Deep/Engine/Sector/Null.pm
 lib/DBM/Deep/Engine/Sector/Reference.pm
 lib/DBM/Deep/Engine/Sector/Scalar.pm
-lib/DBM/Deep/File.pm
+lib/DBM/Deep/Storage/File.pm
 lib/DBM/Deep/Hash.pm
 lib/DBM/Deep/Internals.pod
 lib/DBM/Deep/Iterator.pm
index 7a402a9..f054e5d 100644 (file)
@@ -1,8 +1,10 @@
+DROP TABLE IF EXISTS `rec_array`;
 CREATE TABLE `rec_array` (
   `id` bigint(20) unsigned NOT NULL,
   PRIMARY KEY (`id`)
 );
 
+DROP TABLE IF EXISTS `rec_array_item`;
 CREATE TABLE `rec_array_item` (
   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
   `array` bigint(20) NOT NULL,
@@ -10,14 +12,16 @@ CREATE TABLE `rec_array_item` (
   `value_data` varchar(255) DEFAULT NULL,
   `value_type` enum('array','data','hash','text','value') NOT NULL DEFAULT 'value',
   PRIMARY KEY (`id`),
-  UNIQUE KEY `array_2` (`array`,`pos`),
+  UNIQUE KEY `array_2` (`array`,`pos`)
 );
 
+DROP TABLE IF EXISTS `rec_hash`;
 CREATE TABLE `rec_hash` (
   `id` bigint(20) unsigned NOT NULL,
   PRIMARY KEY (`id`)
 );
 
+DROP TABLE IF EXISTS `rec_hash_item`;
 CREATE TABLE `rec_hash_item` (
   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
   `hash` bigint(20) NOT NULL,
@@ -27,21 +31,24 @@ CREATE TABLE `rec_hash_item` (
   `value_data` varchar(255) DEFAULT NULL,
   `value_type` enum('array','data','hash','text','value') NOT NULL DEFAULT 'value',
   PRIMARY KEY (`id`),
-  UNIQUE KEY `hash_2` (`hash`,`key_hash`),
+  UNIQUE KEY `hash_2` (`hash`,`key_hash`)
 );
 
+DROP TABLE IF EXISTS `rec_item`;
 CREATE TABLE `rec_item` (
   `id` bigint(20) NOT NULL AUTO_INCREMENT,
   `item_type` enum('array','hash') NOT NULL DEFAULT 'hash',
   PRIMARY KEY (`id`)
 );
 
+DROP TABLE IF EXISTS `rec_value_data`;
 CREATE TABLE `rec_value_data` (
   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
   `data` longblob NOT NULL,
   PRIMARY KEY (`id`)
 );
 
+DROP TABLE IF EXISTS `rec_value_text`;
 CREATE TABLE `rec_value_text` (
   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
   `data` longtext NOT NULL,
index 1d0ea6a..20e9620 100644 (file)
@@ -5,13 +5,11 @@ use 5.006_000;
 use strict;
 use warnings FATAL => 'all';
 
-our $VERSION = q(1.0014);
+our $VERSION = q(1.0015);
 
-use Data::Dumper ();
 use Scalar::Util ();
 
-use DBM::Deep::Engine;
-use DBM::Deep::File;
+use DBM::Deep::Engine ();
 
 use DBM::Deep::SQL::Util;
 use DBM::Deep::SQL::Array;
@@ -23,9 +21,6 @@ use overload
 
 use constant DEBUG => 0;
 
-##
-# Setup constants for users to pass to new()
-##
 sub TYPE_HASH   () { DBM::Deep::Engine->SIG_HASH  }
 sub TYPE_ARRAY  () { DBM::Deep::Engine->SIG_ARRAY }
 
@@ -53,12 +48,10 @@ sub _get_args {
     return $args;
 }
 
+# Class constructor method for Perl OO interface.
+# Calls tie() and returns blessed reference to tied hash or array,
+# providing a hybrid OO/tie interface.
 sub new {
-    ##
-    # Class constructor method for Perl OO interface.
-    # Calls tie() and returns blessed reference to tied hash or array,
-    # providing a hybrid OO/tie interface.
-    ##
     my $class = shift;
     my $args = $class->_get_args( @_ );
     my $self;
@@ -221,13 +214,13 @@ sub _copy_value {
         ${$spot} = $value;
     }
     else {
-        # This assumes hash or array only. This is a bad assumption moving forward.
-        # -RobK, 2008-05-27
         my $r = Scalar::Util::reftype( $value );
         my $tied;
         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 {
             $tied = tied(%$value);
         }
@@ -263,9 +256,6 @@ sub _copy_value {
 #}
 
 sub export {
-    ##
-    # Recursively export into standard Perl hashes and arrays.
-    ##
     my $self = shift->_get_self;
 
     my $temp = $self->_repr;
@@ -298,8 +288,7 @@ sub _check_legality {
 }
 
 sub import {
-    # Perl calls import() on use -- ignore
-    return if !ref $_[0];
+    return if !ref $_[0]; # Perl calls import() on use -- ignore
 
     my $self = shift->_get_self;
     my ($struct) = @_;
@@ -366,13 +355,15 @@ sub import {
 
 #XXX Need to keep track of who has a fh to this file in order to
 #XXX close them all prior to optimize on Win32/cygwin
+# Rebuild entire database into new file, then move
+# it back on top of original.
 sub optimize {
-    ##
-    # Rebuild entire database into new file, then move
-    # it back on top of original.
-    ##
     my $self = shift->_get_self;
 
+    # Optimizing is only something we need to do when we're working with our
+    # own file format. Otherwise, let the other guy do the optimizations.
+#    return unless $self->_engine->isa( 'DBM::Deep::Engine::File' );
+
 #XXX Need to create a new test for this
 #    if ($self->_engine->storage->{links} > 1) {
 #        $self->_throw_error("Cannot optimize: reference count is greater than 1");
@@ -505,10 +496,7 @@ sub commit {
     return $rv;
 }
 
-##
 # Accessor methods
-##
-
 sub _engine {
     my $self = $_[0]->_get_self;
     return $self->{engine};
@@ -529,10 +517,7 @@ sub _staleness {
     return $self->{staleness};
 }
 
-##
 # Utility methods
-##
-
 sub _throw_error {
     my $n = 0;
     while( 1 ) {
@@ -543,10 +528,8 @@ sub _throw_error {
     }
 }
 
+# Store single hash key/value or array element in database.
 sub STORE {
-    ##
-    # Store single hash key/value or array element in database.
-    ##
     my $self = shift->_get_self;
     my ($key, $value) = @_;
     warn "STORE($self, '$key', '@{[defined$value?$value:'undef']}')\n" if DEBUG;
@@ -570,10 +553,8 @@ sub STORE {
     return 1;
 }
 
+# Fetch single value or element given plain key or array index
 sub FETCH {
-    ##
-    # Fetch single value or element given plain key or array index
-    ##
     my $self = shift->_get_self;
     my ($key) = @_;
     warn "FETCH($self, '$key')\n" if DEBUG;
@@ -591,10 +572,8 @@ sub FETCH {
         : $result;
 }
 
+# Delete single key/value pair or element given plain key or array index
 sub DELETE {
-    ##
-    # Delete single key/value pair or element given plain key or array index
-    ##
     my $self = shift->_get_self;
     my ($key) = @_;
     warn "DELETE($self, '$key')\n" if DEBUG;
@@ -619,10 +598,8 @@ sub DELETE {
     return $value;
 }
 
+# Check if a single key or element exists given plain key or array index
 sub EXISTS {
-    ##
-    # Check if a single key or element exists given plain key or array index
-    ##
     my $self = shift->_get_self;
     my ($key) = @_;
     warn "EXISTS($self, '$key')\n" if DEBUG;
@@ -636,10 +613,8 @@ sub EXISTS {
     return $result;
 }
 
+# Clear all keys from hash, or all elements from array.
 sub CLEAR {
-    ##
-    # Clear all keys from hash, or all elements from array.
-    ##
     my $self = shift->_get_self;
     warn "CLEAR($self)\n" if DEBUG;
 
@@ -674,16 +649,14 @@ sub CLEAR {
     return 1;
 }
 
-##
 # Public method aliases
-##
-sub put { (shift)->STORE( @_ ) }
-sub store { (shift)->STORE( @_ ) }
-sub get { (shift)->FETCH( @_ ) }
-sub fetch { (shift)->FETCH( @_ ) }
+sub put    { (shift)->STORE( @_ )  }
+sub get    { (shift)->FETCH( @_ )  }
+sub store  { (shift)->STORE( @_ )  }
+sub fetch  { (shift)->FETCH( @_ )  }
 sub delete { (shift)->DELETE( @_ ) }
 sub exists { (shift)->EXISTS( @_ ) }
-sub clear { (shift)->CLEAR( @_ ) }
+sub clear  { (shift)->CLEAR( @_ )  }
 
 sub _dump_file {shift->_get_self->_engine->_dump_file;}
 
index 5521477..b4a4636 100644 (file)
@@ -3,9 +3,7 @@ package DBM::Deep::Array;
 use 5.006_000;
 
 use strict;
-use warnings;
-
-our $VERSION = q(1.0013);
+use warnings FATAL => 'all';
 
 # This is to allow DBM::Deep::Array to handle negative indices on
 # its own. Otherwise, Perl would intercept the call to negative
@@ -171,9 +169,9 @@ sub DELETE {
     return $rv;
 }
 
-# Now that we have a real Reference sector, we should store arrayzize there. However,
-# arraysize needs to be transactionally-aware, so a simple location to store it isn't
-# going to work.
+# Now that we have a real Reference sector, we should store arrayzize there.
+# However, arraysize needs to be transactionally-aware, so a simple location to
+# store it isn't going to work.
 sub FETCHSIZE {
     my $self = shift->_get_self;
 
@@ -378,12 +376,9 @@ sub SPLICE {
 
 # We don't need to populate it, yet.
 # It will be useful, though, when we split out HASH and ARRAY
-sub EXTEND {
-    ##
-    # Perl will call EXTEND() when the array is likely to grow.
-    # We don't care, but include it because it gets called at times.
-    ##
-}
+# Perl will call EXTEND() when the array is likely to grow.
+# We don't care, but include it because it gets called at times.
+sub EXTEND {}
 
 sub _copy_node {
     my $self = shift;
@@ -397,14 +392,11 @@ sub _copy_node {
     return 1;
 }
 
-##
-# Public method aliases
-##
-sub length { (shift)->FETCHSIZE(@_) }
-sub pop { (shift)->POP(@_) }
-sub push { (shift)->PUSH(@_) }
-sub unshift { (shift)->UNSHIFT(@_) }
-sub splice { (shift)->SPLICE(@_) }
+sub length  { (shift)->FETCHSIZE(@_) }
+sub pop     { (shift)->POP(@_)       }
+sub push    { (shift)->PUSH(@_)      }
+sub unshift { (shift)->UNSHIFT(@_)   }
+sub splice  { (shift)->SPLICE(@_)    }
 
 # This must be last otherwise we have to qualify all other calls to shift
 # as calls to CORE::shift
index 49a075c..873d1b2 100644 (file)
@@ -29,6 +29,7 @@ sub SIG_BLIST    () { 'B'    }
 sub SIG_FREE     () { 'F'    }
 sub SIG_SIZE     () {  1     }
 
+use DBM::Deep::Storage::File ();
 use DBM::Deep::Iterator ();
 use DBM::Deep::Engine::Sector::Data ();
 use DBM::Deep::Engine::Sector::BucketList ();
@@ -152,7 +153,7 @@ sub new {
     my $class = shift;
     my ($args) = @_;
 
-    $args->{storage} = DBM::Deep::File->new( $args )
+    $args->{storage} = DBM::Deep::Storage::File->new( $args )
         unless exists $args->{storage};
 
     my $self = bless {
index 50dd19d..dafbe2f 100644 (file)
@@ -14,9 +14,6 @@ sub _get_self {
 sub _repr { return {} }
 
 sub TIEHASH {
-    ##
-    # Tied hash constructor method, called by Perl's tie() function.
-    ##
     my $class = shift;
     my $args = $class->_get_args( @_ );
     
@@ -66,10 +63,8 @@ sub DELETE {
     return $self->SUPER::DELETE( $key, $_[0] );
 }
 
+# Locate and return first key (in no particular order)
 sub FIRSTKEY {
-    ##
-    # Locate and return first key (in no particular order)
-    ##
     my $self = shift->_get_self;
 
     $self->lock_shared;
@@ -83,10 +78,8 @@ sub FIRSTKEY {
         : $result;
 }
 
+# Return next key (in no particular order), given previous one
 sub NEXTKEY {
-    ##
-    # Return next key (in no particular order), given previous one
-    ##
     my $self = shift->_get_self;
 
     my $prev_key = ($self->_engine->storage->{filter_store_key})
@@ -104,11 +97,8 @@ sub NEXTKEY {
         : $result;
 }
 
-##
-# Public method aliases
-##
 sub first_key { (shift)->FIRSTKEY(@_) }
-sub next_key { (shift)->NEXTKEY(@_) }
+sub next_key  { (shift)->NEXTKEY(@_)  }
 
 sub _copy_node {
     my $self = shift;
index 8ff9014..4fd10e3 100644 (file)
@@ -111,7 +111,7 @@ sub get_next_key {
     unless ( @$crumbs ) {
         # This will be a Reference sector
         my $sector = $e->_load_sector( $self->{base_offset} )
-            # If no sector is found, thist must have been deleted from under us.
+            # If no sector is found, this must have been deleted from under us.
             or return;
 
         if ( $sector->staleness != $obj->_staleness ) {
similarity index 93%
rename from lib/DBM/Deep/File.pm
rename to lib/DBM/Deep/Storage/File.pm
index ba4d04f..96862d3 100644 (file)
@@ -1,4 +1,4 @@
-package DBM::Deep::File;
+package DBM::Deep::Storage::File;
 
 use 5.006_000;
 
@@ -11,7 +11,7 @@ use constant DEBUG => 0;
 
 =head1 NAME
 
-DBM::Deep::File
+DBM::Deep::Storage::File
 
 =head1 PURPOSE
 
@@ -22,8 +22,8 @@ Currently, the only storage mechanism supported is the file system.
 
 =head1 OVERVIEW
 
-This class provides an abstraction to the storage mechanism so that the Engine (the
-only class that uses this class) doesn't have to worry about that.
+This class provides an abstraction to the storage mechanism so that the Engine
+(the only class that uses this class) doesn't have to worry about that.
 
 =head1 METHODS
 
@@ -142,8 +142,8 @@ sub size {
 
 This will set the inode value of the underlying file object.
 
-This is only needed to handle some obscure Win32 bugs. It reqlly shouldn't be needed outside
-this object.
+This is only needed to handle some obscure Win32 bugs. It reqlly shouldn't be
+needed outside this object.
 
 There is no return value.
 
@@ -165,9 +165,9 @@ sub set_inode {
 
 This takes an optional offset and some data to print.
 
-C< $offset >, if defined, will be used to seek into the file. If file_offset is set, it will be used
-as the zero location. If it is undefined, no seeking will occur. Then, C< @data > will be printed to
-the current location.
+C< $offset >, if defined, will be used to seek into the file. If file_offset is
+set, it will be used as the zero location. If it is undefined, no seeking will
+occur. Then, C< @data > will be printed to the current location.
 
 There is no return value.
 
@@ -199,9 +199,9 @@ sub print_at {
 
 This takes an optional offset and a length.
 
-C< $offset >, if defined, will be used to seek into the file. If file_offset is set, it will be used
-as the zero location. If it is undefined, no seeking will occur. Then, C< $length > bytes will be
-read from the current location.
+C< $offset >, if defined, will be used to seek into the file. If file_offset is
+set, it will be used as the zero location. If it is undefined, no seeking will
+occur. Then, C< $length > bytes will be read from the current location.
 
 The data read will be returned.
 
@@ -231,7 +231,7 @@ sub read_at {
 
 =head2 DESTROY
 
-When the ::File object goes out of scope, it will be closed.
+When the ::Storage::File object goes out of scope, it will be closed.
 
 =cut
 
index fbb7975..09b7d19 100644 (file)
@@ -51,7 +51,7 @@ my $result = $db->optimize();
 my $after = (stat($filename))[7];
 
 ok( $result, "optimize succeeded" );
-ok( $after < $before, "file size has shrunk" ); # make sure file shrunk
+cmp_ok( $after, '<', $before, "file size has shrunk" ); # make sure file shrunk
 
 is( $db->{key1}, 'value1', "key1's value is still there after optimize" );
 is( $db->{a}{c}, 'value2', "key2's value is still there after optimize" );
index c0a881f..1d47d04 100644 (file)
@@ -1,12 +1,8 @@
 package # Hide from PAUSE
     t::common;
 
-use 5.006_000;
-
 use strict;
-use warnings;
-
-our $VERSION = '0.01';
+use warnings FATAL => 'all';
 
 use base 'Exporter';
 our @EXPORT_OK = qw(
@@ -20,7 +16,6 @@ use Fcntl qw( :flock );
 
 my $parent = $ENV{WORK_DIR} || File::Spec->tmpdir;
 my $dir = tempdir( CLEANUP => 1, DIR => $parent );
-#my $dir = tempdir( DIR => '.' );
 
 sub new_fh {
     my ($fh, $filename) = tempfile( 'tmpXXXX', DIR => $dir, UNLINK => 1 );
@@ -37,6 +32,23 @@ sub new_dbm {
     my @extra_args = (
         [ file => $filename ],
     );
+
+#    eval { require DBD::SQLite; };
+#    unless ( $@ ) {
+#        push @extra_args, [
+#        ];
+#    }
+
+    if ( $ENV{TEST_MYSQL_DSN} ) {
+        push @extra_args, [
+            dbi => {
+                dsn      => "dbi:mysql:$ENV{TEST_MYSQL_DSN}",
+                user     => $ENV{TEST_MYSQL_USER},
+                password => $ENV{TEST_MYSQL_PASS},
+            },
+        ];
+    }
+
     return sub {
         return unless @extra_args;
         my @these_args = @{ shift @extra_args };