.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .el \{\ . de IX .. .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Simple 3pm" .TH Simple 3pm "2012-06-08" "perl v5.14.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" LockFile::Simple \- simple file locking scheme .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& use LockFile::Simple qw(lock trylock unlock); \& \& # Simple locking using default settings \& lock("/some/file") || die "can\*(Aqt lock /some/file\en"; \& warn "already locked\en" unless trylock("/some/file"); \& unlock("/some/file"); \& \& # Build customized locking manager object \& $lockmgr = LockFile::Simple\->make(\-format => \*(Aq%f.lck\*(Aq, \& \-max => 20, \-delay => 1, \-nfs => 1); \& \& $lockmgr\->lock("/some/file") || die "can\*(Aqt lock /some/file\en"; \& $lockmgr\->trylock("/some/file"); \& $lockmgr\->unlock("/some/file"); \& \& $lockmgr\->configure(\-nfs => 0); \& \& # Using lock handles \& my $lock = $lockmgr\->lock("/some/file"); \& $lock\->release; .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" This simple locking scheme is not based on any file locking system calls such as \f(CW\*(C`flock()\*(C'\fR or \f(CW\*(C`lockf()\*(C'\fR but rather relies on basic file system primitives and properties, such as the atomicity of the \f(CW\*(C`write()\*(C'\fR system call. It is not meant to be exempt from all race conditions, especially over \&\s-1NFS\s0. The algorithm used is described below in the \fB\s-1ALGORITHM\s0\fR section. .PP 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. .SH "ALGORITHM" .IX Header "ALGORITHM" The locking alogrithm attempts to create a \fIlockfile\fR using a temporarily redefined \fIumask\fR (leaving only read rights to prevent further create operations). It then writes the process \s-1ID\s0 (\s-1PID\s0) of the process and closes the file. That file is then re-opened and read. If we are able to read the same \s-1PID\s0 we wrote, and only that, we assume the locking is successful. .PP When locking over \s-1NFS\s0, i.e. when the one of the potentially locking processes could access the \fIlockfile\fR via \s-1NFS\s0, then writing the \s-1PID\s0 is not enough. We also write the hostname where locking is attempted to ensure the data are unique. .SH "CUSTOMIZING" .IX Header "CUSTOMIZING" Customization is only possible by using the object-oriented interface, since the configuration parameters are stored within the object. The object creation routine \f(CW\*(C`make\*(C'\fR can be given configuration parmeters in the form a \*(L"hash table list\*(R", i.e. a list of key/value pairs. Those parameters can later be changed via \f(CW\*(C`configure\*(C'\fR by specifying a similar list of key/value pairs. .PP To benefit from the bareword quoting Perl offers, all the parameters must be prefixed with the \f(CW\*(C`\-\*(C'\fR (minus) sign, as in \f(CW\*(C`\-format\*(C'\fR for the \fIformat\fR parameter.. However, when querying the object, the minus must be omitted, as in \f(CW\*(C`$obj\->format\*(C'\fR. .PP Here are the available configuration parmeters along with their meaning, listed in alphabetical order: .IP "\fIautoclean\fR" 4 .IX Item "autoclean" When true, all locks are remembered and pending ones are automatically released when the process exits normally (i.e. whenever Perl calls the \&\s-1END\s0 routines). .IP "\fIdelay\fR" 4 .IX Item "delay" The amount of seconds to wait between locking attempts when the file appears to be already locked. Default is 2 seconds. .IP "\fIefunc\fR" 4 .IX Item "efunc" A function pointer to dereference when an error is to be reported. By default, it redirects to the \fIlogerr()\fR routine if you have Log::Agent installed, to Perl's \fIwarn()\fR function otherwise. .Sp You may set it explicitly to \f(CW\*(C`\e&LockFile::Simple::core_warn\*(C'\fR to force the use of Perl's \fIwarn()\fR function, or to \f(CW\*(C`undef\*(C'\fR to suppress logging. .IP "\fIext\fR" 4 .IX Item "ext" The locking extension that must be added to the file path to be locked to compute the \fIlockfile\fR path. Default is \f(CW\*(C`.lock\*(C'\fR (note that \f(CW\*(C`.\*(C'\fR is part of the extension and can therefore be changed). Ignored when \fIformat\fR is also used. .IP "\fIformat\fR" 4 .IX Item "format" Using this parmeter supersedes the \fIext\fR parmeter. The formatting string specified is run through a rudimentary macro expansion to derive the \&\fIlockfile\fR path from the file to be locked. The following macros are available: .Sp .Vb 5 \& %% 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) .Ve .Sp The default is to use the locking extension, which itself is \f(CW\*(C`.lock\*(C'\fR, so it is as if the format used was \f(CW\*(C`%f.lock\*(C'\fR, but one could imagine things like \f(CW\*(C`/var/run/%F.%p\*(C'\fR, i.e. the \fIlockfile\fR does not necessarily lie besides the locked file (which could even be missing). .Sp When locking, the locking format can be specified to supersede the object configuration itself. .IP "\fIhold\fR" 4 .IX Item "hold" Maximum amount of seconds we may hold a lock. Past that amount of time, an existing \fIlockfile\fR is removed, being taken for a stale lock. Default is 3600 seconds. Specifying 0 prevents any forced unlocking. .IP "\fImax\fR" 4 .IX Item "max" Amount of times we retry locking when the file is busy, sleeping \fIdelay\fR seconds between attempts. Defaults to 30. .IP "\fInfs\fR" 4 .IX Item "nfs" A boolean flag, false by default. Setting it to true means we could lock over \s-1NFS\s0 and therefore the hostname must be included along with the process \&\s-1ID\s0 in the stamp written to the lockfile. .IP "\fIstale\fR" 4 .IX Item "stale" A boolean flag, false by default. When set to true, we attempt to detect stale locks and break them if necessary. .IP "\fIwafter\fR" 4 .IX Item "wafter" Stands for \fIwarn after\fR. It is the number of seconds past the first warning during locking time after which a new warning should be emitted. See \fIwarn\fR and \fIwmin\fR below. Default is 20. .IP "\fIwarn\fR" 4 .IX Item "warn" A boolean flag, true by default. To suppress any warning, set it to false. .IP "\fIwfunc\fR" 4 .IX Item "wfunc" A function pointer to dereference when a warning is to be issued. By default, it redirects to the \fIlogwarn()\fR routine if you have Log::Agent installed, to Perl's \fIwarn()\fR function otherwise. .Sp You may set it explicitly to \f(CW\*(C`\e&LockFile::Simple::core_warn\*(C'\fR to force the use of Perl's \fIwarn()\fR function, or to \f(CW\*(C`undef\*(C'\fR to suppress logging. .IP "\fIwmin\fR" 4 .IX Item "wmin" The minimal amount of time when waiting for a lock after which a first warning must be emitted, if \fIwarn\fR is true. After that, a warning will be emitted every \fIwafter\fR seconds. Defaults to 15. .PP Each of those configuration attributes can be queried on the object directly: .PP .Vb 2 \& $obj = LockFile::Simple\->make(\-nfs => 1); \& $on_nfs = $obj\->nfs; .Ve .PP Those are pure query routines, i.e. you cannot say: .PP .Vb 2 \& $obj\->nfs(0); # WRONG \& $obj\->configure(\-nfs => 0); # Right .Ve .PP to turn of the \s-1NFS\s0 attribute. That is because my \s-1OO\s0 background chokes at having querying functions with side effects. .SH "INTERFACE" .IX Header "INTERFACE" The \s-1OO\s0 interface documented below specifies the signature and the semantics of the operations. Only the \f(CW\*(C`lock\*(C'\fR, \f(CW\*(C`trylock\*(C'\fR and \&\f(CW\*(C`unlock\*(C'\fR operation can be imported and used via a non-OO interface, with the exact same signature nonetheless. .PP The interface contains all the attribute querying routines, one for each configuration parmeter documented in the \fB\s-1CUSTOMIZING\s0\fR section above, plus, in alphabetical order: .IP "configure(\fI\-key => value, \-key2 => value2, ...\fR)" 4 .IX Item "configure(-key => value, -key2 => value2, ...)" Change the specified configuration parameters and silently ignore the invalid ones. .IP "lock(\fIfile\fR, \fIformat\fR)" 4 .IX Item "lock(file, format)" Attempt to lock the file, using the optional locking \fIformat\fR if specified, otherwise using the default \fIformat\fR scheme configured in the object, or by simply appending the \fIext\fR extension to the file. .Sp If the file is already locked, sleep \fIdelay\fR seconds before retrying, repeating try/sleep at most \fImax\fR times. If warning is configured, a first warning is emitted after waiting for \fIwmin\fR seconds, and then once every \fIwafter\fR seconds, via the \fIwfunc\fR routine. .Sp Before the first attempt, and if \fIhold\fR is non-zero, any existing \&\fIlockfile\fR is checked for being too old, and it is removed if found to be stale. A warning is emitted via the \fIwfunc\fR routine in that case, if allowed. .Sp Likewise, if \fIstale\fR 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 \s-1NFS\s0 locking is configured). Should the locking process be dead, the \fIlockfile\fR is declared stale and removed. .Sp Returns a lock handle if the file has been successfully locked, which does not necessarily needs to be kept around. For instance: .Sp .Vb 3 \& $obj\->lock(\*(Aqppp\*(Aq, \*(Aq/var/run/ppp.%p\*(Aq); \& \& $obj\->unlock(\*(Aqppp\*(Aq); .Ve .Sp or, using \s-1OO\s0 programming: .Sp .Vb 4 \& my $lock = $obj\->lock(\*(Aqppp\*(Aq, \*(Aq/var/run/ppp.%p\*(Aq) ||; \& die "Can\*(Aqt lock for ppp\en"; \& \& $lock\->relase; # The only method defined for a lock handle .Ve .Sp 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. .IP "lockfile(\fIfile\fR, \fIformat\fR)" 4 .IX Item "lockfile(file, format)" Simply compute the path of the \fIlockfile\fR that would be used by the \&\fIlock\fR procedure if it were passed the same parameters. .IP "make(\fI\-key => value, \-key2 => value2, ...\fR)" 4 .IX Item "make(-key => value, -key2 => value2, ...)" The creation routine for the simple lock object. Returns a blessed hash reference. .IP "trylock(\fIfile\fR, \fIformat\fR)" 4 .IX Item "trylock(file, format)" Same as \fIlock\fR 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 \fIlock\fR would do anyway. .Sp Returns a lock hande if the file has been successfully locked. .IP "unlock(\fIfile\fR)" 4 .IX Item "unlock(file)" Unlock the \fIfile\fR. .SH "BUGS" .IX Header "BUGS" The algorithm is not bullet proof. It's only reasonably safe. Don't bet the integrity of a mission-critical database on it though. .PP The \fIsysopen()\fR call should probably be used with the \f(CW\*(C`O_EXCL|O_CREAT\*(C'\fR flags to be on the safer side. Still, over \s-1NFS\s0, this is not an atomic operation anyway. .PP \&\fB\s-1BEWARE\s0\fR: 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 \f(CW\*(C`\-stale\*(C'\fR and set \&\f(CW\*(C`\-hold\*(C'\fR 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. ;\-) .SH "AUTHOR" .IX Header "AUTHOR" Raphael Manfredi \fI\fR .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIFile::Flock\fR\|(3).