Subject: | Optimization on a database using 'file_offset' fails |
Date: | Wed, 17 Oct 2007 22:22:52 -0700 (PDT) |
To: | bug-DBM-Deep [...] rt.cpan.org |
From: | Steven Samelson <stevensamelson [...] yahoo.com> |
DBM::Deep version: 1.0006
Perl version: v5.8.8 built for MSWin32-x86-multi-thread
OS version: Windows XP and Windows 2003 Server
Bug Description:
Optimizing databases with 'file_offset' larger than zero results in a very large database (100x larger). Optimization should retain the offset for the database, along with any data above the specified offset.
Patch:
Here is an inefficient work around. The comments with "Changed" indicate where some of the modifications were made (other comments were removed for sake of brevity):
sub optimize {
##
# Rebuild entire database into new file, then move
# it back on top of original.
##
my $self = shift->_get_self;
#XXX Need to create a new test for this
# if ($self->_storage->{links} > 1) {
# $self->_throw_error("Cannot optimize: reference count is greater than 1");
# }
#XXX Do we have to lock the tempfile?
#####################################################################################
# Changed
# This is to make sure that any database temp file that has been left from
# the previous optimization has been deleted.
#####################################################################################
my $file_offset = $self->_storage->{file_offset};
my $file = $self->_storage->{file};
my $new_db_name = $file . '.tmp';
unlink($new_db_name) if (-f $new_db_name);
#####################################################################################
#XXX Should we use tempfile() here instead of a hard-coded name?
my $db_temp = DBM:Deep->new(
file => $self->_storage->{file} . '.tmp',
type => $self->_type,
# Bring over all the parameters that we need to bring over
( map { $_ => $self->_engine->$_ } qw(
byte_size max_buckets data_sector_size num_txns
)),
file_offset => 0, # Changed
sig_file => $sig_file, # Changed
);
$self->lock();
$self->_engine->clear_cache;
$self->_copy_node( $db_temp );
# Changed
$db_temp->_storage->close;
undef $db_temp;
##
# Attempt to copy user, group and permissions over to new file
##
my @stats = stat($self->_fh);
my $perms = $stats[2] & 07777;
my $uid = $stats[4];
my $gid = $stats[5];
chown( $uid, $gid, $self->_storage->{file} . '.tmp' );
chmod( $perms, $self->_storage->{file} . '.tmp' );
# q.v. perlport for more information on this variable
if ( $^O eq 'MSWin32' || $^O eq 'cygwin' ) {
##
# Potential race condition when optmizing on Win32 with locking.
# The Windows filesystem requires that the filehandle be closed
# before it is overwritten with rename(). This could be redone
# with a soft copy.
##
$self->unlock();
$self->_storage->close;
}
################################################################################################
# Changed
# Read the top part from the old database.
################################################################################################
# Copy the top part from the old db to the new db.
my $top_part;
my $fh_old;
open $fh_old, $file;
binmode $fh_old;
my $rd = sysread($fh_old, $top_part, $file_offset);
close $fh_old;
################################################################################################
if (!rename $self->_storage->{file} . '.tmp', $self->_storage->{file}) {
unlink $self->_storage->{file} . '.tmp';
$self->unlock();
$self->_throw_error("Optimize failed: Cannot copy temp file over original: $!");
}
$self->unlock();
$self->_storage->close;
################################################################################################
# Changed
# Read the content of the database.
################################################################################################
my $db_content;
# Get the actual size of the image
my @array = stat("$file");
my $db_size = $array[7];
my $fh;
open $fh, "$file";
binmode $fh;
$rd = sysread($fh, $db_content, $db_size);
close $fh;
################################################################################################
# Changed
# Concatenate the top part with the database content and save it in the database.
###############################################################################################
# Save it in the new db.
my $fh_new;
open $fh_new, ">$file";
binmode $fh_new;
print $fh_new ($top_part . $db_content);
close $fh_new;
################################################################################################
$self->_storage->open;
$self->lock();
$self->_engine->setup_fh( $self );
$self->unlock();
return 1;
}
Show quoted text
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
Message body is not shown because it is too large.