Skip to content

Commit

Permalink
Switch to using File::NFSLock.
Browse files Browse the repository at this point in the history
LockFile::Simple uses some deprecated syntax, which
causes lots of warnings with newer perls.

File:NFSLock also has shared and exclusive locks,
which will come in handy.
  • Loading branch information
Jeffrey Ryan Thalhammer committed May 5, 2012
1 parent b9668a2 commit 09d094d
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 45 deletions.
4 changes: 2 additions & 2 deletions lib/Pinto.pm
Expand Up @@ -60,7 +60,7 @@ sub run {
my $action_class = $self->action_base_class . "::$action_name";
Class::Load::load_class($action_class);

$self->repos->lock;
$self->repos->lock_exclusive;
my $guard = $self->repos->db->schema->txn_scope_guard;

@args{qw(logger repos)} = ($self->logger, $self->repos);
Expand Down Expand Up @@ -101,7 +101,7 @@ sub add_logger {

#------------------------------------------------------------------------------

__PACKAGE__->meta->make_immutable();
__PACKAGE__->meta->make_immutable;

#-----------------------------------------------------------------------------

Expand Down
78 changes: 37 additions & 41 deletions lib/Pinto/Locker.pm
@@ -1,11 +1,11 @@
package Pinto::Locker;
# ABSTRACT: Manage locks to synchronize concurrent operations

# ABSTRACT: Synchronize concurrent Pinto actions
package Pinto::Locker;

use Moose;

use Path::Class;
use LockFile::Simple;
use File::NFSLock;

use Pinto::Types qw(File);
use Pinto::Exception qw(throw);
Expand All @@ -17,48 +17,29 @@ use namespace::autoclean;
# VERSION

#-----------------------------------------------------------------------------
# Moose attributes

has timeout => (
is => 'ro',
isa => 'Int',
default => 50
);


has _lock => (
is => 'rw',
isa => 'LockFile::Lock',
isa => 'File::NFSLock',
predicate => 'is_locked',
init_arg => undef,
);

has _lockmgr => (
is => 'ro',
isa => 'LockFile::Simple',
init_arg => undef,
lazy_build => 1,
);

#-----------------------------------------------------------------------------
# Moose roles

with qw( Pinto::Role::Configurable
Pinto::Role::Loggable );

#-----------------------------------------------------------------------------
# Builders

sub _build__lockmgr {
my ($self) = @_;

my $wfunc = sub { $self->debug(@_) };
my $efunc = sub { throw(@_) };

return LockFile::Simple->make( -autoclean => 1,
-efunc => $efunc,
-wfunc => $wfunc,
-stale => 1,
-nfs => 1 );
}

#-----------------------------------------------------------------------------
# Methods

=method lock()
=method lock
Attempts to get a lock on a Pinto repository. If the repository is already
locked, we will attempt to contact the current lock holder and make sure they
Expand All @@ -67,28 +48,43 @@ we patiently wait until we timeout, which is about 60 seconds.
=cut

sub lock { ## no critic (Homonym)
sub lock_exclusive {
my ($self) = @_;

my $root_dir = $self->config->root_dir;
my $root_dir = $self->root_dir;
throw "$root_dir is already locked" if $self->is_locked;

my $lock_file = $root_dir->file('.lock')->stringify;
my $lock = File::NFSLock->new($lock_file, 'EX', $self->timeout)
or throw 'Unable to lock the repository -- please try later';

$self->debug("Process $$ got exclusive lock on $root_dir");
$self->_lock($lock);

return $self;
}

#-----------------------------------------------------------------------------

sub lock_shared {
my ($self) = @_;

# If by chance, the directory we are trying to lock does not exist,
# then LockFile::Simple will wait (a while) until it does. To
# avoid this extra delay, just make sure the directory exists now.
throw "Repository $root_dir does not exist" if not -e $root_dir;
my $root_dir = $self->root_dir;
throw "$root_dir is already locked" if $self->is_locked;

my $lock = $self->_lockmgr->lock( $root_dir->file('')->stringify )
my $lock_file = $root_dir->file('.lock')->stringify;
my $lock = File::NFSLock->new($lock_file, 'SH', $self->timeout)
or throw 'Unable to lock the repository -- please try later';

$self->debug("Process $$ got the lock on $root_dir");
$self->debug("Process $$ got shared lock on $root_dir");
$self->_lock($lock);

return $self;
}

#-----------------------------------------------------------------------------

=method unlock()
=method unlock
Releases the lock on the Pinto repository so that other processes can
get to work.
Expand All @@ -100,7 +96,7 @@ sub unlock {

return $self if not $self->is_locked;

$self->_lock->release or throw 'Unable to unlock repository';
$self->_lock->unlock or throw 'Unable to unlock repository';

my $root_dir = $self->config->root_dir;
$self->debug("Process $$ released the lock on $root_dir");
Expand Down
6 changes: 4 additions & 2 deletions lib/Pinto/Repository.pm
Expand Up @@ -76,7 +76,9 @@ has cache => (
logger => $_[0]->logger ) },
);

=method lock
=method lock_shared
=method lock_exclusive
=method unlock
Expand All @@ -86,7 +88,7 @@ has locker => (
is => 'ro',
isa => 'Pinto::Locker',
lazy => 1,
handles => [ qw(lock unlock) ],
handles => [ qw(lock_shared lock_exclusive unlock) ],
default => sub { Pinto::Locker->new( config => $_[0]->config,
logger => $_[0]->logger ) },
);
Expand Down

0 comments on commit 09d094d

Please sign in to comment.