File Coverage

blib/lib/Path/Class/File/Lockable.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Path::Class::File::Lockable;
2              
3 2     2   49347 use warnings;
  2         6  
  2         62  
4 2     2   12 use strict;
  2         4  
  2         71  
5 2     2   12 use base qw( Path::Class::File );
  2         8  
  2         4946  
6 2     2   117801 use File::NFSLock;
  0            
  0            
7             use Fcntl qw(LOCK_EX LOCK_NB);
8             use Carp;
9              
10             our $VERSION = '0.03';
11              
12             =head1 NAME
13              
14             Path::Class::File::Lockable - lock your files with Path::Class::File
15              
16             =head1 SYNOPSIS
17              
18             my $file = Path::Class::File::Lockable->new('path/to/file');
19             $file->lock;
20             # do stuff with $file
21             $file->unlock;
22              
23             =head1 DESCRIPTION
24              
25             Path::Class::File::Lockable uses simple files to indicate whether
26             a file is locked or not. It does not use flock(), since that is
27             unstable over NFS. Effort has been made to avoid race conditions.
28              
29             Path::Class::File::Lockable is intended for long-standing locks, as in a
30             Subversion workspace. See SVN::Class for example.
31              
32             =head1 METHODS
33              
34             This is a subclass of Path::Class::File. Only new or overridden methods
35             are documented here.
36              
37             =cut
38              
39             =head2 lock_ext
40              
41             Returns the file extension used to indicate a lock file. Default is
42             C<.lock>.
43              
44             =cut
45              
46             sub lock_ext {'.lock'}
47              
48             =head2 lock_file
49              
50             Returns a Path::Class::File object representing the lock file
51             itself. No check is made as to whether the lock file exists.
52              
53             =cut
54              
55             sub lock_file {
56             my $self = shift;
57             return Path::Class::File->new( join( '', $self, $self->lock_ext ) );
58             }
59              
60             =head2 lock_info
61              
62             Returns a colon-limited string with the contents of the lock file.
63             Will croak if the lock file does not exist.
64              
65             B that the owner and timestamp in the file contents
66             are not from a stat() of the file.
67             They are written
68             at the time the lock file is created. So chown'ing or touch'ing
69             a lock file do not alter its status.
70              
71             See lock_owner() and lock_time() for easier ways to get at specific
72             information.
73              
74             =cut
75              
76             sub lock_info {
77             my $self = shift;
78             my $lfile = $self->lock_file;
79             if ( !-s $lfile ) {
80             croak "no such lock file: $lfile";
81             }
82             return $lfile->slurp;
83             }
84              
85             =head2 lock_owner
86              
87             Returns the name of the person who locked the file.
88              
89             =cut
90              
91             sub lock_owner {
92             my $self = shift;
93             return ( split( m/:/, $self->lock_info ) )[0];
94             }
95              
96             =head2 lock_time
97              
98             Returns the time the file was locked (in Epoch seconds).
99              
100             =cut
101              
102             sub lock_time {
103             my $self = shift;
104             return ( split( m/:/, $self->lock_info ) )[1];
105             }
106              
107             =head2 lock_pid
108              
109             Returns the PID of the process that locked the file.
110              
111             =cut
112              
113             sub lock_pid {
114             my $self = shift;
115             return ( split( m/:/, $self->lock_info ) )[2];
116             }
117              
118             =head2 locked
119              
120             Returns true if the file has an existing lock file.
121              
122             =cut
123              
124             sub locked {
125             my $self = shift;
126             return -s $self->lock_file;
127             }
128              
129             =head2 lock( [I] )
130              
131             Acquire a lock on the file.
132              
133             This method should be NFS-safe via File::NFSLock.
134              
135             =cut
136              
137             sub lock {
138             my $self = shift;
139             my $owner;
140             if ( $^O eq 'MSWin32' ) {
141             require Win32;
142             $owner = Win32::LoginName();
143             }
144             else {
145             $owner = shift || getlogin() || ( getpwuid($<) )[0] || 'anonymous';
146             }
147              
148             # we have to lock our lock file first, to avoid
149             # NFS and race condition badness.
150             # so obtain a lock on our lock file, write our lock
151             # then release the lock on our lock file.
152             # we can't use File::NFSLock all by itself since it is
153             # not persistent across processes.
154             my $lock = File::NFSLock->new(
155             { file => $self->lock_file,
156             lock_type => LOCK_EX | LOCK_NB,
157             blocking_timeout => 5,
158             stale_lock_timeout => 5
159             }
160             );
161              
162             if ( !$lock ) {
163             croak "can't get safe lock on lock file: $File::NFSLock::errstr";
164             }
165              
166             my $fh = $self->lock_file->openw() or croak "can't write lock file: $!";
167             print {$fh} join( ':', $owner, time(), $$ );
168             $fh->close;
169              
170             $lock->unlock;
171             }
172              
173             =head2 unlock
174              
175             Removes lock file. Uses system() call to enable unlinking across
176             NFS. Will croak on any error.
177              
178             =cut
179              
180             sub unlock {
181             my $self = shift;
182             $self->lock_file->remove or croak "can't unlink lock file: $!";
183             return 1;
184             }
185              
186             =head1 AUTHOR
187              
188             Peter Karman, C<< >>
189              
190             =head1 BUGS
191              
192             Please report any bugs or feature requests to
193             C, or through the web interface at
194             L.
195             I will be notified, and then you'll automatically be notified of progress on
196             your bug as I make changes.
197              
198             =head1 SUPPORT
199              
200             You can find documentation for this module with the perldoc command.
201              
202             perldoc Path::Class::File::Lockable
203              
204             You can also look for information at:
205              
206             =over 4
207              
208             =item * AnnoCPAN: Annotated CPAN documentation
209              
210             L
211              
212             =item * CPAN Ratings
213              
214             L
215              
216             =item * RT: CPAN's request tracker
217              
218             L
219              
220             =item * Search CPAN
221              
222             L
223              
224             =back
225              
226             =head1 ACKNOWLEDGEMENTS
227              
228             There are lots of lock file modules on CPAN. Some of them are probably better
229             suited to your needs than this one.
230              
231             The Minnesota Supercomputing Institute C<< http://www.msi.umn.edu/ >>
232             sponsored the development of this software.
233              
234             =head1 SEE ALSO
235              
236             File::NFSLock, Path::Class::File
237              
238             =head1 COPYRIGHT & LICENSE
239              
240             Copyright 2007 by the Regents of the University of Minnesota.
241             All rights reserved.
242              
243             This program is free software; you can redistribute it and/or modify it
244             under the same terms as Perl itself.
245              
246             =cut
247              
248             1;