|
|
| |
Simple(3) |
User Contributed Perl Documentation |
Simple(3) |
LockFile::Simple - simple file locking scheme
use LockFile::Simple qw(lock trylock unlock);
# Simple locking using default settings
lock("/some/file") || die "can't lock /some/file\n";
warn "already locked\n" unless trylock("/some/file");
unlock("/some/file");
# Build customized locking manager object
$lockmgr = LockFile::Simple->make(-format => '%f.lck',
-max => 20, -delay => 1, -nfs => 1);
$lockmgr->lock("/some/file") || die "can't lock /some/file\n";
$lockmgr->trylock("/some/file");
$lockmgr->unlock("/some/file");
$lockmgr->configure(-nfs => 0);
# Using lock handles
my $lock = $lockmgr->lock("/some/file");
$lock->release;
This simple locking scheme is not based on any file locking system calls such as
"flock()" or
"lockf()" but rather relies on basic file
system primitives and properties, such as the atomicity of the
"write()" system call. It is not meant to be
exempt from all race conditions, especially over NFS. The algorithm used is
described below in the ALGORITHM section.
It is possible to customize the locking operations to attempt
locking once every 5 seconds for 30 times, or delete stale locks (files that
are deemed too ancient) before attempting the locking.
The locking alogrithm attempts to create a lockfile using a temporarily
redefined umask (leaving only read rights to prevent further create
operations). It then writes the process ID (PID) of the process and closes the
file. That file is then re-opened and read. If we are able to read the same
PID we wrote, and only that, we assume the locking is successful.
When locking over NFS, i.e. when the one of the potentially
locking processes could access the lockfile via NFS, then writing the
PID is not enough. We also write the hostname where locking is attempted to
ensure the data are unique.
Customization is only possible by using the object-oriented interface, since the
configuration parameters are stored within the object. The object creation
routine "make" can be given configuration
parmeters in the form a "hash table list", i.e. a list of key/value
pairs. Those parameters can later be changed via
"configure" by specifying a similar list of
key/value pairs.
To benefit from the bareword quoting Perl offers, all the
parameters must be prefixed with the "-"
(minus) sign, as in "-format" for the
format parameter.. However, when querying the object, the minus must
be omitted, as in "$obj->format".
Here are the available configuration parmeters along with their
meaning, listed in alphabetical order:
- autoclean
- When true, all locks are remembered and pending ones are automatically
released when the process exits normally (i.e. whenever Perl calls the END
routines).
- delay
- The amount of seconds to wait between locking attempts when the file
appears to be already locked. Default is 2 seconds.
- efunc
- A function pointer to dereference when an error is to be reported. By
default, it redirects to the logerr() routine if you have
Log::Agent installed, to Perl's warn() function otherwise.
You may set it explicitely to
"\&LockFile::Simple::core_warn" to
force the use of Perl's warn() function, or to
"undef" to suppress logging.
- ext
- The locking extension that must be added to the file path to be locked to
compute the lockfile path. Default is
".lock" (note that
"." is part of the extension and can
therefore be changed). Ignored when format is also used.
- format
- Using this parmeter supersedes the ext parmeter. The formatting
string specified is run through a rudimentary macro expansion to derive
the lockfile path from the file to be locked. The following macros
are available:
%% A real % sign
%f The full file path name
%D The directory where the file resides
%F The base name of the file
%p The process ID (PID)
The default is to use the locking extension, which itself is
".lock", so it is as if the format
used was "%f.lock", but one could
imagine things like "/var/run/%F.%p",
i.e. the lockfile does not necessarily lie besides the locked
file (which could even be missing).
When locking, the locking format can be specified to supersede
the object configuration itself.
- hold
- Maximum amount of seconds we may hold a lock. Past that amount of time, an
existing lockfile is removed, being taken for a stale lock. Default
is 3600 seconds. Specifying 0 prevents any forced unlocking.
- max
- Amount of times we retry locking when the file is busy, sleeping
delay seconds between attempts. Defaults to 30.
- nfs
- A boolean flag, false by default. Setting it to true means we could lock
over NFS and therefore the hostname must be included along with the
process ID in the stamp written to the lockfile.
- stale
- A boolean flag, false by default. When set to true, we attempt to detect
stale locks and break them if necessary.
- wafter
- Stands for warn after. It is the number of seconds past the first
warning during locking time after which a new warning should be emitted.
See warn and wmin below. Default is 20.
- warn
- A boolean flag, true by default. To suppress any warning, set it to
false.
- wfunc
- A function pointer to dereference when a warning is to be issued. By
default, it redirects to the logwarn() routine if you have
Log::Agent installed, to Perl's warn() function otherwise.
You may set it explicitely to
"\&LockFile::Simple::core_warn" to
force the use of Perl's warn() function, or to
"undef" to suppress logging.
- wmin
- The minimal amount of time when waiting for a lock after which a first
warning must be emitted, if warn is true. After that, a warning
will be emitted every wafter seconds. Defaults to 15.
Each of those configuration attributes can be queried on the
object directly:
$obj = LockFile::Simple->make(-nfs => 1);
$on_nfs = $obj->nfs;
Those are pure query routines, i.e. you cannot say:
$obj->nfs(0); # WRONG
$obj->configure(-nfs => 0); # Right
to turn of the NFS attribute. That is because my OO background
chokes at having querying functions with side effects.
The OO interface documented below specifies the signature and the semantics of
the operations. Only the "lock",
"trylock" and
"unlock" operation can be imported and used
via a non-OO interface, with the exact same signature nonetheless.
The interface contains all the attribute querying routines, one
for each configuration parmeter documented in the CUSTOMIZING section
above, plus, in alphabetical order:
- configure(-key => value, -key2 => value2, ...)
- Change the specified configuration parameters and silently ignore the
invalid ones.
- lock(file, format)
- Attempt to lock the file, using the optional locking format if
specified, otherwise using the default format scheme configured in
the object, or by simply appending the ext extension to the file.
If the file is already locked, sleep delay seconds
before retrying, repeating try/sleep at most max times. If
warning is configured, a first warning is emitted after waiting for
wmin seconds, and then once every wafter seconds, via the
wfunc routine.
Before the first attempt, and if hold is non-zero, any
existing lockfile is checked for being too old, and it is removed
if found to be stale. A warning is emitted via the wfunc routine
in that case, if allowed.
Likewise, if stale is non-zero, a check is made to see
whether any locking process is still around (only if the lock holder is
on the same machine when NFS locking is configured). Should the locking
process be dead, the lockfile is declared stale and removed.
Returns a lock handle if the file has been successfully
locked, which does not necessarily needs to be kept around. For
instance:
$obj->lock('ppp', '/var/run/ppp.%p');
<do some work>
$obj->unlock('ppp');
or, using OO programming:
my $lock = $obj->lock('ppp', '/var/run/ppp.%p') ||;
die "Can't lock for ppp\n";
<do some work>
$lock->relase; # The only method defined for a lock handle
i.e. you don't even have to know which file was locked to
release it, since there is a lock handle right there that knows enough
about the lock parameters.
- lockfile(file, format)
- Simply compute the path of the lockfile that would be used by the
lock procedure if it were passed the same parameters.
- make(-key => value, -key2 => value2, ...)
- The creation routine for the simple lock object. Returns a blessed hash
reference.
- trylock(file, format)
- Same as lock except that it immediately returns false and does not
sleep if the to-be-locked file is busy, i.e. already locked. Any stale
locking file is removed, as lock would do anyway.
Returns a lock hande if the file has been successfully
locked.
- unlock(file)
- Unlock the file.
The algorithm is not bullet proof. It's only reasonably safe. Don't bet the
integrity of a mission-critical database on it though.
The sysopen() call should probably be used with the
"O_EXCL|O_CREAT" flags to be on the safer
side. Still, over NFS, this is not an atomic operation anyway.
BEWARE: there is a race condition between the time we
decide a lock is stale or too old and the time we unlink it. Don't use
"-stale" and set
"-hold" to 0 if you can't bear with that
idea, but recall that this race only happens when something is already
wrong. That does not make it right, nonetheless. ;-)
Raphael Manfredi <Raphael_Manfredi@pobox.com>
Visit the GSP FreeBSD Man Page Interface. Output converted with ManDoc. |