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.28 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   6814336 use strict;
  78         992  
  78         2315  
28 78     78   420 use warnings;
  78         136  
  78         2276  
29              
30 78     78   414 use Carp qw(croak confess);
  78         146  
  78         5038  
31             our $errstr;
32 78     78   551 use base 'Exporter';
  78         160  
  78         15432  
33             our @EXPORT_OK = qw(uncache);
34              
35             our $VERSION = '1.28';
36              
37             #Get constants, but without the bloat of
38             #use Fcntl qw(LOCK_SH LOCK_EX LOCK_NB);
39             use constant {
40 78         190534 LOCK_SH => 1,
41             LOCK_EX => 2,
42             LOCK_NB => 4,
43 78     78   655 };
  78         132  
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 82508021 $errstr = undef;
73              
74 1167         3832 my $type = shift;
75 1167   50     9992 my $class = ref($type) || $type || __PACKAGE__;
76 1167         3296 my $self = {};
77              
78             ### allow for arguments by hash ref or serially
79 1167 100 66     8256 if( @_ && ref $_[0] ){
80 1134         3088 $self = shift;
81             }else{
82 33         285 $self->{file} = shift;
83 33         283 $self->{lock_type} = shift;
84 33         267 $self->{blocking_timeout} = shift;
85 33         151 $self->{stale_lock_timeout} = shift;
86             }
87 1167   50     4016 $self->{file} ||= "";
88 1167   50     3509 $self->{lock_type} ||= 0;
89 1167   100     5535 $self->{blocking_timeout} ||= 0;
90 1167   100     5873 $self->{stale_lock_timeout} ||= 0;
91 1167         4929 $self->{lock_pid} = $$;
92 1167         5173 $self->{unlocked} = 1;
93 1167         4309 foreach my $signal (@CATCH_SIGS) {
94 2334 100 66     10196 if (!$SIG{$signal} ||
95             $SIG{$signal} eq "DEFAULT") {
96 2246         33922 $SIG{$signal} = $graceful_sig;
97             }
98             }
99              
100             ### force lock_type to be numerical
101 1167 50 33     13904 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       3141 if( !$HOSTNAME ){
109 68         80510 require Sys::Hostname;
110 68         102208 $HOSTNAME = Sys::Hostname::hostname();
111             }
112              
113             ### quick usage check
114             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 1167 50       4129 unless length($self->{file});
118              
119             croak ($errstr = "Unrecognized lock_type operation setting [$self->{lock_type}]")
120 1167 50 33     10358 unless $self->{lock_type} && $self->{lock_type} =~ /^\d+$/;
121              
122             ### Input syntax checking passed, ready to bless
123 1167         2794 bless $self, $class;
124              
125             ### choose a random filename
126 1167         3429 $self->{rand_file} = rand_file( $self->{file} );
127              
128             ### choose the lock filename
129 1167         4585 $self->{lock_file} = $self->{file} . $LOCK_EXTENSION;
130              
131             my $quit_time = $self->{blocking_timeout} &&
132             !($self->{lock_type} & LOCK_NB) ?
133 1167 100 66     4272 time() + $self->{blocking_timeout} : 0;
134              
135             ### remove an old lockfile if it is older than the stale_timeout
136 1167 50 100     21413 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         2793 while (1) {
143             ### open the temporary file
144 1368 50       6428 $self->create_magic
145             or return undef;
146              
147 1368 100       5532 if ( $self->{lock_type} & LOCK_EX ) {
    50          
148 1339 100       4409 last if $self->do_lock;
149             } elsif ( $self->{lock_type} & LOCK_SH ) {
150 29 100       184 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 213         606 my $fh;
164 213 100 100     11902 if ( -e $self->{lock_file} &&
165             open ($fh,'+<', $self->{lock_file}) ){
166              
167 175         924 my @mine = ();
168 175         3043 my @them = ();
169 175         436 my @dead = ();
170              
171 175         926 my $has_lock_exclusive = !((stat _)[2] & $SHARE_BIT);
172 175         663 my $try_lock_exclusive = !($self->{lock_type} & LOCK_SH);
173              
174 175         3188 while(defined(my $line=<$fh>)){
175 175 50       4424 if ($line =~ /^\Q$HOSTNAME\E (-?\d+) /) {
176 175         1238 my $pid = $1;
177 175 100       3116 if ($pid == $$) { # This is me.
    100          
178 1         12 push @mine, $line;
179             }elsif(kill 0, $pid) { # Still running on this host.
180 172         2661 push @them, $line;
181             }else{ # Finished running on this host.
182 2         36 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 175 100       912 if (@dead) {
191             # Lock lock_file to avoid a race condition.
192 2         24 local $LOCK_EXTENSION = ".shared";
193             my $lock = new File::NFSLock {
194             file => $self->{lock_file},
195 2         56 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         20 seek ($fh, 0, 0);
203 2         14 my $content = '';
204 2         24 while(defined(my $line=<$fh>)){
205 2 50       71 if ($line =~ /^\Q$HOSTNAME\E (-?\d+) /) {
206 2         9 my $pid = $1;
207 2 50       40 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       16 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         19 close $fh;
220 2         99 unlink $self->{lock_file};
221             }
222              
223             ### No "dead" or stale locks found.
224             } else {
225 173         3460 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 175 100 100     1763 if ($try_lock_exclusive eq $has_lock_exclusive && @mine){
235 1         8 return $self;
236             }
237             }
238              
239             ### If non-blocking, then kick out now.
240             ### ($errstr might already be set to the reason.)
241 212 100       1099 if ($self->{lock_type} & LOCK_NB) {
242 11   50     142 $errstr ||= "NONBLOCKING lock failed!";
243 11         88 return undef;
244             }
245              
246             ### wait a moment
247 201         201044744 sleep(1);
248              
249             ### but don't wait past the time out
250 201 50 66     6150 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         5546 $self->uncache;
260              
261             ### Yes, the lock has been acquired.
262 1155         4825 delete $self->{unlocked};
263              
264 1155         4577 return $self;
265             }
266              
267             sub DESTROY {
268 1167     1167   36102743 shift()->unlock();
269             }
270              
271             sub unlock ($) {
272 1187     1187 1 100081430 my $self = shift;
273 1187 100       3823 if (!$self->{unlocked}) {
274 1155 50       19890 unlink( $self->{rand_file} ) if -e $self->{rand_file};
275 1155 100       4573 if( $self->{lock_type} & LOCK_SH ){
276 33         439 $self->do_unlock_shared;
277             }else{
278 1122         3386 $self->do_unlock;
279             }
280 1155         4725 $self->{unlocked} = 1;
281 1155         3235 foreach my $signal (@CATCH_SIGS) {
282 2310 100 66     16818 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         32751 delete $SIG{$signal};
290             }
291             }
292             }
293 1187         19540 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 4095 my $file = shift;
304 2322         18682 "$file.tmp.". time()%10000 .'.'. $$ .'.'. int(rand()*10000);
305             }
306              
307             sub create_magic ($;$) {
308 1396     1396 0 3077 $errstr = undef;
309 1396         2772 my $self = shift;
310 1396   66     6978 my $append_file = shift || $self->{rand_file};
311 1396   66     11806 $self->{lock_line} ||= "$HOSTNAME $self->{lock_pid} ".time()." ".int(rand()*10000)."\n";
312 1396 50       110891 open (my $fh,'>>', $append_file) or do { $errstr = "Couldn't open \"$append_file\" [$!]"; return undef; };
  0         0  
  0         0  
313 1396         11861 print $fh $self->{lock_line};
314 1396         51907 close $fh;
315 1396         10568 return 1;
316             }
317              
318             sub do_lock {
319 1339     1339 0 2618 $errstr = undef;
320 1339         2661 my $self = shift;
321 1339         2774 my $lock_file = $self->{lock_file};
322 1339         2508 my $rand_file = $self->{rand_file};
323 1339         2065 my $chmod = 0600;
324 1339 50       24408 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 1339   66     51414 my $success = link( $rand_file, $lock_file )
330             && -e $rand_file && (stat _)[3] == 2;
331 1339         41391 unlink $rand_file;
332              
333 1339         8988 return $success;
334             }
335              
336             sub do_lock_shared {
337 29     29 0 74 $errstr = undef;
338 29         57 my $self = shift;
339 29         71 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         48 my $chmod = 0600;
344 29         66 $chmod |= $SHARE_BIT;
345 29 50       618 chmod( $chmod, $rand_file)
346             || die "I need ability to chmod files to adequatetly perform locking";
347              
348             ### lock the locking process
349 29         357 local $LOCK_EXTENSION = ".shared";
350 29         572 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         390 my $success = link( $rand_file, $lock_file);
365 29         1155 unlink $rand_file;
366 29 100 66     904 if ( !$success &&
    100 100        
367             -e $lock_file &&
368             ((stat _)[2] & $SHARE_BIT) != $SHARE_BIT ){
369              
370 2         18 $errstr = 'Exclusive lock exists.';
371 2         24 return undef;
372              
373             } elsif ( !$success ) {
374             ### Shared lock exists, append my lock
375 20         98 $self->create_magic ($self->{lock_file});
376             }
377              
378             # Success
379 27         162 return 1;
380             }
381              
382             sub do_unlock ($) {
383 1122     1122 0 43081 return unlink shift->{lock_file};
384             }
385              
386             sub do_unlock_shared ($) {
387 33     33 0 245 $errstr = undef;
388 33         185 my $self = shift;
389 33         210 my $lock_file = $self->{lock_file};
390 33         217 my $lock_line = $self->{lock_line};
391              
392             ### lock the locking process
393 33         565 local $LOCK_EXTENSION = '.shared';
394 33         1094 my $lock = new File::NFSLock ($lock_file,LOCK_EX,62,60);
395              
396             ### get the handle on the lock file
397 33         175 my $fh;
398 33 50       1412 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         181 my $content = '';
408 33         939 while(defined(my $line=<$fh>)){
409 251 100       958 next if $line eq $lock_line;
410 218         809 $content .= $line;
411             }
412              
413             ### other shared locks exist
414 33 100       261 if( length($content) ){
415 28         326 seek $fh, 0, 0;
416 28         188 print $fh $content;
417 28         1556 truncate $fh, length($content);
418 28         906 close $fh;
419              
420             ### only I exist
421             }else{
422 5         62 close $fh;
423 5         527 unlink $lock_file;
424             }
425              
426             }
427              
428             sub uncache ($;$) {
429             # allow as method call
430 1155     1155 1 1976 my $file = pop;
431 1155 50       4097 ref $file && ($file = $file->{file});
432 1155         2653 my $rand_file = rand_file( $file );
433              
434             ### hard link to the actual file which will bring it up to date
435 1155   66     57428 return ( link( $file, $rand_file) && unlink($rand_file) );
436             }
437              
438             sub newpid {
439 12     12 1 8015002 my $self = shift;
440             # Detect if this is the parent or the child
441 12 100       494 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         45 my $patience = time + 10;
447 4         80 while (time < $patience) {
448 46 100       3361 if (rename("$self->{lock_file}.fork",$self->{rand_file})) {
449             # Child finished its newpid call.
450             # Wipe the signal file.
451 4         481 unlink $self->{rand_file};
452 4         119 last;
453             }
454             # Brief pause before checking again
455             # to avoid intensive IO across NFS.
456 42         4211149 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       221 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         140 $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         243 $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         332 delete $self->{lock_line};
482             # Append a new lock_line to the lock_file.
483 8         332 $self->create_magic($self->{lock_file});
484              
485 8 100       128 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         63 $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         705 open (my $fh, '>', "$self->{lock_file}.fork");
498 8         204 close($fh);
499             }
500             }
501              
502             sub fork {
503 6     6 1 1940 my $self = shift;
504             # Store fork response.
505 6         5853 my $pid = CORE::fork();
506 6 50 33     709 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         226 $self->newpid;
510             }
511             # Return original fork response
512 6         200 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