Removed transactional staleness counter from the HEAD as it can never be stale
rkinyon [Tue, 30 Jan 2007 04:22:46 +0000 (04:22 +0000)]
lib/DBM/Deep/Engine.pm
t/35_transaction_multiple.t

index c2e4a0e..13f29fa 100644 (file)
@@ -359,10 +359,10 @@ sub begin_work {
     }
 
     my @slots = $self->read_txn_slots;
-    for my $i ( 1 .. @slots ) {
+    for my $i ( 0 .. @slots ) {
         next if $slots[$i];
         $slots[$i] = 1;
-        $self->set_trans_id( $i );
+        $self->set_trans_id( $i + 1 );
         last;
     }
     $self->write_txn_slots( @slots );
@@ -389,7 +389,8 @@ sub rollback {
         my $read_loc = $entry
           + $self->hash_size
           + $self->byte_size
-          + $self->trans_id * ( $self->byte_size + 4 );
+          + $self->byte_size
+          + ($self->trans_id - 1) * ( $self->byte_size + 4 );
 
         my $data_loc = $self->storage->read_at( $read_loc, $self->byte_size );
         $data_loc = unpack( $StP{$self->byte_size}, $data_loc );
@@ -403,7 +404,7 @@ sub rollback {
     $self->clear_entries;
 
     my @slots = $self->read_txn_slots;
-    $slots[$self->trans_id] = 0;
+    $slots[$self->trans_id-1] = 0;
     $self->write_txn_slots( @slots );
     $self->inc_txn_staleness_counter( $self->trans_id );
     $self->set_trans_id( 0 );
@@ -427,13 +428,15 @@ sub commit {
 
         my $head_loc = $self->storage->read_at( $base, $self->byte_size );
         $head_loc = unpack( $StP{$self->byte_size}, $head_loc );
+
+        my $spot = $base + $self->byte_size + ($self->trans_id - 1) * ( $self->byte_size + 4 );
         my $trans_loc = $self->storage->read_at(
-            $base + $self->trans_id * ( $self->byte_size + 4 ), $self->byte_size,
+            $spot, $self->byte_size,
         );
 
         $self->storage->print_at( $base, $trans_loc );
         $self->storage->print_at(
-            $base + $self->trans_id * ( $self->byte_size + 4 ),
+            $spot,
             pack( $StP{$self->byte_size} . ' N', (0) x 2 ),
         );
 
@@ -445,7 +448,7 @@ sub commit {
     $self->clear_entries;
 
     my @slots = $self->read_txn_slots;
-    $slots[$self->trans_id] = 0;
+    $slots[$self->trans_id-1] = 0;
     $self->write_txn_slots( @slots );
     $self->inc_txn_staleness_counter( $self->trans_id );
     $self->set_trans_id( 0 );
@@ -472,7 +475,7 @@ sub write_txn_slots {
 sub get_running_txn_ids {
     my $self = shift;
     my @transactions = $self->read_txn_slots;
-    my @trans_ids = grep { $transactions[$_] } 0 .. $#transactions;
+    my @trans_ids = map { $_+1} grep { $transactions[$_] } 0 .. $#transactions;
 }
 
 sub get_txn_staleness_counter {
@@ -482,13 +485,12 @@ sub get_txn_staleness_counter {
     # Hardcode staleness of 0 for the HEAD
     return 0 unless $trans_id;
 
-    my $x = unpack( 'N',
+    return unpack( 'N',
         $self->storage->read_at(
-            $self->trans_loc + 4 * $trans_id,
+            $self->trans_loc + 4 + 4 * ($trans_id - 1),
             4,
         )
     );
-    return $x;
 }
 
 sub inc_txn_staleness_counter {
@@ -499,7 +501,7 @@ sub inc_txn_staleness_counter {
     return unless $trans_id;
 
     $self->storage->print_at(
-        $self->trans_loc + 4 * $trans_id,
+        $self->trans_loc + 4 + 4 * ($trans_id - 1),
         pack( 'N', $self->get_txn_staleness_counter( $trans_id ) + 1 ),
     );
 }
@@ -551,7 +553,7 @@ sub clear_entries {
 
         my $nt = $self->num_txns;
 
-        my $header_var = 1 + 1 + 1 + 1 + 4 + 4 * $nt + 3 * $self->byte_size;
+        my $header_var = 1 + 1 + 1 + 1 + 4 + 4 * ($nt - 1) + 3 * $self->byte_size;
 
         my $loc = $self->storage->request_space( $header_fixed + $header_var );
 
@@ -568,8 +570,9 @@ sub clear_entries {
             pack('C', $self->data_sector_size - 1),
 
             pack('C', $nt),
+#XXX This is a problem - it limits everything to 32 transactions
             pack('N', 0 ),                   # Transaction activeness bitfield
-            pack('N' . $nt, 0 x $nt ),       # Transaction staleness counters
+            pack('N' . ($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)
@@ -577,7 +580,7 @@ sub clear_entries {
 
         #XXX Set these less fragilely
         $self->set_trans_loc( $header_fixed + 4 );
-        $self->set_chains_loc( $header_fixed + 4 + 4 + 4 * $nt );
+        $self->set_chains_loc( $header_fixed + 4 + 4 + 4 * ($nt-1) );
 
         return;
     }
@@ -618,9 +621,6 @@ sub clear_entries {
             DBM::Deep->_throw_error("Corrupted file - bad header");
         }
 
-        $self->set_trans_loc( $header_fixed + scalar(@values) );
-        $self->set_chains_loc( $header_fixed + scalar(@values) + 4 + 4 * $self->num_txns );
-
         #XXX Add warnings if values weren't set right
         @{$self}{qw(byte_size max_buckets data_sector_size num_txns)} = @values;
 
@@ -628,12 +628,15 @@ sub clear_entries {
         $self->{max_buckets} += 1;
         $self->{data_sector_size} += 1;
 
-        my $header_var = scalar(@values) + 4 + 4 * $self->num_txns + 3 * $self->byte_size;
+        my $header_var = scalar(@values) + 4 + 4 * ($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)." );
         }
 
+        $self->set_trans_loc( $header_fixed + scalar(@values) );
+        $self->set_chains_loc( $header_fixed + scalar(@values) + 4 + 4 * ($self->num_txns - 1) );
+
         return length($buffer) + length($buffer2);
     }
 }
@@ -1558,8 +1561,9 @@ sub bucket_size {
     my $self = shift;
     unless ( $self->{bucket_size} ) {
         my $e = $self->engine;
+        #XXX Convert the 4 to STALE_SIZE()
         # Key + head (location) + transactions (location + staleness-counter)
-        my $location_size = $e->byte_size + $e->num_txns * ( $e->byte_size + 4 );
+        my $location_size = $e->byte_size + $e->byte_size + ($e->num_txns - 1) * ($e->byte_size + 4);
         $self->{bucket_size} = $e->hash_size + $location_size;
     }
     return $self->{bucket_size};
@@ -1672,13 +1676,22 @@ sub write_md5 {
 
     my $loc = $spot
       + $engine->hash_size
-      + $engine->byte_size
-      + $args->{trans_id} * ( $engine->byte_size + 4 );
+      + $engine->byte_size;
 
-    $engine->storage->print_at( $loc,
-        pack( $StP{$engine->byte_size}, $args->{value}->offset ),
-        pack( 'N', $engine->get_txn_staleness_counter( $args->{trans_id} ) ),
-    );
+    #XXX Convert the 4 to STALE_SIZE()
+    if ( $args->{trans_id} ) {
+        $loc += $engine->byte_size + ($args->{trans_id} - 1) * ( $engine->byte_size + 4 );
+
+        $engine->storage->print_at( $loc,
+            pack( $StP{$engine->byte_size}, $args->{value}->offset ),
+            pack( 'N', $engine->get_txn_staleness_counter( $args->{trans_id} ) ),
+        );
+    }
+    else {
+        $engine->storage->print_at( $loc,
+            pack( $StP{$engine->byte_size}, $args->{value}->offset ),
+        );
+    }
 }
 
 sub mark_deleted {
@@ -1695,13 +1708,23 @@ sub mark_deleted {
 
     my $loc = $spot
       + $engine->hash_size
-      + $engine->byte_size
-      + $args->{trans_id} * ( $engine->byte_size + 4 );
+      + $engine->byte_size;
+
+    #XXX Convert the 4 to STALE_SIZE()
+    if ( $args->{trans_id} ) {
+        $loc += $engine->byte_size + ($args->{trans_id} - 1) * ( $engine->byte_size + 4 );
+
+        $engine->storage->print_at( $loc,
+            pack( $StP{$engine->byte_size}, 1 ), # 1 is the marker for deleted
+            pack( 'N', $engine->get_txn_staleness_counter( $args->{trans_id} ) ),
+        );
+    }
+    else {
+        $engine->storage->print_at( $loc,
+            pack( $StP{$engine->byte_size}, 1 ), # 1 is the marker for deleted
+        );
+    }
 
-    $engine->storage->print_at( $loc,
-        pack( $StP{$engine->byte_size}, 1 ), # 1 is the marker for deleted
-        pack( 'N', $engine->get_txn_staleness_counter( $args->{trans_id} ) ),
-    );
 }
 
 sub delete_md5 {
@@ -1749,22 +1772,29 @@ sub get_data_location_for {
     my $spot = $self->offset + $self->base_size
       + $args->{idx} * $self->bucket_size
       + $e->hash_size
-      + $e->byte_size
-      + $args->{trans_id} * ( $e->byte_size + 4 );
+      + $e->byte_size;
+
+    #XXX Convert the 4 to STALE_SIZE()
+    if ( $args->{trans_id} ) {
+        $spot += $e->byte_size + ($args->{trans_id} - 1) * ( $e->byte_size + 4 );
+    }
 
+    #XXX Convert the 4 to STALE_SIZE()
     my $buffer = $e->storage->read_at(
         $spot,
         $e->byte_size + 4,
     );
     my ($loc, $staleness) = unpack( $StP{$e->byte_size} . ' N', $buffer );
 
-    # We have found an entry that is old, so get rid of it
-    if ( $staleness != (my $s = $e->get_txn_staleness_counter( $args->{trans_id} ) ) ) {
-        $e->storage->print_at(
-            $spot,
-            pack( $StP{$e->byte_size} . ' N', (0) x 2 ), 
-        );
-        $loc = 0;
+    if ( $args->{trans_id} ) {
+        # We have found an entry that is old, so get rid of it
+        if ( $staleness != (my $s = $e->get_txn_staleness_counter( $args->{trans_id} ) ) ) {
+            $e->storage->print_at(
+                $spot,
+                pack( $StP{$e->byte_size} . ' N', (0) x 2 ), 
+            );
+            $loc = 0;
+        }
     }
 
     # If we're in a transaction and we never wrote to this location, try the
index 901b5c0..11261fd 100644 (file)
@@ -49,7 +49,7 @@ $db1->{bar} = 'foo';
 ok(  exists $db1->{bar}, "After DB1 set bar to foo, DB1's bar exists" );
 ok( !exists $db2->{bar}, "After DB1 set bar to foo, DB2's bar doesn't exist" );
 ok( !exists $db3->{bar}, "After DB1 set bar to foo, DB3's bar doesn't exist" );
-
 $db2->begin_work;
 
 is( $db1->{foo}, 'bar2', "After DB2 transaction begin, DB1's foo is still bar2" );