Fixed a bug with how transactions worked across a reindex
rkinyon [Sun, 14 Jan 2007 05:39:19 +0000 (05:39 +0000)]
lib/DBM/Deep/Engine.pm
t/33_transactions.t

index f2bad5a..3722aed 100644 (file)
@@ -505,6 +505,24 @@ sub add_entry {
     $self->{entries}{$trans_id}{$loc} = undef;
 }
 
+# If the buckets are being relocated because of a reindexing, the entries
+# mechanism needs to be made aware of it.
+sub reindex_entry {
+    my $self = shift;
+    my ($old_loc, $new_loc) = @_;
+
+    TRANS:
+    while ( my ($trans_id, $locs) = each %{ $self->{entries} } ) {
+        foreach my $orig_loc ( keys %{ $locs } ) {
+            if ( $orig_loc == $old_loc ) {
+                delete $locs->{orig_loc};
+                $locs->{$new_loc} = undef;
+                next TRANS;
+            }
+        }
+    }
+}
+
 sub clear_entries {
     my $self = shift;
     delete $self->{entries}{$self->trans_id};
@@ -1348,7 +1366,9 @@ sub get_bucket_list {
         });
 
         my %blist_cache;
-        foreach my $md5 ( $sector->chopped_up ) {
+        #XXX q.v. the comments for this function.
+        foreach my $entry ( $sector->chopped_up ) {
+            my ($spot, $md5) = @{$entry};
             my $idx = ord( substr( $md5, $i, 1 ) );
 
             # XXX This is inefficient
@@ -1359,7 +1379,8 @@ sub get_bucket_list {
 
             $new_index->set_entry( $idx => $blist->offset );
 
-            $blist->write_at_next_open( $md5 );
+            my $new_spot = $blist->write_at_next_open( $md5 );
+            $engine->reindex_entry( $spot => $new_spot );
         }
 
         # Handle the new item separately.
@@ -1497,6 +1518,7 @@ sub bucket_size {
     return $self->{bucket_size};
 }
 
+# XXX This is such a poor hack. I need to rethink this code.
 sub chopped_up {
     my $self = shift;
 
@@ -1504,14 +1526,13 @@ sub chopped_up {
 
     my @buckets;
     foreach my $idx ( 0 .. $e->max_buckets - 1 ) {
-        my $md5 = $e->storage->read_at(
-            $self->offset + $self->base_size + $idx * $self->bucket_size, $e->hash_size,
-        );
+        my $spot = $self->offset + $self->base_size + $idx * $self->bucket_size;
+        my $md5 = $e->storage->read_at( $spot, $e->hash_size );
 
         last if $md5 eq $e->blank_md5;
 
         my $rest = $e->storage->read_at( undef, $self->bucket_size - $e->hash_size );
-        push @buckets, $md5 . $rest;
+        push @buckets, [ $spot, $md5 . $rest ];
     }
 
     return @buckets;
@@ -1519,15 +1540,15 @@ sub chopped_up {
 
 sub write_at_next_open {
     my $self = shift;
-    my ($md5) = @_;
+    my ($entry) = @_;
 
     #XXX This is such a hack!
     $self->{_next_open} = 0 unless exists $self->{_next_open};
 
-    $self->engine->storage->print_at(
-        $self->offset + $self->base_size + $self->{_next_open}++ * $self->bucket_size,
-        $md5,
-    );
+    my $spot = $self->offset + $self->base_size + $self->{_next_open}++ * $self->bucket_size;
+    $self->engine->storage->print_at( $spot, $entry );
+
+    return $spot;
 }
 
 sub has_md5 {
index 0b69c05..1e6e779 100644 (file)
@@ -208,4 +208,3 @@ __END__
 Tests to add:
 * Two transactions running at the same time
 * Doing a clear on the head while a transaction is running
-# More than just two keys