AnyEvent-FileLock
view release on metacpan or search on metacpan
lib/AnyEvent/FileLock.pm view on Meta::CPAN
if (defined $file) {
my $open_mode = delete $opts{open_mode} // $mode;
$open_mode =~ /^\+?(?:<|>>?)/ or croak "bad mode specification";
open $fh, $mode, $file or return
}
else {
$fh = delete $opts{fh} // croak "file or fh argument is required";
}
my $self = { file => $file,
fh => $fh,
type => $type,
max_time => $max_time,
user_cb => $user_cb,
delay => $delay };
bless $self, $class;
if ($type eq 'fcntl') {
$self->{$_} = delete($opts{lock_start}) // 0
for qw(lock_start lock_whence lock_len);
$self->{operation} = ($lock_mode eq '<' ? Fcntl::F_RDLCK() : Fcntl::F_WRLCK());
}
else {
$self->{operation} = ($lock_mode eq '<' ? Fcntl::LOCK_SH() : Fcntl::LOCK_EX());
}
%opts and croak "unkwnown arguments found (".join(', ', sort keys %opts).")";
my $alcb = $self->{acquire_lock_cb} = weak_method_callback($self, '_acquire_lock');
&AE::postpone($alcb);
$self;
}
sub _acquire_lock {
my $self = shift;
my $operation = $self->{opertation};
my $now = AE::now;
my $ok;
if ($self->{type} eq 'flock') {
$ok = CORE::flock($self->{fh}, $self->{operation}|Fcntl::LOCK_NB());
}
else {
require Fcntl::Packer;
my %flock = (type => $self->{operation});
$flock{$_} = $self->{"lock_$_"} for qw(whence start len);
$ok = fcntl($self->{fh}, Fcntl::F_SETLK, Fcntl::Packer::pack_fcntl_flock(\%flock));
}
if ($ok) {
$self->{user_cb}->($self->{fh});
}
elsif ($! == Errno::EAGAIN() and
(!defined($self->{max_time}) or $self->{max_time} >= $now)) {
# we add some randomness into the delay to avoid the case
# where all the contenders follow exactly the same pattern so
# that they end looking for the pattern all at once every time
# (and obviosly all but one failing).
$self->{timer} = &AE::timer($self->{delay} * (0.8 + rand 0.40), 0, $self->{acquire_lock_cb});
return;
}
else {
$self->{user_cb}->();
}
# release all the references, the object is useless from this
# point on time.
%$self = ();
}
1;
__END__
=head1 NAME
AnyEvent::FileLock - Lock files asynchronously
=head1 SYNOPSIS
use AnyEvent::FileLock;
my $w = AnyEvent::FileLock->flock(file => $fn,
cb => sub { ... },
mode => '<',
delay => $seconds,
timeout => $timeout);
=head1 DESCRIPTION
This module tries to lock some file repeatedly until it success or a
timeout happens.
=head2 API
The function provides a unique method C<flock> accepting the following
arguments:
=over 4
=item fh => $file_handle
When this argument is given the passed file handle is used as the file
locking target.
=item file => $file_name
When this argument is given a file with the given name will be opened
or created and then the module will try to lock it.
=item type => $lock_type
C<$lock_type> may be C<fcntl> or C<flock> and determines the way used
to obtain the lock under the hood.
The default is C<flock>.
In order to use locks of type C<fcntl>, the module L<Fctnl::Packer>
has to be also installed.
( run in 0.790 second using v1.01-cache-2.11-cpan-efa8479b9fe )