File Coverage

blib/lib/File/NFSLock.pm
Criterion Covered Total %
statement 180 197 91.3
branch 66 86 76.7
condition 46 69 66.6
subroutine 17 17 100.0
pod 4 11 36.3
total 313 380 82.3


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             # File::NFSLock - bdpO - NFS compatible (safe) locking utility
4             #
5             # $Id: NFSLock.pm,v 1.27 2014/11/10 14:00:00 hookbot Exp $
6             #
7             # Copyright (C) 2002, Paul T Seamons
8             # paul@seamons.com
9             # http://seamons.com/
10             #
11             # Rob B Brown
12             # bbb@cpan.org
13             #
14             # This package may be distributed under the terms of either the
15             # GNU General Public License
16             # or the
17             # Perl Artistic License
18             #
19             # All rights reserved.
20             #
21             # Please read the perldoc File::NFSLock
22             #
23             ################################################################
24              
25             package File::NFSLock;
26              
27 78     78   2491597 use strict;
  78         148  
  78         2663  
28 78     78   281 use warnings;
  78         90  
  78         2004  
29              
30 78     78   286 use Carp qw(croak confess);
  78         106  
  78         5183  
31             our $errstr;
32 78     78   297 use base 'Exporter';
  78         87  
  78         9513  
33             our @EXPORT_OK = qw(uncache);
34              
35             our $VERSION = '1.27';
36              
37             #Get constants, but without the bloat of
38             #use Fcntl qw(LOCK_SH LOCK_EX LOCK_NB);
39             use constant {
40 78         156562 LOCK_SH => 1,
41             LOCK_EX => 2,
42             LOCK_NB => 4,
43 78     78   441 };
  78         108  
