Skip to Content.
Sympa Menu

devel - Re: [sympa-developpers] Lock problem?

Subject: Developers of Sympa

List archive

Chronological Thread  
  • From: IKEDA Soji <address@concealed>
  • To: address@concealed
  • Subject: Re: [sympa-developpers] Lock problem?
  • Date: Mon, 5 Aug 2013 01:11:18 +0900

Hi,

Though direct use of File::NFSLock is possible, I wrote a small
module wrapping it. Some notes:

o The feature File::NFSLock argues support for NFS is anticipating
cache of filesystem. It may make lock processing a bit less
efficient on local filesystems.

o Current Sympa::Lock takes care of upgrading "read" locking to
"write" one (shared to exclusive), but it seems not to be used.
So my module doesn't implement it.

o Sympa::Lock::lock() is non-blocking, namely, it won't wait
competing lock and fails immediately. This module follows this
feature, but it can be discussed.

Regards,

--- Soji

On Tue, 23 Jul 2013 19:36:21 +0200
Guillaume Rousse <address@concealed> wrote:

> Le 23/07/2013 18:40, IKEDA Soji a écrit :
> > "Hardlink magic" (I named it) is, as I understood:
> > (1) There may be only one main lock file (i-node) by each target
> > file;
> > (2) Each proccess or routine creates a hardlink to the file above
> > so that add shared-lock to the target file, and unlink it to
> > unlock target file;
> > (3) When the main lock file does not have hardlinks anymore,
> > it is removed from filesystem by the kernel.
> >
> > - Lock file will be removed by kernel automatically.
> > - As lock files may exist independent from target files, forward
> > locking is possible.
> > - As hardlink is usual thing on Unix-like systems, it may work
> > on environmets not limited to NFS.
> Despite my initial understanding, the module name actually means
> 'NFS-compatible' locking, not 'NFS-based' locking.
>
> It seems to be light and easily readable, so I'm OK for the change. And
> a full replacement for Sympa::Lock, instead of an underlying mechanism
> for this class. As they work the same way ((maintaining a 'foo.NFSlock'
> file whose existence is enough to advertise 'foo' is currently locked),
> so I don't see much point in encapsulating it in our custom API.
>
> --
> Guillaume Rousse
> INRIA, Direction des systèmes d'information
> Domaine de Voluceau
> Rocquencourt - BP 105
> 78153 Le Chesnay
> Tel: 01 39 63 58 31
>


--
株式会社 コンバージョン セキュリティ&OSSソリューション部 池田荘児
〒231-0004 神奈川県横浜市中区元浜町3-21-2 ヘリオス関内ビル7F
e-mail address@concealed TEL 045-640-3550
http://www.conversion.co.jp/

# -*- indent-tabs-mode: t; -*-
# vim:ft=perl:noet:sw=8:textwidth=78
# $Id$

# Sympa - SYsteme de Multi-Postage Automatique
# Copyright (c) 1997, 1998, 1999, 2000, 2001 Comite Reseau des Universites
# Copyright (c) 1997,1998, 1999 Institut Pasteur & Christophe Wolfhugel
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses>.

=head1 NAME

Sympa::LockedFile - Filehandle with locking

=head1 SYNOPSIS

use Sympa::LockedFile;

# Create filehandle acquiring lock.
my $fh = Sympa::LockedFile->new('/path/to/file', 1200, '+<') or die;
# or,
my $fh = Sympa::LockedFile->new();
$fh->open('/path/to/file', 1200, '+<') or die;

# Operations...
while (<$fh>) { ... }
seek $fh, 0, 0;
truncate $fh, 0;
print $fh "blah blah\n";
# et cetera.

# Close filehandle releasing lock.
$fh->close;

=head1 DESCRIPTION

This class implements a filehadle with locking.

=cut

package Sympa::LockedFile;

use strict;
use warnings;

use Carp qw(croak);
use English qw(-no_match_vars);
use Fcntl qw(LOCK_EX LOCK_NB LOCK_SH);
use File::NFSLock;

use Sympa::Log::Syslog;

use base qw(IO::File);

our %locks;
my $default_timeout = 60 * 20; # After this period a lock can be stolen

=head2 Class Method

=over

=item Sympa::LockedFile->new ( [ $path, [ $timeout, [ $mode ] ] ] )

Creates new object.
If any of optional parameters are specified, opens a file acquiring lock.

Parameters:

See open().

Returns:

New object or, if something went wrong, false value.

=back

=head2 Instance Methods

Instance of L<Sympa::LockedFile> supports the methods provided by L<IO::File>.

=over

=item $fh->open ( $path, [ $timeout, [ $mode ] ] )

Opens a file specified by $path acquiring lock.

Parameters:

=over

=item $path

Path of file to be locked and opened.

=item $timeout

If existing lock is older than this timeout (seconds), lock will be stolen.
Default is 1200, i.e. 20 minutes.

=item $mode

Mode to open file.
If it includes any writing operations (C<'E<gt>'>, C<'E<gt>E<gt>'>,
C<'+E<lt>'>, ...), trys to acquire exclusive lock (C<LOCK_EX>),
otherwise shared lock (C<LOCK_SH>).

Default is C<'E<lt>'>.

=back

Returns:

New filehandle.
If acquiring lock failed, won't open file.
If opening file failed, releases acquired lock.
In both cases returns false value.

=back

=cut

sub open {
Sympa::Log::Syslog::do_log('debug2', '(%s, %s, %s)', @_);
my ($self, $path, $timeout, $mode) = @_;
$timeout ||= $default_timeout;
$mode ||= '<';

my $hold = 30; #FIXME: seems ignored by LOCK_NB
my $operation;
if ($mode =~ /[+>aw]/) {
$operation = LOCK_EX;
} else {
$operation = LOCK_SH;
}
my $lock = File::NFSLock->new(
$path, $operation | LOCK_NB, $hold, $timeout
);
unless ($lock) {
Sympa::Log::Syslog::do_log('err',
'Failed locking %s: %s', $path, $ERRNO
);
return undef;
}

unless ($self->SUPER::open($path, $mode)) {
Sympa::Log::Syslog::do_log('err',
'Failed opening %s: %s', $path, $ERRNO
);
$lock->unlock; # make sure unlock to occur immediately.
return undef;
}

$locks{$self+0} = $lock; # register lock object, i.e. keep locking.
return 1;
}

=over

=item $fh->close ( )

Closes filehandle and releases lock on it.

Parameters:

None.

Returns:

If close succeeded, returns true value, otherwise false value.

If filehandle had not been locked by current process,
this method will safely close filehandle and die.

=back

=cut

sub close {
Sympa::Log::Syslog::do_log('debug2', '(%s)', @_);
my ($self) = @_;

my $ret = $self->SUPER::close;

croak 'Lock not found'
unless exists $locks{$self+0};

$locks{$self+0}->unlock; # make sure unlock to occur immediately.
delete $locks{$self+0}; # lock object will be destructed.
return $ret;
}

# Destruct inside reference to lock object to release it.
# Corresponding filehandle will automatically closed.
sub DESTROY {
delete $locks{shift+0}; # lock object will be destructed.
}

1;
__END__

=head1 SEE ALSO

L<perlfunc/Functions for filehandles, files or directories>.

L<IO::File>, L<File::NFSLock>.

=head1 AUTHORS

Sympa developers and contributors.




Archive powered by MHonArc 2.6.19+.

Top of Page