DBM-Deep

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

        - Thanks to our new co-maintainer, SPROUT! :)
    - Had to turn off singleton support in the File backend because the caching
      was causing havoc with transactions. Turning on fatal warnings does give
      apparently important information.
    - Oh - forgot to mention that fatal warnings are now on in all files.

1.0019_002 Jan 05 22:30:00 2010 EST
    (This is the second developer release for 1.0020.)
    (This version is compatible with 1.0014)
	- Fixed bug where attempting to store a value tied to something other than
      DBM::Deep would leave the file flocked.
	- Added support for DBD::SQLite
        - Build.PL has been extended to support sqlite vs. mysql
        - Storage::DBI now detects between the two DBDs
    - (RT #51888) Applied POD patch (Thanks, FWIE!)
    - (RT #44981) Added VERSION to ::Array, ::Engine, and ::Hash
    - Removed extraneous slashes from POD links (Thanks ilmari!)
    - (RT #50541) Fixed bug in clear() for hashes in the File backend.
        - This has caused a regression in speed for clear() when clearing
          large hashes using running with the File backend. ->clear() (on my
          machine) now takes ( N / 40 ) ** (1.66) seconds. So, clearing 4000

README  view on Meta::CPAN

          locking => 1
      );

    This causes DBM::Deep to "flock()" the underlying filehandle with
    exclusive mode for writes, and shared mode for reads. This is required
    if you have multiple processes accessing the same database file, to
    avoid file corruption. Please note that "flock()" does NOT work for
    files over NFS. See "DB over NFS" below for more.

  Explicit Locking
    You can explicitly lock a database, so it remains locked for multiple
    actions. This is done by calling the "lock_exclusive()" method (for when
    you want to write) or the "lock_shared()" method (for when you want to
    read). This is particularly useful for things like counters, where the
    current value needs to be fetched, then incremented, then stored again.

      $db->lock_exclusive();
      my $counter = $db->get("counter");
      $counter++;
      $db->put("counter", $counter);
      $db->unlock();

lib/DBM/Deep.pod  view on Meta::CPAN

  );

This causes DBM::Deep to C<flock()> the underlying filehandle with exclusive
mode for writes, and shared mode for reads. This is required if you have
multiple processes accessing the same database file, to avoid file corruption.
Please note that C<flock()> does NOT work for files over NFS. See L</DB over
NFS> below for more.

=head2 Explicit Locking

You can explicitly lock a database, so it remains locked for multiple
actions. This is done by calling the C<lock_exclusive()> method (for when you
want to write) or the C<lock_shared()> method (for when you want to read).
This is particularly useful for things like counters, where the current value
needs to be fetched, then incremented, then stored again.

  $db->lock_exclusive();
  my $counter = $db->get("counter");
  $counter++;
  $db->put("counter", $counter);
  $db->unlock();

lib/DBM/Deep/Storage.pm  view on Meta::CPAN


Take a lock usable for writing.

=item * lock_shared( $obj )

Take a lock usable for reading.

=item * unlock( $obj )

Releases the last lock taken. If this is the outermost lock, then the
object is actually unlocked.

=back

=cut

sub lock_exclusive { die "lock_exclusive must be implemented in a child class" }
sub lock_shared { die "lock_shared must be implemented in a child class" }
sub unlock { die "unlock must be implemented in a child class" }

1;

lib/DBM/Deep/Storage/File.pm  view on Meta::CPAN

    my ($args) = @_;

    my $self = bless {
        autobless          => 1,
        autoflush          => 1,
        end                => 0,
        fh                 => undef,
        file               => undef,
        file_offset        => 0,
        locking            => 1,
        locked             => 0,
#XXX Migrate this to the engine, where it really belongs.
        filter_store_key   => undef,
        filter_store_value => undef,
        filter_fetch_key   => undef,
        filter_fetch_value => undef,
    }, $class;

    # Grab the parameters we want to use
    foreach my $param ( keys %$self ) {
        next unless exists $args->{$param};

lib/DBM/Deep/Storage/File.pm  view on Meta::CPAN

    if ( $^O eq 'MSWin32' || $^O eq 'cygwin' ) {
        $type = LOCK_EX;
    }

    if (!defined($self->{fh})) { return; }

    #XXX This either needs to allow for upgrading a shared lock to an
    # exclusive lock or something else with autovivification.
    # -RobK, 2008-03-09
    if ($self->{locking}) {
        if (!$self->{locked}) {
            flock($self->{fh}, $type);

            # refresh end counter in case file has changed size
            my @stats = stat($self->{fh});
            $self->{end} = $stats[7];

            # double-check file inode, in case another process
            # has optimize()d our file while we were waiting.
            if (defined($self->{inode}) && $stats[1] != $self->{inode}) {
                $self->close;

lib/DBM/Deep/Storage/File.pm  view on Meta::CPAN


                #XXX This needs work
                $obj->{engine}->setup( $obj );

                flock($self->{fh}, $type); # re-lock

                # This may not be necessary after re-opening
                $self->{end} = (stat($self->{fh}))[7]; # re-end
            }
        }
        $self->{locked}++;

        return 1;
    }

    return;
}

sub unlock {
    my $self = shift;

    if (!defined($self->{fh})) { return; }

    if ($self->{locking} && $self->{locked} > 0) {
        $self->{locked}--;

        if (!$self->{locked}) {
            flock($self->{fh}, LOCK_UN);
            return 1;
        }

        return;
    }

    return;
}

t/07_locking.t  view on Meta::CPAN

use common qw( new_dbm );

use_ok( 'DBM::Deep' );

my $dbm_factory = new_dbm( locking => 1 );
while ( my $dbm_maker = $dbm_factory->() ) {
    my $db = $dbm_maker->();

    lives_ok {
        $db->unlock;
    } "Can call unlock on an unlocked DB.";

    ##
    # basic put/get
    ##
    $db->{key1} = "value1";
    is( $db->{key1}, "value1", "key1 is set" );

    $db->{key2} = [ 1 .. 3 ];
    is( $db->{key2}[1], 2, "The value is set properly" );

t/11_optimize.t  view on Meta::CPAN

ok( $result, "optimize succeeded" );
cmp_ok( $after, '<', $before, "file size has shrunk" ); # make sure file shrunk

is( $db->{key1}, 'value1', "key1's value is still there after optimize" );
is( $db->{a}{c}, 'value2', "key2's value is still there after optimize" );

$db->_get_self->_engine->storage->close( $db->_get_self );

##
# now for the tricky one -- try to store a new key while file is being
# optimized and locked by another process.  filehandle should be invalidated,
# and automatically re-opened transparently.  Cannot test on Win32, due to
# problems with fork()ing, flock()ing, etc.  Win32 very bad.
##

SKIP: {
    skip "Fork tests skipped until fh/filename question solved.", 4;
    skip "Fork tests skipped on Win32", 4
        if $^O eq 'MSWin32' || $^O eq 'cygwin';

    ##

utils/lib/DBM/Deep/09830.pm  view on Meta::CPAN

	# times before unlock(), then the same number of unlocks() must
	# be called before the lock is released.
	##
    my $self = $_[0]->_get_self;
	my $type = $_[1];
    $type = LOCK_EX unless defined $type;
	
	if (!defined($self->_fh)) { return; }

	if ($self->_root->{locking}) {
		if (!$self->_root->{locked}) {
			flock($self->_fh, $type);
			
			# refresh end counter in case file has changed size
			my @stats = stat($self->_root->{file});
			$self->_root->{end} = $stats[7];
			
			# double-check file inode, in case another process
			# has optimize()d our file while we were waiting.
			if ($stats[1] != $self->_root->{inode}) {
				$self->_open(); # re-open
				flock($self->_fh, $type); # re-lock
				$self->_root->{end} = (stat($self->_fh))[7]; # re-end
			}
		}
		$self->_root->{locked}++;

        return 1;
	}

    return;
}

sub unlock {
	##
	# If db locking is set, unlock the db file.  See note in lock()
	# regarding calling lock() multiple times.
	##
    my $self = $_[0]->_get_self;

	if (!defined($self->_fh)) { return; }
	
	if ($self->_root->{locking} && $self->_root->{locked} > 0) {
		$self->_root->{locked}--;
		if (!$self->_root->{locked}) { flock($self->_fh, LOCK_UN); }

        return 1;
	}

    return;
}

sub _copy_value {
    my $self = shift->_get_self;
    my ($spot, $value) = @_;

utils/lib/DBM/Deep/09830.pm  view on Meta::CPAN

        file_offset => 0,
        end => 0,
        autoflush => undef,
        locking => undef,
        debug => undef,
        filter_store_key => undef,
        filter_store_value => undef,
        filter_fetch_key => undef,
        filter_fetch_value => undef,
        autobless => undef,
        locked => 0,
        %$args,
    }, $class;

    if ( $self->{fh} && !$self->{file_offset} ) {
        $self->{file_offset} = tell( $self->{fh} );
    }

    return $self;
}

utils/lib/DBM/Deep/10002.pm  view on Meta::CPAN

    my ($args) = @_;

    my $self = bless {
        autobless          => 1,
        autoflush          => 1,
        end                => 0,
        fh                 => undef,
        file               => undef,
        file_offset        => 0,
        locking            => 1,
        locked             => 0,
#XXX Migrate this to the engine, where it really belongs.
        filter_store_key   => undef,
        filter_store_value => undef,
        filter_fetch_key   => undef,
        filter_fetch_value => undef,
    }, $class;

    # Grab the parameters we want to use
    foreach my $param ( keys %$self ) {
        next unless exists $args->{$param};

utils/lib/DBM/Deep/10002.pm  view on Meta::CPAN

##
sub lock {
    my $self = shift;
    my ($obj, $type) = @_;

    $type = LOCK_EX unless defined $type;

    if (!defined($self->{fh})) { return; }

    if ($self->{locking}) {
        if (!$self->{locked}) {
            flock($self->{fh}, $type);

            # refresh end counter in case file has changed size
            my @stats = stat($self->{fh});
            $self->{end} = $stats[7];

            # double-check file inode, in case another process
            # has optimize()d our file while we were waiting.
            if (defined($self->{inode}) && $stats[1] != $self->{inode}) {
                $self->close;

utils/lib/DBM/Deep/10002.pm  view on Meta::CPAN


                #XXX This needs work
                $obj->{engine}->setup_fh( $obj );

                flock($self->{fh}, $type); # re-lock

                # This may not be necessary after re-opening
                $self->{end} = (stat($self->{fh}))[7]; # re-end
            }
        }
        $self->{locked}++;

        return 1;
    }

    return;
}

##
# If db locking is set, unlock the db file.  See note in lock()
# regarding calling lock() multiple times.
##
sub unlock {
    my $self = shift;

    if (!defined($self->{fh})) { return; }

    if ($self->{locking} && $self->{locked} > 0) {
        $self->{locked}--;
        if (!$self->{locked}) { flock($self->{fh}, LOCK_UN); }

        return 1;
    }

    return;
}

sub flush {
    my $self = shift;



( run in 0.646 second using v1.01-cache-2.11-cpan-49f99fa48dc )