44              
45             ### Convert lock_type to a number
46             our $TYPES = {
47             BLOCKING => LOCK_EX,
48             BL => LOCK_EX,
49             EXCLUSIVE => LOCK_EX,
50             EX => LOCK_EX,
51             NONBLOCKING => LOCK_EX | LOCK_NB,
52             NB => LOCK_EX | LOCK_NB,
53             SHARED => LOCK_SH,
54             SH => LOCK_SH,
55             };
56             our $LOCK_EXTENSION = '.NFSLock'; # customizable extension
57             our $HOSTNAME = undef;
58             our $SHARE_BIT = 1;
59              
60             ###----------------------------------------------------------------###
61              
62             my $graceful_sig = sub {
63             print STDERR "Received SIG$_[0]\n" if @_;
64             # Perl's exit should safely DESTROY any objects
65             # still "alive" before calling the real _exit().
66             exit 1;
67             };
68              
69             our @CATCH_SIGS = qw(TERM INT);
70              
71             sub new {
72 1167     1167 0 82606692 $errstr = undef;
73              
74 1167         2918 my $type = shift;
75 1167   50     8233 my $class = ref($type) || $type || __PACKAGE__;
76 1167         1959 my $self = {};
77              
78             ### allow for arguments by hash ref or serially
79 1167 100 66     8192 if( @_ && ref $_[0] ){
80 1134         2088 $self = shift;
81             }else{
82 33         182 $self->{file} = shift;
83 33         146 $self->{lock_type} = shift;
84 33         105 $self->{blocking_timeout} = shift;
85 33         98 $self->{stale_lock_timeout} = shift;
86             }
87 1167   50     3014 $self->{file} ||= "";
88 1167   50     2527 $self->{lock_type} ||= 0;
89 1167   100     4225 $self->{blocking_timeout} ||= 0;
90 1167   100     3598 $self->{stale_lock_timeout} ||= 0;
91 1167         3145 $self->{lock_pid} = $$;
92 1167         1904 $self->{unlocked} = 1;
93 1167         5162 foreach my $signal (@CATCH_SIGS) {
94 2334 100 66     7444 if (!$SIG{$signal} ||
95             $SIG{$signal} eq "DEFAULT") {
96 2246         19640 $SIG{$signal} = $graceful_sig;
97             }
98             }
99              
100             ### force lock_type to be numerical
101 1167 50 33     12904 if( $self->{lock_type} &&
      33        
102             $self->{lock_type} !~ /^\d+/ &&
103             exists $TYPES->{$self->{lock_type}} ){
104 0         0 $self->{lock_type} = $TYPES->{$self->{lock_type}};
105             }
106              
107             ### need the hostname
108 1167 100       2404 if( !$HOSTNAME ){
109 68         358973 require Sys::Hostname;
110 68         144332 $HOSTNAME = Sys::Hostname::hostname();
111             }
112              
113             ### quick usage check
114 1167 50       3901 croak ($errstr = "Usage: my \$f = $class->new('/pathtofile/file',\n"
115             ."'BLOCKING|EXCLUSIVE|NONBLOCKING|SHARED', [blocking_timeout, stale_lock_timeout]);\n"
116             ."(You passed \"$self->{file}\" and \"$self->{lock_type}\")")
117             unless length($self->{file});
118              
119 1167 50 33     8752 croak ($errstr = "Unrecognized lock_type operation setting [$self->{lock_type}]")
120             unless $self->{lock_type} && $self->{lock_type} =~ /^\d+$/;
121              
122             ### Input syntax checking passed, ready to bless
123 1167         2599 bless $self, $class;
124              
125             ### choose a random filename
126 1167         3879 $self->{rand_file} = rand_file( $self->{file} );
127              
128             ### choose the lock filename
129 1167         3520 $self->{lock_file} = $self->{file} . $LOCK_EXTENSION;
130              
131 1167 100 66     3771 my $quit_time = $self->{blocking_timeout} &&
132             !($self->{lock_type} & LOCK_NB) ?
133             time() + $self->{blocking_timeout} : 0;
134              
135             ### remove an old lockfile if it is older than the stale_timeout
136 1167 50 100     38882 if( -e $self->{lock_file} &&
      66        
137             $self->{stale_lock_timeout} > 0 &&
138             time() - (stat _)[9] > $self->{stale_lock_timeout} ){
139 0         0 unlink $self->{lock_file};
140             }
141              
142 1167         1240 while (1) {
143             ### open the temporary file
144 1342 50       4699 $self->create_magic
145             or return undef;
146              
147 1342 100       4350 if ( $self->{lock_type} & LOCK_EX ) {
    50          
148 1313 100       3671 last if $self->do_lock;
149             } elsif ( $self->{lock_type} & LOCK_SH ) {
150 29 100       248 last if $self->do_lock_shared;
151             } else {
152 0         0 $errstr = "Unknown lock_type [$self->{lock_type}]";
153 0         0 return undef;
154             }
155              
156             ### Lock failed!
157              
158             ### I know this may be a race condition, but it's okay. It is just a
159             ### stab in the dark to possibly find long dead processes.
160              
161             ### If lock exists and is readable, see who is mooching on the lock
162              
163 187         376 my $fh;
164 187 100 100     43146 if ( -e $self->{lock_file} &&
165             open ($fh,'+<', $self->{lock_file}) ){
166              
167 153         408 my @mine = ();
168 153         285 my @them = ();
169 153         231 my @dead = ();
170              
171 153         768 my $has_lock_exclusive = !((stat _)[2] & $SHARE_BIT);
172 153         697 my $try_lock_exclusive = !($self->{lock_type} & LOCK_SH);
173              
174 153         7814 while(defined(my $line=<$fh>)){
175 153 50       3700 if ($line =~ /^\Q$HOSTNAME\E (-?\d+) /) {
176 153         775 my $pid = $1;
177 153 100       1843 if ($pid == $$) { # This is me.
    100          
178 1         8 push @mine, $line;
179             }elsif(kill 0, $pid) { # Still running on this host.
180 150         2468 push @them, $line;
181             }else{ # Finished running on this host.
182 2         21 push @dead, $line;
183             }
184             } else { # Running on another host, so
185 0         0 push @them, $line; # assume it is still running.
186             }
187             }
188              
189             ### If there was at least one stale lock discovered...
190 153 100       826 if (@dead) {
191             # Lock lock_file to avoid a race condition.
192 2         8 local $LOCK_EXTENSION = ".shared";
193 2         35 my $lock = new File::NFSLock {
194             file => $self->{lock_file},
195             lock_type => LOCK_EX,
196             blocking_timeout => 62,
197             stale_lock_timeout => 60,
198             };
199              
200             ### Rescan in case lock contents were modified between time stale lock
201             ### was discovered and lockfile lock was acquired.
202 2         13 seek ($fh, 0, 0);
203 2         2 my $content = '';
204 2         16 while(defined(my $line=<$fh>)){
205 2 50       42 if ($line =~ /^\Q$HOSTNAME\E (-?\d+) /) {
206 2         5 my $pid = $1;
207 2 50       23 next if (!kill 0, $pid); # Skip dead locks from this host
208             }
209 0         0 $content .= $line; # Save valid locks
210             }
211              
212             ### Save any valid locks or wipe file.
213 2 50       9 if( length($content) ){
214 0         0 seek $fh, 0, 0;
215 0         0 print $fh $content;
216 0         0 truncate $fh, length($content);
217 0         0 close $fh;
218             }else{
219 2         12 close $fh;
220 2         93 unlink $self->{lock_file};
221             }
222              
223             ### No "dead" or stale locks found.
224             } else {
225 151         2516 close $fh;
226             }
227              
228             ### If attempting to acquire the same type of lock
229             ### that it is already locked with, and I've already
230             ### locked it myself, then it is safe to lock again.
231             ### Just kick out successfully without really locking.
232             ### Assumes locks will be released in the reverse
233             ### order from how they were established.
234 153 100 100     1224 if ($try_lock_exclusive eq $has_lock_exclusive && @mine){
235 1         5 return $self;
236             }
237             }
238              
239             ### If non-blocking, then kick out now.
240             ### ($errstr might already be set to the reason.)
241 186 100       719 if ($self->{lock_type} & LOCK_NB) {
242 11   50     99 $errstr ||= "NONBLOCKING lock failed!";
243 11         74 return undef;
244             }
245              
246             ### wait a moment
247 175         175103812 sleep(1);
248              
249             ### but don't wait past the time out
250 175 50 66     3446 if( $quit_time && (time > $quit_time) ){
251 0         0 $errstr = "Timed out waiting for blocking lock";
252 0         0 return undef;
253             }
254              
255             # BLOCKING Lock, So Keep Trying
256             }
257              
258             ### clear up the NFS cache
259 1155         3621 $self->uncache;
260              
261             ### Yes, the lock has been acquired.
262 1155         2707 delete $self->{unlocked};
263              
264 1155         3428 return $self;
265             }
266              
267             sub DESTROY {
268 1167     1167   36075194 shift()->unlock();
269             }
270              
271             sub unlock ($) {
272 1187     1187 1 100041554 my $self = shift;
273 1187 100       3367 if (!$self->{unlocked}) {
274 1155 50       31125 unlink( $self->{rand_file} ) if -e $self->{rand_file};
275 1155 100       2760 if( $self->{lock_type} & LOCK_SH ){
276 33         301 $self->do_unlock_shared;
277             }else{
278 1122         2348 $self->do_unlock;
279             }
280 1155         2812 $self->{unlocked} = 1;
281 1155         2248 foreach my $signal (@CATCH_SIGS) {
282 2310 100 66     15258 if ($SIG{$signal} &&
283             ($SIG{$signal} eq $graceful_sig)) {
284             # Revert handler back to how it used to be.
285             # Unfortunately, this will restore the
286             # handler back even if there are other
287             # locks still in tact, but for most cases,
288             # it will still be an improvement.
289 2240         13063 delete $SIG{$signal};
290             }
291             }
292             }
293 1187         9924 return 1;
294             }
295              
296             ###----------------------------------------------------------------###
297              
298             # concepts for these routines were taken from Mail::Box which
299             # took the concepts from Mail::Folder
300              
301              
302             sub rand_file ($) {
303 2322     2322 0 2483 my $file = shift;
304 2322         14485 "$file.tmp.". time()%10000 .'.'. $$ .'.'. int(rand()*10000);
305             }
306              
307             sub create_magic ($;$) {
308 1370     1370 0 2005 $errstr = undef;
309 1370         1618 my $self = shift;
310 1370   66     6038 my $append_file = shift || $self->{rand_file};
311 1370   66     11644 $self->{lock_line} ||= "$HOSTNAME $self->{lock_pid} ".time()." ".int(rand()*10000)."\n";
312 1370 50       207855 open (my $fh,'>>', $append_file) or do { $errstr = "Couldn't open \"$append_file\" [$!]"; return undef; };
  0         0  
  0         0  
313 1370         7624 print $fh $self->{lock_line};
314 1370         108152 close $fh;
315 1370         9307 return 1;
316             }
317              
318             sub do_lock {
319 1313     1313 0 1568 $errstr = undef;
320 1313         1936 my $self = shift;
321 1313         2011 my $lock_file = $self->{lock_file};
322 1313         1627 my $rand_file = $self->{rand_file};
323 1313         1377 my $chmod = 0600;
324 1313 50       60484 chmod( $chmod, $rand_file)
325             || die "I need ability to chmod files to adequatetly perform locking";
326              
327             ### try a hard link, if it worked
328             ### two files are pointing to $rand_file
329 1313   66     240743 my $success = link( $rand_file, $lock_file )
330             && -e $rand_file && (stat _)[3] == 2;
331 1313         74028 unlink $rand_file;
332              
333 1313         6623 return $success;
334             }
335              
336             sub do_lock_shared {
337 29     29 0 44 $errstr = undef;
338 29         43 my $self = shift;
339 29         62 my $lock_file = $self->{lock_file};
340 29         51 my $rand_file = $self->{rand_file};
341              
342             ### chmod local file to make sure we know before
343 29         37 my $chmod = 0600;
344 29         61 $chmod |= $SHARE_BIT;
345 29 50       1064 chmod( $chmod, $rand_file)
346             || die "I need ability to chmod files to adequatetly perform locking";
347              
348             ### lock the locking process
349 29         160 local $LOCK_EXTENSION = ".shared";
350 29         548 my $lock = new File::NFSLock {
351             file => $lock_file,
352             lock_type => LOCK_EX,
353             blocking_timeout => 62,
354             stale_lock_timeout => 60,
355             };
356             # The ".shared" lock will be released as this status
357             # is returned, whether or not the status is successful.
358              
359             ### If I didn't have exclusive and the shared bit is not
360             ### set, I have failed
361              
362             ### Try to create $lock_file from the special
363             ### file with the magic $SHARE_BIT set.
364 29         798 my $success = link( $rand_file, $lock_file);
365 29         1725 unlink $rand_file;
366 29 100 66     846 if ( !$success &&
    100 100        
367             -e $lock_file &&
368             ((stat _)[2] & $SHARE_BIT) != $SHARE_BIT ){
369              
370 2         6 $errstr = 'Exclusive lock exists.';
371 2         19 return undef;
372              
373             } elsif ( !$success ) {
374             ### Shared lock exists, append my lock
375 20         106 $self->create_magic ($self->{lock_file});
376             }
377              
378             # Success
379 27         327 return 1;
380             }
381              
382             sub do_unlock ($) {
383 1122     1122 0 54573 return unlink shift->{lock_file};
384             }
385              
386             sub do_unlock_shared ($) {
387 33     33 0 103 $errstr = undef;
388 33         85 my $self = shift;
389 33         116 my $lock_file = $self->{lock_file};
390 33         98 my $lock_line = $self->{lock_line};
391              
392             ### lock the locking process
393 33         339 local $LOCK_EXTENSION = '.shared';
394 33         534 my $lock = new File::NFSLock ($lock_file,LOCK_EX,62,60);
395              
396             ### get the handle on the lock file
397 33         94 my $fh;
398 33 50       968 if( ! open ($fh,'+<', $lock_file) ){
399 0 0       0 if( ! -e $lock_file ){
400 0         0 return 1;
401             }else{
402 0         0 die "Could not open for writing shared lock file $lock_file ($!)";
403             }
404             }
405              
406             ### read existing file
407 33         11707 my $content = '';
408 33         615 while(defined(my $line=<$fh>)){
409 251 100       581 next if $line eq $lock_line;
410 218         570 $content .= $line;
411             }
412              
413             ### other shared locks exist
414 33 100       205 if( length($content) ){
415 28         171 seek $fh, 0, 0;
416 28         79 print $fh $content;
417 28         1315 truncate $fh, length($content);
418 28         555 close $fh;
419              
420             ### only I exist
421             }else{
422 5         31 close $fh;
423 5         451 unlink $lock_file;
424             }
425              
426             }
427              
428             sub uncache ($;$) {
429             # allow as method call
430 1155     1155 1 1513 my $file = pop;
431 1155 50       3394 ref $file && ($file = $file->{file});
432 1155         2050 my $rand_file = rand_file( $file );
433              
434             ### hard link to the actual file which will bring it up to date
435 1155   66     68165 return ( link( $file, $rand_file) && unlink($rand_file) );
436             }
437              
438             sub newpid {
439 12     12 1 8010703 my $self = shift;
440             # Detect if this is the parent or the child
441 12 100       338 if ($self->{lock_pid} == $$) {
442             # This is the parent
443              
444             # Must wait for child to call newpid before processing.
445             # A little patience for the child to call newpid
446 4         32 my $patience = time + 10;
447 4         44 while (time < $patience) {
448 46 100       1737 if (rename("$self->{lock_file}.fork",$self->{rand_file})) {
449             # Child finished its newpid call.
450             # Wipe the signal file.
451 4         305 unlink $self->{rand_file};
452 4         41 last;
453             }
454             # Brief pause before checking again
455             # to avoid intensive IO across NFS.
456 42         4208786 select(undef,undef,undef,0.1);
457             }
458              
459             # Child finished running newpid() and acquired shared lock
460             # So now we're safe to continue without risk of
461             # blowing away the lock prematurely.
462 4 100       112 unless ( $self->{lock_type} & LOCK_SH ) {
463             # If it's not already a SHared lock, then
464             # just switch it from EXclusive to SHared
465             # from this process's point of view.
466             # Then the child will still hold the lock
467             # if the parent releases it first.
468             # (Don't chmod the lock file.)
469 2         53 $self->{lock_type} |= LOCK_SH;
470             }
471             } else {
472             # This is the new child
473              
474             # Fix lock_pid to the new pid.
475 8         95 $self->{lock_pid} = $$;
476              
477             # We can leave the old lock_line in the lock_file
478             # But we need to add the new lock_line for this pid.
479              
480             # Clear lock_line to create a fresh one.
481 8         249 delete $self->{lock_line};
482             # Append a new lock_line to the lock_file.
483 8         243 $self->create_magic($self->{lock_file});
484              
485 8 100       81 unless ( $self->{lock_type} & LOCK_SH ) {
486             # If it's not already a SHared lock, then
487             # just switch it from EXclusive to SHared
488             # from this process's point of view.
489             # Then the parent will still hold the lock
490             # if this child releases it first.
491             # (Don't chmod the lock file.)
492 4         68 $self->{lock_type} |= LOCK_SH;
493             }
494              
495             # Create signal file to notify parent that
496             # the lock_line entry has been delegated.
497 8         648 open (my $fh, '>', "$self->{lock_file}.fork");
498 8         189 close($fh);
499             }
500             }
501              
502             sub fork {
503 6     6 1 1543 my $self = shift;
504             # Store fork response.
505 6         4162 my $pid = CORE::fork();
506 6 50 33     409 if (defined $pid and !$self->{unlocked}) {
507             # Fork worked and we really have a lock to deal with
508             # So upgrade to shared lock across both parent and child
509 6         117 $self->newpid;
510             }
511             # Return original fork response
512 6         140 return $pid;
513             }
514              
515             1;
516              
517              
518             =pod
519              
520             =head1 NAME
521              
522             File::NFSLock - perl module to do NFS (or not) locking
523              
524             =head1 SYNOPSIS
525              
526             use File::NFSLock qw(uncache);
527             use Fcntl qw(LOCK_EX LOCK_NB);
528              
529             my $file = "somefile";
530              
531             ### set up a lock - lasts until object looses scope
532             if (my $lock = new File::NFSLock {
533             file => $file,
534             lock_type => LOCK_EX|LOCK_NB,
535             blocking_timeout => 10, # 10 sec
536             stale_lock_timeout => 30 * 60, # 30 min
537             }) {
538              
539             ### OR
540             ### my $lock = File::NFSLock->new($file,LOCK_EX|LOCK_NB,10,30*60);
541              
542             ### do write protected stuff on $file
543             ### at this point $file is uncached from NFS (most recent)
544             open(FILE, "+<$file") || die $!;
545              
546             ### or open it any way you like
547             ### my $fh = IO::File->open( $file, 'w' ) || die $!
548              
549             ### update (uncache across NFS) other files
550             uncache("someotherfile1");
551             uncache("someotherfile2");
552             # open(FILE2,"someotherfile1");
553              
554             ### unlock it
555             $lock->unlock();
556             ### OR
557             ### undef $lock;
558             ### OR let $lock go out of scope
559             }else{
560             die "I couldn't lock the file [$File::NFSLock::errstr]";
561             }
562              
563              
564             =head1 DESCRIPTION
565              
566             Program based of concept of hard linking of files being atomic across
567             NFS. This concept was mentioned in Mail::Box::Locker (which was
568             originally presented in Mail::Folder::Maildir). Some routine flow is
569             taken from there -- particularly the idea of creating a random local
570             file, hard linking a common file to the local file, and then checking
571             the nlink status. Some ideologies were not complete (uncache
572             mechanism, shared locking) and some coding was even incorrect (wrong
573             stat index). File::NFSLock was written to be light, generic,
574             and fast.
575              
576              
577             =head1 USAGE
578              
579             Locking occurs by creating a File::NFSLock object. If the object
580             is created successfully, a lock is currently in place and remains in
581             place until the lock object goes out of scope (or calls the unlock
582             method).
583              
584             A lock object is created by calling the new method and passing two
585             to four parameters in the following manner:
586              
587             my $lock = File::NFSLock->new($file,
588             $lock_type,
589             $blocking_timeout,
590             $stale_lock_timeout,
591             );
592              
593             Additionally, parameters may be passed as a hashref:
594              
595             my $lock = File::NFSLock->new({
596             file => $file,
597             lock_type => $lock_type,
598             blocking_timeout => $blocking_timeout,
599             stale_lock_timeout => $stale_lock_timeout,
600             });
601              
602             =head1 PARAMETERS
603              
604             =over 4
605              
606             =item Parameter 1: file
607              
608             Filename of the file upon which it is anticipated that a write will
609             happen to. Locking will provide the most recent version (uncached)
610             of this file upon a successful file lock. It is not necessary
611             for this file to exist.
612              
613             =item Parameter 2: lock_type
614              
615             Lock type must be one of the following:
616              
617             BLOCKING
618             BL
619             EXCLUSIVE (BLOCKING)
620             EX
621             NONBLOCKING
622             NB
623             SHARED
624             SH
625              
626             Or else one or more of the following joined with '|':
627              
628             Fcntl::LOCK_EX() (BLOCKING)
629             Fcntl::LOCK_NB() (NONBLOCKING)
630             Fcntl::LOCK_SH() (SHARED)
631              
632             Lock type determines whether the lock will be blocking, non blocking,
633             or shared. Blocking locks will wait until other locks are removed
634             before the process continues. Non blocking locks will return undef if
635             another process currently has the lock. Shared will allow other
636             process to do a shared lock at the same time as long as there is not
637             already an exclusive lock obtained.
638              
639             =item Parameter 3: blocking_timeout (optional)
640              
641             Timeout is used in conjunction with a blocking timeout. If specified,
642             File::NFSLock will block up to the number of seconds specified in
643             timeout before returning undef (could not get a lock).
644              
645              
646             =item Parameter 4: stale_lock_timeout (optional)
647              
648             Timeout is used to see if an existing lock file is older than the stale
649             lock timeout. If do_lock fails to get a lock, the modified time is checked
650             and do_lock is attempted again. If the stale_lock_timeout is set to low, a
651             recursion load could exist so do_lock will only recurse 10 times (this is only
652             a problem if the stale_lock_timeout is set too low -- on the order of one or two
653             seconds).
654              
655             =back
656              
657             =head1 METHODS
658              
659             After the $lock object is instantiated with new,
660             as outlined above, some methods may be used for
661             additional functionality.
662              
663             =head2 unlock
664              
665             $lock->unlock;
666              
667             This method may be used to explicitly release a lock
668             that is acquired. In most cases, it is not necessary
669             to call unlock directly since it will implicitly be
670             called when the object leaves whatever scope it is in.
671              
672             =head2 uncache
673              
674             $lock->uncache;
675             $lock->uncache("otherfile1");
676             uncache("otherfile2");
677              
678             This method is used to freshen up the contents of a
679             file across NFS, ignoring what is contained in the
680             NFS client cache. It is always called from within
681             the new constructor on the file that the lock is
682             being attempted. uncache may be used as either an
683             object method or as a stand alone subroutine.
684              
685             =head2 fork
686              
687             my $pid = $lock->fork;
688             if (!defined $pid) {
689             # Fork Failed
690             } elsif ($pid) {
691             # Parent ...
692             } else {
693             # Child ...
694             }
695              
696             fork() is a convenience method that acts just like the normal
697             CORE::fork() except it safely ensures the lock is retained
698             within both parent and child processes. WITHOUT this, then when
699             either the parent or child process releases the lock, then the
700             entire lock will be lost, allowing external processes to
701             re-acquire a lock on the same file, even if the other process
702             still has the lock object in scope. This can cause corruption
703             since both processes might think they have exclusive access to
704             the file.
705              
706             =head2 newpid
707              
708             my $pid = fork;
709             if (!defined $pid) {
710             # Fork Failed
711             } elsif ($pid) {
712             $lock->newpid;
713             # Parent ...
714             } else {
715             $lock->newpid;
716             # Child ...
717             }
718              
719             The newpid() synopsis shown above is equivalent to the
720             one used for the fork() method, but it's not intended
721             to be called directly. It is called internally by the
722             fork() method. To be safe, it is recommended to use
723             $lock->fork() from now on.
724              
725             =head1 FAILURE
726              
727             On failure, a global variable, $File::NFSLock::errstr, should be set and should
728             contain the cause for the failure to get a lock. Useful primarily for debugging.
729              
730             =head1 LOCK_EXTENSION
731              
732             By default File::NFSLock will use a lock file extension of ".NFSLock". This is
733             in a global variable $File::NFSLock::LOCK_EXTENSION that may be changed to
734             suit other purposes (such as compatibility in mail systems).
735              
736             =head1 REPO
737              
738             The source is now on github:
739              
740             git clone https://github.com/hookbot/File-NFSLock
741              
742             =head1 BUGS
743              
744             If you spot anything, please submit a pull request on
745             github and/or submit a ticket with RT:
746             https://rt.cpan.org/Dist/Display.html?Queue=File-NFSLock
747              
748             =head2 FIFO
749              
750             Locks are not necessarily obtained on a first come first serve basis.
751             Not only does this not seem fair to new processes trying to obtain a lock,
752             but it may cause a process starvation condition on heavily locked files.
753              
754             =head2 DIRECTORIES
755              
756             Locks cannot be obtained on directory nodes, nor can a directory node be
757             uncached with the uncache routine because hard links do not work with
758             directory nodes. Some other algorithm might be used to uncache a
759             directory, but I am unaware of the best way to do it. The biggest use I
760             can see would be to avoid NFS cache of directory modified and last accessed
761             timestamps.
762              
763             =head1 INSTALL
764              
765             Download and extract tarball before running
766             these commands in its base directory:
767              
768             perl Makefile.PL
769             make
770             make test
771             make install
772              
773             For RPM installation, download tarball before
774             running these commands in your _topdir:
775              
776             rpm -ta SOURCES/File-NFSLock-*.tar.gz
777             rpm -ih RPMS/noarch/perl-File-NFSLock-*.rpm
778              
779             =head1 AUTHORS
780              
781             Paul T Seamons (paul@seamons.com) - Performed majority of the
782             programming with copious amounts of input from Rob Brown.
783              
784             Rob B Brown (bbb@cpan.org) - In addition to helping in the
785             programming, Rob Brown provided most of the core testing to make sure
786             implementation worked properly. He is now the current maintainer.
787              
788             Also Mark Overmeer (mark@overmeer.net) - Author of Mail::Box::Locker,
789             from which some key concepts for File::NFSLock were taken.
790              
791             Also Kevin Johnson (kjj@pobox.com) - Author of Mail::Folder::Maildir,
792             from which Mark Overmeer based Mail::Box::Locker.
793              
794             =head1 COPYRIGHT
795              
796             Copyright (C) 2001
797             Paul T Seamons
798             paul@seamons.com
799             http://seamons.com/
800              
801             Copyright (C) 2002-2014,
802             Rob B Brown
803             bbb@cpan.org
804              
805             This package may be distributed under the terms of either the
806             GNU General Public License
807             or the
808             Perl Artistic License
809              
810             All rights reserved.
811              
812             =cut