use warnings;
use Fcntl qw( :DEFAULT :flock :seek );
+use Scalar::Util ();
# File-wide notes:
# * All the local($/,$\); are to protect read() and print() from -l.
max_buckets => 16,
fileobj => undef,
+ obj => undef,
}, $class;
if ( defined $args->{pack_size} ) {
next unless exists $args->{$param};
$self->{$param} = $args->{$param};
}
+ Scalar::Util::weaken( $self->{obj} ) if $self->{obj};
if ( $self->{max_buckets} < 16 ) {
warn "Floor of max_buckets is 16. Setting it to 16 from '$self->{max_buckets}'\n";
my $self = shift;
my ($obj) = @_;
+ local($/,$\);
+
my $fh = $self->_fh;
flock $fh, LOCK_EX;
# File is empty -- write header and master index
##
if (!$bytes_read) {
+ $self->_fileobj->audit( "# Database created on" );
+
$self->write_file_header;
$obj->{base_offset} = $self->_request_space( $self->tag_size( $self->{index_size} ) );
##
# Get our type from master index header
##
- my $tag = $self->load_tag($obj->_base_offset)
- or $self->_throw_error("Corrupted file, no master index record");
+ my $tag = $self->load_tag($obj->_base_offset);
+ unless ( $tag ) {
+ flock $fh, LOCK_UN;
+ $self->_throw_error("Corrupted file, no master index record");
+ }
unless ($obj->_type eq $tag->{signature}) {
+ flock $fh, LOCK_UN;
$self->_throw_error("File type mismatch");
}
}
# plain (undigested) key and value.
##
my $self = shift;
- my ($tag, $md5, $plain_key, $value, $deleted) = @_;
+ my ($tag, $md5, $plain_key, $value, $deleted, $orig_key) = @_;
$deleted ||= 0;
local($/,$\);
for ( @transactions ) {
my $tag2 = $self->load_tag( $tag->{offset} - SIG_SIZE - $self->{data_size} );
$self->_fileobj->{transaction_id} = $_;
- $self->add_bucket( $tag2, $md5, '', '', 1 );
+ $self->add_bucket( $tag2, $md5, '', '', 1, $orig_key );
$self->_fileobj->{transaction_id} = 0;
}
}
$location = $self->split_index( $md5, $tag );
}
- $self->write_value( $location, $plain_key, $value );
+ $self->write_value( $location, $plain_key, $value, $orig_key );
return $result;
}
sub write_value {
my $self = shift;
- my ($location, $key, $value) = @_;
+ my ($location, $key, $value, $orig_key) = @_;
local($/,$\);
tie %$value, 'DBM::Deep', {
base_offset => $location,
fileobj => $root,
+ parent => $self->{obj},
+ parent_key => $orig_key,
};
%$value = %x;
}
tie @$value, 'DBM::Deep', {
base_offset => $location,
fileobj => $root,
+ parent => $self->{obj},
+ parent_key => $orig_key,
};
@$value = @x;
}
sub read_from_loc {
my $self = shift;
- my ($subloc) = @_;
+ my ($subloc, $orig_key) = @_;
local($/,$\);
##
if (($signature eq SIG_HASH) || ($signature eq SIG_ARRAY)) {
my $new_obj = DBM::Deep->new({
- type => $signature,
+ type => $signature,
base_offset => $subloc,
fileobj => $self->_fileobj,
+ parent => $self->{obj},
+ parent_key => $orig_key,
});
if ($new_obj->_fileobj->{autobless}) {
read( $fh, $new_loc, $size );
$new_loc = unpack( $self->{long_pack}, $new_loc );
- return $self->read_from_loc( $new_loc );
+ return $self->read_from_loc( $new_loc, $orig_key );
}
else {
return;
# Fetch single value given tag and MD5 digested key.
##
my $self = shift;
- my ($tag, $md5) = @_;
+ my ($tag, $md5, $orig_key) = @_;
#ACID - This is a read. Can find exact or HEAD
my ($subloc, $offset, $size,$is_deleted) = $self->_find_in_buckets( $tag, $md5 );
if ( $subloc && !$is_deleted ) {
- return $self->read_from_loc( $subloc );
+ return $self->read_from_loc( $subloc, $orig_key );
}
return;
}
# Delete single key/value pair given tag and MD5 digested key.
##
my $self = shift;
- my ($tag, $md5) = @_;
+ my ($tag, $md5, $orig_key) = @_;
local($/,$\);