Subject: Developers of Sympa
List archive
- From: IKEDA Soji <address@concealed>
- To: address@concealed
- Subject: Re: [sympa-developpers] Lock problem?
- Date: Wed, 20 Nov 2013 14:00:47 +0900
Hi,
On Tue, 06 Aug 2013 16:29:20 +0200
Guillaume Rousse <address@concealed> wrote:
> Le 04/08/2013 18:11, IKEDA Soji a écrit :
> > 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.
> That's easy to wrap a non-blocking function to make it blocking, that's
> easier to do the opposite direction, so I prefer this way.
>
> There is a primitive t/lock.t test suite I used when refactoring
> Sympa::Lock, feel free to adapt it to test your new implementation.
I wrote testcases copying your example t/lock.t.
And new LockedFile.pm fixed problems:
- Mix-up between blocking timeout and stale lock timeouts.
- Locking was always non-blocking (LOCK_NB was always enabled).
Regards,
--- Soji
--
株式会社 コンバージョン セキュリティ&OSSソリューション部 池田荘児
〒231-0004 神奈川県横浜市中区元浜町3-21-2 ヘリオス関内ビル7F
e-mail address@concealed TEL 045-640-3550
http://www.conversion.co.jp/
# Sympa - SYsteme de Multi-Postage Automatique # # Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel # Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites # Copyright (c) 2011, 2012, 2013 GIP RENATER # # 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/>. 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; $File::NFSLock::LOCK_EXTENSION = '.lock'; use Sympa::Log::Syslog; use base qw(IO::File); our %lock_of; my $default_timeout = 30; my $stale_lock_timeout = 20 * 60; # TODO should become a config parameter sub open { Sympa::Log::Syslog::do_log( 'debug2', '(%s, %s, %s, %s)', @_ ); my ( $self, $file, $blocking_timeout, $mode ) = @_; $blocking_timeout ||= $default_timeout; $mode ||= '<'; my $lock_type; if ( $mode =~ /[+>aw]/ ) { $lock_type = LOCK_EX; } else { $lock_type = LOCK_SH; } if ( $blocking_timeout < 0 ) { $lock_type |= LOCK_NB; } my $lock = File::NFSLock->new( { file => $file, lock_type => $lock_type, blocking_timeout => $blocking_timeout, stale_lock_timeout => $stale_lock_timeout, } ); unless ($lock) { Sympa::Log::Syslog::do_log( 'err', 'Failed locking %s: %s', $file, $ERRNO ); return undef; } unless ( $self->SUPER::open( $file, $mode ) ) { Sympa::Log::Syslog::do_log( 'err', 'Failed opening %s: %s', $file, $ERRNO ); $lock->unlock; # make sure unlock to occur immediately. return undef; } $lock_of{ $self + 0 } = $lock; # register lock object, i.e. keep locking. return 1; } sub close { Sympa::Log::Syslog::do_log( 'debug2', '(%s)', @_ ); my ($self) = @_; my $ret = $self->SUPER::close; croak 'Lock not found' unless exists $lock_of{ $self + 0 }; $lock_of{ $self + 0 }->unlock; # make sure unlock to occur immediately. delete $lock_of{ $self + 0 }; # lock object will be destructed. return $ret; } # Destruct inside reference to lock object so that it will be released. # Corresponding filehandle will be closed automatically. sub DESTROY { my ($self) = @_; delete $lock_of{ $self + 0 }; # lock object will be destructed. } 1; __END__ =encoding us-ascii =head1 NAME Sympa::LockedFile - Filehandle with locking =head1 SYNOPSIS use Sympa::LockedFile; # Create filehandle acquiring lock. my $fh = Sympa::LockedFile->new('/path/to/file', 20, '+<') or die; # or, my $fh = Sympa::LockedFile->new(); $fh->open('/path/to/file', 20, '+<') 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. =head2 Class Method =over =item Sympa::LockedFile->new ( [ $file, [ $blocking_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 Instances of L<Sympa::LockedFile> support the methods provided by L<IO::File>. =over =item $fh->open ( $file, [ $blocking_timeout, [ $mode ] ] ) Opens a file specified by $file acquiring lock. Parameters: =over =item $file Path of file to be locked and opened. =item $blocking_timeout Programs will block up to the number of seconds specified by this option before returning undef (could not get a lock). If negative value was given, programs will not block but fail immediately. Default is C<30>. However, if existing lock is older than 1200 seconds i.e. 20 minutes, lock will be stolen. =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 =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 it and die. =back =head1 SEE ALSO L<perlfunc/"Functions for filehandles, files or directories">, L<perlop/"I/O Operators">, L<IO::File>, L<File::NFSLock>. =head1 AUTHORS L<Sympa::LockedFile> was initially wrote by: IKEDA Soji <address@concealed>. =cut
Attachment:
LockedFile.t
Description: Troff document
- Re: [sympa-developpers] Lock problem?, IKEDA Soji, 11/20/2013
Archive powered by MHonArc 2.6.19+.