File::Lock::Multi - Lock files more than once
use File::Lock::Multi::Fuser; my $lock = File::Lock::Multi::Fuser->new(name => "/path/to/file", max => 3); $lock->lock or die; # no more than 3 locks have been taken out on "/path/to/file" [...]
flock() (and co-operative locks in general) are a handy tool used for various synchronization tasks;
- ensuring a daemon/process may only have one copy running at once
- "waiting in line" for your turn to write to a file
- flagging that a certain process, or a certain part of a process is running
POSIX supports the concept of "exclusive" ("write") and "shared" ("read") locks on files -- many processes may take out a "shared" lock on any particular file, but only one process may have an "exclusive" lock, and that process can not take out this lock unless there are no "shared" locks open.
Part of what makes this such an effective and worry-free system, is that these locks are maintained on the kernel level -- so if you kill off a process, you do not need to be concerned that the locks it had will stick around and get in some other process's way.
... But let's say you have a CPU-intensive operation that you want to limit to, oh, 5 running copies at a time? Or 3 different types of CPU-intensive operation that you want to collectively limit to 2 running copies at a time? You could keep a counter somewhere, but if processes are killed off manually, what is going to come along and decrement your counter?
"exclusive" locks are just that -- exclusive -- and there is no simple way to tell how many processes have taken out a "shared" lock on a file (from perl, anyway).
File::Lock::Multi is designed to work around this problem by providing it's own type of "locks" that behave like POSIX "exclusive" locks, except that you can specify how many locks are allowed to be taken out. So long as each process agrees on the maximum number of locks, they can work in parallel, but within the limits you have specified.
There are three locking mechanisms available; File::Lock::Multi::Fuser allows you to have multi-locks using just one file, but only works on linux and has some drawbacks (see the documentation for details); File::Lock::Multi::FlockFiles uses the
flock() call on several files named after the file you specify in order to emulate allowing more than one lock. File::Lock::Multi::MySQL allows you to use a MySQL backend to take out multiple locks on a resource that is shared across multiple servers, using MySQL's GET_LOCK function.
- new(param => 'value', ...)
Creates a new
File::Lock::Multiobject, which will represent a lock on a file. Once you have an object, you can attempt to aquire a lock with the "lock" method; the lock will be relinquished when you call the "release" method, or when the object falls out of scope.
"new" takes the following parameters; only "file" is required:
The name of the resource you wish to lock; this parameter is required. When dealing with files, if the file does not already exist, a zero-byte file will be created when you attempt to acquire the lock with "lock".
This parameter is required.
The maximum number of lockers that may lock this file.
How long to wait to acquire the lock, in seconds. A value of zero means don't wait at all, and a negative value means to wait forever (block).
Default: -1 (wait forever).
How often to check if the lock is available when waiting, in seconds. For example, if "timeout" was set to "5", and "polling_interval" was set to "0.5",
File::Lock::Multiwould try to obtain the lock every half a second, up to a maximum of five seconds, before giving up.
Default: 0.2 (1/5th of a second).
This method actually works by taking out the lock anyway, and then checking if there are too many lockers -- if there are too many lockers, it releases the lock, and optionally waits for "polling_interval" and tries again.
$timeoutis specified, this overrides the object's default.
Returns a true value if an attempt to take out the lock would succeed. This method works by calling "lock" with a timeout of zero (non-blocking), then immediately releases the lock if it obtained one.
Returns true if this lock is active, false otherwise.
Release a lock if we have taken one out. Raises an exception if we have not.
Returns an array with an entry for each entity that has locked this file. Presumedly each entry in the array is some sort of identifier indicating _who_ has locked this file, but that would be implementation specific. :-)
Copyright 2010 Tyler "Crackerjack" MacDonald <email@example.com>
This is free software; You may distribute it under the same terms as perl itself.
File::Lock::Multi::Fuser for technical details about the linux /proc implementation.
File::Lock::Multi::FlockFiles for technical details about the multiple-file implementation.
l<File::Lock::Multi::MySQL> for technical details about the MySQL implementation.
IPC::Locker for a network-based locking solution that may help if you don't want to use MySQL for distributed locking ("Multiple locks may be requested, in which case the first lock to be free will be used.")