Minor fixes, including removing the ==2/1 from add_bucket()
[dbsrgits/DBM-Deep.git] / lib / DBM / Deep.pm
index dbb9a9e..75aee67 100644 (file)
@@ -34,6 +34,8 @@ use 5.6.0;
 use strict;
 use warnings;
 
+our $VERSION = q(0.99_01);
+
 use Fcntl qw( :DEFAULT :flock :seek );
 use Digest::MD5 ();
 use Scalar::Util ();
@@ -41,14 +43,11 @@ use Scalar::Util ();
 use DBM::Deep::Engine;
 use DBM::Deep::File;
 
-use vars qw( $VERSION );
-$VERSION = q(0.99_01);
-
 ##
 # Setup constants for users to pass to new()
 ##
-sub TYPE_HASH   () { DBM::Deep::Engine->SIG_HASH   }
-sub TYPE_ARRAY  () { DBM::Deep::Engine->SIG_ARRAY  }
+sub TYPE_HASH   () { DBM::Deep::Engine->SIG_HASH  }
+sub TYPE_ARRAY  () { DBM::Deep::Engine->SIG_ARRAY }
 
 sub _get_args {
     my $proto = shift;
@@ -335,8 +334,7 @@ sub rollback {
 
 sub commit {
     my $self = shift->_get_self;
-    # At this point, we need to replay the actions taken
-    $self->_fileobj->end_transaction;
+    $self->_fileobj->commit_transaction;
     return 1;
 }
 
@@ -384,14 +382,29 @@ sub _is_writable {
 
 sub _find_parent {
     my $self = shift;
-    if ( $self->{parent} ) {
-        my $base = $self->{parent}->_find_parent();
-        if ( $self->{parent}->_type eq TYPE_HASH ) {
-            return $base . "\{$self->{parent_key}\}";
+
+    my $base = '';
+    #XXX This if() is redundant
+    if ( my $parent = $self->{parent} ) {
+        my $child = $self;
+        while ( $parent->{parent} ) {
+            $base = (
+                $parent->_type eq TYPE_HASH
+                    ? "\{$child->{parent_key}\}"
+                    : "\[$child->{parent_key}\]"
+            ) . $base;
+
+            $child = $parent;
+            $parent = $parent->{parent};
+        }
+        if ( $base ) {
+            $base = "\$db->get( '$child->{parent_key}' )->" . $base;
+        }
+        else {
+            $base = "\$db->get( '$child->{parent_key}' )";
         }
-        return $base . "\[$self->{parent_key}\]";
     }
-    return '$db->';
+    return $base;
 }
 
 sub STORE {
@@ -401,41 +414,49 @@ sub STORE {
     my $self = shift->_get_self;
     my ($key, $value, $orig_key) = @_;
 
+
     if ( $^O ne 'MSWin32' && !_is_writable( $self->_fh ) ) {
         $self->_throw_error( 'Cannot write to a readonly filehandle' );
     }
 
-    if ( my $afh = $self->_fileobj->{audit_fh} ) {
-        unless ( $self->_type eq TYPE_ARRAY && $orig_key eq 'length' ) {
-            my $lhs = $self->_find_parent;
-            if ( $self->_type eq TYPE_HASH ) {
-                $lhs .= "\{$orig_key\}";
-            }
-            else {
-                $lhs .= "\[$orig_key\]";
-            }
+    #XXX The second condition needs to disappear
+    if ( defined $orig_key && !( $self->_type eq TYPE_ARRAY && $orig_key eq 'length') ) {
+        my $rhs;
 
-            my $rhs;
+        my $r = Scalar::Util::reftype( $value ) || '';
+        if ( $r eq 'HASH' ) {
+            $rhs = '{}';
+        }
+        elsif ( $r eq 'ARRAY' ) {
+            $rhs = '[]';
+        }
+        elsif ( defined $value ) {
+            $rhs = "'$value'";
+        }
+        else {
+            $rhs = "undef";
+        }
 
-            my $r = Scalar::Util::reftype( $value ) || '';
-            if ( $r eq 'HASH' ) {
-                $rhs = '{}';
-            }
-            elsif ( $r eq 'ARRAY' ) {
-                $rhs = '[]';
+        if ( my $c = Scalar::Util::blessed( $value ) ) {
+            $rhs = "bless $rhs, '$c'";
+        }
+
+        my $lhs = $self->_find_parent;
+        if ( $lhs ) {
+            if ( $self->_type eq TYPE_HASH ) {
+                $lhs .= "->\{$orig_key\}";
             }
             else {
-                $rhs = "'$value'";
+                $lhs .= "->\[$orig_key\]";
             }
 
-            if ( my $c = Scalar::Util::blessed( $value ) ) {
-                $rhs = "bless $rhs, '$c'";
-            }
-
-            flock( $afh, LOCK_EX );
-            print( $afh "$lhs = $rhs; # " . localtime(time) . "\n" );
-            flock( $afh, LOCK_UN );
+            $lhs .= "=$rhs;";
+        }
+        else {
+            $lhs = "\$db->put('$orig_key',$rhs);";
         }
+
+        $self->_fileobj->audit($lhs);
     }
 
     ##
@@ -456,11 +477,11 @@ sub STORE {
     ##
     # Add key/value to bucket list
     ##
-    my $result = $self->{engine}->add_bucket( $tag, $md5, $key, $value, undef, $orig_key ); 
+    $self->{engine}->add_bucket( $tag, $md5, $key, $value, undef, $orig_key ); 
 
     $self->unlock();
 
-    return $result;
+    return 1;
 }
 
 sub FETCH {
@@ -468,7 +489,7 @@ sub FETCH {
     # Fetch single value or element given plain key or array index
     ##
     my $self = shift->_get_self;
-    my ($key) = @_;
+    my ($key, $orig_key) = @_;
 
     my $md5 = $self->{engine}{digest}->($key);
 
@@ -477,7 +498,8 @@ sub FETCH {
     ##
     $self->lock( LOCK_SH );
 
-    my $tag = $self->{engine}->find_bucket_list( $self->_base_offset, $md5 );
+    my $tag = $self->{engine}->find_bucket_list( $self->_base_offset, $md5 );#, { create => 1 } );
+    #XXX This needs to autovivify
     if (!$tag) {
         $self->unlock();
         return;
@@ -486,7 +508,7 @@ sub FETCH {
     ##
     # Get value from bucket list
     ##
-    my $result = $self->{engine}->get_bucket_value( $tag, $md5 );
+    my $result = $self->{engine}->get_bucket_value( $tag, $md5, $orig_key );
 
     $self->unlock();
 
@@ -501,13 +523,23 @@ sub DELETE {
     ##
     # Delete single key/value pair or element given plain key or array index
     ##
-    my $self = $_[0]->_get_self;
-    my $key = $_[1];
+    my $self = shift->_get_self;
+    my ($key, $orig_key) = @_;
 
     if ( $^O ne 'MSWin32' && !_is_writable( $self->_fh ) ) {
         $self->_throw_error( 'Cannot write to a readonly filehandle' );
     }
 
+    if ( defined $orig_key ) {
+        my $lhs = $self->_find_parent;
+        if ( $lhs ) {
+            $self->_fileobj->audit( "delete $lhs;" );
+        }
+        else {
+            $self->_fileobj->audit( "\$db->delete('$orig_key');" );
+        }
+    }
+
     ##
     # Request exclusive lock for writing
     ##
@@ -530,7 +562,7 @@ sub DELETE {
         $value = $self->_fileobj->{filter_fetch_value}->($value);
     }
 
-    my $result = $self->{engine}->delete_bucket( $tag, $md5 );
+    my $result = $self->{engine}->delete_bucket( $tag, $md5, $orig_key );
 
     ##
     # If this object is an array and the key deleted was on the end of the stack,
@@ -546,8 +578,8 @@ sub EXISTS {
     ##
     # Check if a single key or element exists given plain key or array index
     ##
-    my $self = $_[0]->_get_self;
-    my $key = $_[1];
+    my $self = shift->_get_self;
+    my ($key) = @_;
 
     my $md5 = $self->{engine}{digest}->($key);
 
@@ -580,25 +612,30 @@ sub CLEAR {
     ##
     # Clear all keys from hash, or all elements from array.
     ##
-    my $self = $_[0]->_get_self;
+    my $self = shift->_get_self;
 
     if ( $^O ne 'MSWin32' && !_is_writable( $self->_fh ) ) {
         $self->_throw_error( 'Cannot write to a readonly filehandle' );
     }
 
+    {
+        my $lhs = $self->_find_parent;
+
+        if ( $self->_type eq TYPE_HASH ) {
+            $lhs = '%{' . $lhs . '}';
+        }
+        else {
+            $lhs = '@{' . $lhs . '}';
+        }
+
+        $self->_fileobj->audit( "$lhs = ();" );
+    }
+
     ##
     # Request exclusive lock for writing
     ##
     $self->lock( LOCK_EX );
 
-    my $fh = $self->_fh;
-
-    seek($fh, $self->_base_offset + $self->_fileobj->{file_offset}, SEEK_SET);
-    if (eof $fh) {
-        $self->unlock();
-        return;
-    }
-
 #XXX This needs updating to use _release_space
     $self->{engine}->write_tag(
         $self->_base_offset, $self->_type,