NAME
Dir::Flock - advisory locking of a dedicated directory
VERSION
0.08
SYNOPSIS
use Dir::Flock;
my $dir = Dir::Flock::getDir("/home/mob/projects/foo");
my $success = Dir::Flock::lock($dir);
# ... synchronized code
$success = Dir::Flock::unlock($dir);
# flock semantics
use Fcntl ':flock';
$success = Dir::Flock::flock($dir, LOCK_EX | LOCK_NB);
...
Dir::Flock::flock($dir, LOCK_UN);
# mutex/scoping semantics
{
my $lock = Dir::Flock::lockobj($dir);
... synchronized code ...
} # lock released when $lock goes out of scope
# code ref semantics
Dir::Flock::sync {
... synchronized code ...
}, $dir
DESCRIPTION
Dir::Flock
implements advisory locking of a directory. The use case is to execute synchronized code (code that should only be executed by one process or thread at a time) or provide exclusive access to a file or other resource. Dir::Flock
has more overhead than some of the other synchronization techniques available to Perl programmers, but it might be the only technique that works on NFS (Networked File System).
Algorithm
File locking is difficult on NFS because, as I understand it, each node maintains a cache that includes file contents and file metadata. When a system call wants to check whether a lock exists on a file, the filesystem driver might inspect the cached file rather than the file on the server, and it might miss an action taken by another node to lock a file.
The cache is not used, again, as I understand it, when the filesystem driver reads a directory. If advisory locking is accomplished through reading the contents of a directory, it will not be affected by NFS's caching behavior.
To acquire a lock in a directory, this module writes a small file into the directory. Then it checks if this new file is the "oldest" file in the directory. If it is the oldest file, then the process has acquired the lock. If there is already an older file in the directory, than that file specifies what process has a lock on the directory, and we have to wait and try again later. To unlock the directory, the module simply deletes the file in the directory that represents its lock.
Semantics
This module offers several different semantics for advisory locking of a directory.
functional semantics
The core Dir::Flock::lock and Dir::Flock::unlock functions begin and end advisory locking on a directory. All of the other semantics are implemented in terms of these functions.
$ok = Dir::Flock::lock( "/some/path" );
$ok = Dir::Flock::lock( "/some/path", $timeout );
$ok = Dir::Flock::unlock( "/some/path" );
flock semantics
The function Dir::Flock::flock emulates the Perl flock builtin, accepting the same arguments for the operation argument.
use Fcntl ':flock';
$ok = Dir::Flock::flock( "/some/path", LOCK_EX );
...
$ok = Dir::Flock::flock( "/some/path", LOCK_UN );
scope-oriented semantics
The Dir::Flock::lockobj function returns an object representing a directory lock. The lock is released when the object goes out of scope.
{
my $lock = Dir::Flock::lockobj( "/some/path" );
...
} # $lock out of scope, lock released
BLOCK semantics
The Dir::Flock::sync accepts a block of code or other code reference, to be executed with an advisory lock on a directory.
Dir::Flock::sync {
... synchronized code ...
} "/some/path";
FUNCTIONS
Most functions return a false value and set the package variable $Dir::Flock::errstr
if they are unsuccessful.
lock
lock_ex
$success = Dir::Flock::lock( $directory [, $timeout ] )
$success = Dir::Flock::lock_ex( $directory [, $timeout ] )
Attempts to obtain an exclusive lock on the given directory. While the directory is locked, the lock
or lock_sh
call on the same directory from other processes or threads will block until the directory is unlocked (see "unlock"). Returns true if the lock was successfully acquired.
If an optional $timeout
argument is provided, the function will try for at least $timeout
seconds to acquire the lock, and return a false value if it is not successful in that time. Use a timeout of zero to make a "non-blocking" exclusive lock request.
lock_sh
$success = Dir::Flock::lock_sh( $directory [, $timeout ] )
Attempts to obtain a shared lock on the given directory. While there are shared locks on a directory, other calls to lock_sh
may also receive a shared lock on the directory but calls to lock
/lock_ex
on the directory will block until all shared locks are removed.
If an optional $timeout
argument is provided, the function will try for at least $timeout
seconds to acquire the lock, and return a false value if it is not successful in that time. Use a timeout of zero to make a "non-blocking" shared lock request.
unlock
$success = Dir::Flock::unlock( $directory )
Releases the exclusive or shared lock on the given directory held by this process. Returns a false value if the current process did not possess the lock on the directory.
getDir
$tmp_directory = Dir::Flock::getDir( $root )
Creates a temporary and empty directory in a subdirectory of $root
that is suitable for use as a synchronization directory. The directory will automatically be cleaned up when the process that called this function exits.
If the input to getDir
is a filename rather than a directory name, a new subdirectory will be created in the directory where the file is located.
flock
$success = Dir::Flock::flock( $dir, $op )
Acquires and releases advisory locks on the given directory with the same semantics as the Perl builtin flock function.
lockobj
lockobj_ex
$lock = Dir::Flock::lockobj( $dir [, $timeout] );
$lock = Dir::Flock::lockobj_ex( $dir [, $timeout] );
Attempts to acquire an exclusive advisory lock for the given directory. On success, returns a handle to the directory lock with the feature that the lock will be released when the handle goes out of scope. This allows you to use this module with syntax such as
{
my $lock = Dir::Flock::lockobj( "/some/path" );
... synchronized code ...
}
# $lock out of scope, so directory lock released
... unsynchronized code ...
Optional $timeout
argument causes the function to block for a maximum of $timeout
seconds attempting to acquire the lock. If $timeout
is not provided or is undef
, the function will block indefinitely while waiting for the lock.
Returns a false value and may sets $Dir::Flock::errstr
if the function times out or is otherwise unable to acquire the directory lock.
lockobj_ex
is an alias for lockobj
.
lockobj_sh
my $lock = Dir::Flock::lockobj_sh($dir [, $timeout])
Analogue to "lockobj_ex". Returns a reference to a shared lock on a directory that will be released when the reference goes out of scope.
Returns a false value and may set $Dir::Flock::errstr
if the function times out or otherwise fails to acquire a shared lock on the directory.
sync
sync_ex
$result = Dir::Flock::sync CODE $dir [, $timeout]
@result = Dir::Flock::sync_ex CODE $dir [, $timeout]
Semantics for executing a block of code while there is an advisory exclusive lock on the given directory. The code can be evaluated in both scalar or list contexts. An optional $timeout
argument will cause the function to give up and return a false value if the lock cannot be acquired after $timeout
seconds. Callers should be careful to distinguish cases where the specified code reference returns nothing and where the sync
function times out and returns nothing. One way to distinguish these cases is to check the value of $Dir::Flock::errstr
, which will generally be set if there was an issue with the locking mechanics.
The lock is released in the event that the given $code
produces a fatal error.
sync_sh
$result = Dir::Flock::sync_sh BLOCK $dir [, $timeout]
@result = Dir::Flock::sync_sh BLOCK $dir [, $timeout]
Analogue of "sync_ex" but executes the code block while there is an advisory shared lock on the given directory.
DEPENDENCIES
Dir::Flock
requires Time::HiRes where the Time::HiRes::time
function has subsection resolution.
EXPORTS
Nothing is exported from Dir::Flock
by default, but all of the functions documented here may be exported by name.
Many of the core functions of Dir::Flock
have the same name as Perl builtin functions or functions from other popular modules, so users should be wary of importing functions from this module into their working namespace.
VARIABLES
PAUSE_LENGTH
$Dir::Flock::PAUSE_LENGTH
$Dir::Flock::PAUSE_LENGTH
is the average number of seconds that the module will wait after a failed attempt to acquire a lock before attempting to acquire it again. The default value is 0.001, which is a good setting for having a high throughput when the synchronized operations take a short amount of time. In contexts where the synchronized operations take a longer time, it may be appropriate to increase this value to reduce busy-waiting CPU utilization.
LIMITATIONS
See "System requirements" above.
The Dir::Flock::Mock module can be loaded when necessary to provide a consistent synchronization API on systems that require Dir::Flock
to work properly and on systems that don't support Dir::Flock
.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc Dir::Flock
You can also look for information at:
CPAN Ratings
<mob@cpan.org>
With the decommissioning of http://rt.cpan.org/, please send bug reports and feature requests directly to the author's email address.
AUTHOR
Marty O'Brien, <mob@cpan.org>
LICENSE AND COPYRIGHT
Copyright (c) 2019-2020, Marty O'Brien
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.
See http://dev.perl.org/licenses/ for more information.