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;
$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
}
else {
$self->{offset} = 0;
+ $self->{is_new} = 0;
+
+ return if exists $self->engine->sector_cache->{0};
my $s = $e->storage;
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__