Added description to a test
[dbsrgits/DBM-Deep.git] / lib / DBM / Deep / Engine / Sector / FileHeader.pm
index a6bb82c..fe70e6a 100644 (file)
@@ -17,8 +17,7 @@ sub _init {
     my $e = $self->engine;
 
     # This means the file is being created.
-    # Use defined() here because the offset should always be 0. -RobK. 2008-06-20
-    unless ( $e->storage->size ) {
+    unless ( exists $self->engine->sector_cache->{0} || $self->engine->storage->size ) {
         my $nt = $e->num_txns;
         my $bl = $e->txn_bitfield_len;
 
@@ -27,7 +26,10 @@ sub _init {
         $self->{offset} = $e->storage->request_space( $header_fixed + $header_var );
         DBM::Deep::_throw_error( "Offset wasn't 0, it's '$self->{offset}'" ) unless $self->offset == 0;
 
-        $self->write( $self->offset,
+        # Make sure we set up sector caching so that get_data() works. -RobK, 2008-06-24
+        $self->engine->sector_cache->{$self->offset} = chr(0) x ($header_fixed + $header_var);
+
+        $self->write( 0,
             $e->SIG_FILE
           . $e->SIG_HEADER
           . pack('N', $this_file_version) # At this point, we're at 9 bytes
@@ -54,6 +56,9 @@ sub _init {
     }
     else {
         $self->{offset} = 0;
+        $self->{is_new} = 0;
+
+        return if exists $self->engine->sector_cache->{0};
 
         my $s = $e->storage;
 
@@ -108,21 +113,133 @@ sub _init {
         my $bl = $e->txn_bitfield_len;
         $e->set_chains_loc( $header_fixed + scalar(@values) + $bl + $DBM::Deep::Engine::STALE_SIZE * ($e->num_txns - 1) );
 
-        $self->{is_new} = 1;
+        # Make sure we set up sector caching so that get_data() works. -RobK, 2008-06-24
+        $self->engine->sector_cache->{$self->offset} = $buffer . $buffer2;
     }
 }
 
 sub header_var_size {
     my $self = shift;
-    my $e = $self->engine;
+    my $e = shift || $self->engine;
     return 1 + 1 + 1 + 1 + $e->txn_bitfield_len + $DBM::Deep::Engine::STALE_SIZE * ($e->num_txns - 1) + 3 * $e->byte_size;
 }
 
-sub size   {
+sub size {
     my $self = shift;
-    $self->{size} ||= $header_fixed + $self->header_var_size;
+    if ( ref($self) ) {
+        $self->{size} ||= $header_fixed + $self->header_var_size;
+    }
+    else {
+        return $header_fixed + $self->header_var_size( @_ );
+    }
 }
+
 sub is_new { $_[0]{is_new} }
 
+sub add_free_sector {
+    my $self = shift;
+    my ($multiple, $sector) = @_;
+
+    my $e = $self->engine;
+
+    my $chains_offset = $multiple * $e->byte_size;
+
+    # Increment staleness.
+    # XXX Can this increment+modulo be done by "&= 0x1" ?
+    my $staleness = unpack( $e->StP($DBM::Deep::Engine::STALE_SIZE), $sector->read( $e->SIG_SIZE, $DBM::Deep::Engine::STALE_SIZE ) );
+    $staleness = ($staleness + 1 ) % ( 2 ** ( 8 * $DBM::Deep::Engine::STALE_SIZE ) );
+    $sector->write( $e->SIG_SIZE, pack( $e->StP($DBM::Deep::Engine::STALE_SIZE), $staleness ) );
+
+    my $old_head = $self->read( $e->chains_loc + $chains_offset, $e->byte_size );
+
+    $self->write( $e->chains_loc + $chains_offset,
+        pack( $e->StP($e->byte_size), $sector->offset ),
+    );
+
+    # Record the old head in the new sector after the signature and staleness counter
+    $sector->write( $e->SIG_SIZE + $DBM::Deep::Engine::STALE_SIZE, $old_head );
+}
+
+sub request_sector {
+    my $self = shift;
+    my ($multiple, $size) = @_;
+
+    my $e = $self->engine;
+
+    my $chains_offset = $multiple * $e->byte_size;
+
+    my $old_head = $self->read( $e->chains_loc + $chains_offset, $e->byte_size );
+    my $loc = unpack( $e->StP($e->byte_size), $old_head );
+
+    # We don't have any free sectors of the right size, so allocate a new one.
+    unless ( $loc ) {
+        my $offset = $e->storage->request_space( $size );
+
+        # Zero out the new sector. This also guarantees correct increases
+        # in the filesize.
+        $self->engine->sector_cache->{$offset} = chr(0) x $size;
+
+        return $offset;
+    }
+
+    # Need to load the new sector so we can read from it.
+    my $new_sector = $self->engine->get_data( $loc, $size );
+
+    # Read the new head after the signature and the staleness counter
+    my $new_head = substr( $$new_sector, $e->SIG_SIZE + $DBM::Deep::Engine::STALE_SIZE, $e->byte_size );
+
+    $self->write( $e->chains_loc + $chains_offset, $new_head );
+
+    return $loc;
+}
+
+sub read_txn_slots {
+    my $self = shift;
+    my $e = $self->engine;
+    my $bl = $e->txn_bitfield_len;
+    my $num_bits = $bl * 8;
+    my @x = split '', unpack( 'b'.$num_bits, $self->read( $e->trans_loc, $bl ) );
+    return @x;
+}
+
+sub write_txn_slots {
+    my $self = shift;
+    my $e = $self->engine;
+    my $num_bits = $e->txn_bitfield_len * 8;
+    $self->write( $e->trans_loc,
+        pack( 'b'.$num_bits, join('', @_) ),
+    );
+}
+
+sub get_txn_staleness_counter {
+    my $self = shift;
+    my ($trans_id) = @_;
+
+    # Hardcode staleness of 0 for the HEAD
+    return 0 unless $trans_id;
+
+    my $e = $self->engine;
+    return unpack( $e->StP($DBM::Deep::Engine::STALE_SIZE),
+        $self->read(
+            $e->trans_loc + $e->txn_bitfield_len + $DBM::Deep::Engine::STALE_SIZE * ($trans_id - 1),
+            $DBM::Deep::Engine::STALE_SIZE,
+        )
+    );
+}
+
+sub inc_txn_staleness_counter {
+    my $self = shift;
+    my ($trans_id) = @_;
+
+    # Hardcode staleness of 0 for the HEAD
+    return 0 unless $trans_id;
+
+    my $e = $self->engine;
+    $self->write(
+        $e->trans_loc + $e->txn_bitfield_len + $DBM::Deep::Engine::STALE_SIZE * ($trans_id - 1),
+        pack( $e->StP($DBM::Deep::Engine::STALE_SIZE), $self->get_txn_staleness_counter( $trans_id ) + 1 ),
+    );
+}
+
 1;
 __END__